(一)unity shader在实际项目中出现的问题————unity的后处理插件景深效果在某些低档机(如三星)无效的解决方案

本专栏主要解决一些移动平台上unity shader效果异常的问题。很多情况下我们发现unity中的shader在PC平台效果正常,但是在移动平台上效果不对,或者部分机型效果不对的问题,尤其是低档老年机,作为一款上线游戏难免要支持高中低档大部分机型,但是部分机型(如华为)在渲染方面难免会出现很多奇怪的问题。

 

最近在做一个小游戏,用到了景深后处理效果,然后发现在一个三星的低端机景深没有效果,在其他机器上效果正常。

这是其他机型正常的效果:

(一)unity shader在实际项目中出现的问题————unity的后处理插件景深效果在某些低档机(如三星)无效的解决方案_第1张图片

这是三星低端机的效果,景深后处理无效:

(一)unity shader在实际项目中出现的问题————unity的后处理插件景深效果在某些低档机(如三星)无效的解决方案_第2张图片

于是打开Frame Dugger调试效果正常的机型,发现渲染正常:

(一)unity shader在实际项目中出现的问题————unity的后处理插件景深效果在某些低档机(如三星)无效的解决方案_第3张图片

 这是三星低档机的调试信息:

(一)unity shader在实际项目中出现的问题————unity的后处理插件景深效果在某些低档机(如三星)无效的解决方案_第4张图片

然后我把景深效果换成bloom效果,在三星低档机跑了下,发现后处理效果是对的。只有景深不对。于是我们看下代码:

下面是bloom的部分代码:

(一)unity shader在实际项目中出现的问题————unity的后处理插件景深效果在某些低档机(如三星)无效的解决方案_第5张图片

下面是景深的部分代码:

Shader "Hidden/PostProcessing/DepthOfField"
{
    // SubShader with SM 5.0 support
    // DX11+, OpenGL 4.3+, OpenGL ES 3.1+AEP, Vulkan, consoles
    // Gather intrinsics are used to reduce texture sample count.
    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass // 0
        {
            Name "CoC Calculation"

            HLSLPROGRAM
                #pragma target 3.5
                #pragma vertex VertDefault
                #pragma fragment FragCoC
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 1
        {
            Name "CoC Temporal Filter"

            HLSLPROGRAM
                #pragma target 5.0
                #pragma vertex VertDefault
                #pragma fragment FragTempFilter
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 2
        {
            Name "Downsample and Prefilter"

            HLSLPROGRAM
                #pragma target 5.0
                #pragma vertex VertDefault
                #pragma fragment FragPrefilter
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 3
        {
            Name "Bokeh Filter (small)"

            HLSLPROGRAM
                #pragma target 3.5
                #pragma vertex VertDefault
                #pragma fragment FragBlur
                #define KERNEL_SMALL
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 4
        {
            Name "Bokeh Filter (medium)"

            HLSLPROGRAM
                #pragma target 3.5
                #pragma vertex VertDefault
                #pragma fragment FragBlur
                #define KERNEL_MEDIUM
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 5
        {
            Name "Bokeh Filter (large)"

            HLSLPROGRAM
                #pragma target 3.5
                #pragma vertex VertDefault
                #pragma fragment FragBlur
                #define KERNEL_LARGE
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 6
        {
            Name "Bokeh Filter (very large)"

            HLSLPROGRAM
                #pragma target 3.5
                #pragma vertex VertDefault
                #pragma fragment FragBlur
                #define KERNEL_VERYLARGE
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 7
        {
            Name "Postfilter"

            HLSLPROGRAM
                #pragma target 3.5
                #pragma vertex VertDefault
                #pragma fragment FragPostBlur
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 8
        {
            Name "Combine"

            HLSLPROGRAM
                #pragma target 3.5
                #pragma vertex VertDefault
                #pragma fragment FragCombine
                #include "DepthOfField.hlsl"
            ENDHLSL
        }

        Pass // 9
        {
            Name "Debug Overlay"

            HLSLPROGRAM
                #pragma target 3.5
                #pragma vertex VertDefault
                #pragma fragment FragDebugOverlay
                #include "DepthOfField.hlsl"
            ENDHLSL
        }
    }

于是问题就明了了。我们发现景深的shader里每个pass里多了 #pragma target 3.5或#pragma target 5.0。

先看看什么是 #pragma target。

当编写表面着色器或常规shader着色器程序时,HLSL源代码可以编译成不同的“着色器模型”。为了允许使用更现代的GPU功能,您必须使用更高的着色器编译目标。

但是:使用更高的着色器编译目标,可能使着色器不能在旧的GPU或平台上工作。

Unity默认将着色器编译成最低支持目标(2.5);介于DirectX着色器模型2.0和3.0之间。任何着色器如果没有通过 #pragma 为几何体、外壳或域着色器明确的设置函数入口点,都将降低内部着色器的能力要求。这将让着色器在更多的非DX11平台都可以兼容工作。

这儿有一些可支持的着色器模型列表,可以提升一些兼容性(在某些情况下需要更高的平台/GPU):

#pragma target 2.0

  • Unity所有平台都支持。DX9着色器模型2.0。
  • 有限数量的算术和纹理指令;8个插值器;没有顶点阶段纹理采样;片段着色器中没有导数
    ;没有显式的LOD纹理采样。

#pragma target 2.5(efault)

  • 几乎与3.0 目标模型一样(往下看),除了仍然只有8个插值器,没有显式的LOD纹理采样。
  • 在Windows Phone平台上编译到DX11特性级别9.3的。

#pragma target 3.0

  • DX9着色器模型3.0:导数指令,LOD纹理采样,10个插值器,更多的数学/纹理指令。
  • 不支持DX11特性界别9.x GPU(例如,多数的Windows Phone设备)。
  • 在一些OpenGL ES 2.0设备不完全支持,这取决于当前的驱动程序扩展和所使用的特性。

#pragma target 3.5(or es3.0)

  • OpenGL ES 3.0的功能(在D3D平台的DX10 SM4.0,仅仅是没有几何着色器)。
  • 不支持DX11 9.X(WinPhone),OpenGL ES 2.0。
  • 支持DX11+,OpenGL 3.2+,OpenGL ES 3+,Metal,Vulkan,PS4/XB1 游戏主机。
  • 着色器原生整形操作,纹理数组,等。

#pragma target 4.0

  • DX11 SM 4.0。
  • 不支持DX11 9.X(WinPhone),OpenGL ES 2.0/3.0/3.1,Metal。
  • 支持DX11+,OpenGL 3.2+,OpenGL ES 3.1+AEP,Vulkan,PS4/XB1 游戏主机。拥有几何着色器和所有es3.0目标的。

#pragma target 4.5(or es3.1)

  • OpenGL ES 3.1的功能(在D3D平台的DX11 SM5.0,仅仅没有曲面细分着色器)。
  • 在SM5.0前不支持DX11,OpenGL 4.3前(例如:Mac),OpenGL ES 2.0/3.0。
  • 支持DX11+SM5.0,OpenGL 4.3+,OpenGL ES 3.1,Metal,Vulkan,PS/XB1 游戏主机。
  • 有用通用计算着色器,司机访问纹理些,原子操作,等。没有几何,曲面细分着色器。

#pragma target 4.6(oor gl4.1)

  • OpenGL 4.1的功能(在D3D平台的DX11 SM5.0,仅仅没有通用计算着色器)。这基本上是Mac上支持的最高OpenGL。
  • 在SM5.0前不支持DX11,4.1前不支持OpenGL,OpenGL ES 2.0/3.0/3.1,Metal。
  • 支持DX11+SM5.0,OpenGL 4.1+,OpenGL ES 3.1+AEP,Vulkan,Metal(没有几何着色器),PS4/XB1 游戏主机。

#pragma target 5.0

  • DX11 着色器模型5.0。
  • 在SM5.0前不支持DX11,4.3前不支持OpenGL(例如:Mac),OpenGL ES 2.0/3.0/3.1,Metal。
  • 支持DX11+SM5.0,OpenGL 4.3+,OpenGL ES 3.1+AEP,Vulkan,Metal(没有几何着色器),PS4/XB1 游戏主机。

注意所有OpenGL类平台(包括移动平台的)都将会被看作是“SM3.0”。WP8/WinRT 平台(DX11特性级别9.x)被看作是SM2.5。

因为自己项目中自己写的shader一般都是用#pragma target 3.0,在大多数机型基本没出什么问题,所以我把景深shader里#pragma target全改为3.0。

想一下也知道,低端机用#pragma target 5.0的着色器编译目标,编译不通也正常。所以Frame Dugger里我们会发现景深无效的情况下,当前draw call里的pass用的#0,然后ZTest、Zwirte、Cull的属性都是默认的设置,跟我shader里的设置完全不对。因为着色器编译目标太高,此低档机不支持,所以找不到任何一个可以渲染的pass,所以就出问题了。

你可能感兴趣的:(unity,Shader,游戏开发,unity)