编写着色器时的性能技巧
自定义着色器 GUI

使用替换的着色器进行渲染

有些渲染效果需要使用一组不同的着色器来渲染场景。例如,良好的边缘检测要求纹理具有场景法线,这样才能检测出表面方向不同的边缘。其他效果可能要求纹理具有场景深度,诸如此类。为此,可使用所有对象的替换着色器来渲染场景。

应通过脚本使用函数 Camera.RenderWithShaderCamera.SetReplacementShader 来实现着色器替换。这两个函数均采用 shaderreplacementTag

工作方式如下:摄像机按正常方式渲染场景,对象仍使用自己的材质,但要更改最终使用的实际着色器:

  • 如果 replacementTag 为空,则使用指定的替换着色器来渲染场景中的所有对象。
  • 如果 replacementTag 不为空,则对于将要渲染的每个对象:
    • 查询真实对象的着色器以获取标签值
    • 如果没有该标签,则不渲染对象。
    • 在替换着色器中找到一个子着色器,并且该子着色器的一个给定标签具有找到的值。如果找不到此类子着色器,则不渲染对象。
    • 现在,使用该子着色器来渲染对象。

因此,比如说,如果所有着色器都要有一个值为“Opaque”、“Transparent”、“Background”或“Overlay”的“RenderType”标签,则可编写一个替换着色器,该着色器只使用一个具有 RenderType = Solid 标签的子着色器来渲染实体对象。在替换着色器中找不到其他标签类型,因此不会渲染对象。或者您也可以为不同“RenderType”标签值编写若干子着色器。顺便提一下,Unity 的所有内置着色器都设置了一个“RenderType”标签。

光照着色器替换

使用着色器替换时,将使用摄像机上配置的渲染路径来渲染场景。这意味着用于替换的着色器可以包含阴影和光照通道(您可以使用表面着色器进行着色器替换)。这对于渲染特殊效果和场景调试很有用。

Unity 内置着色器中的着色器替换标签

Unity 的所有内置着色器都设置了一个“RenderType”标签,可以在使用替换着色器进行渲染时使用此标签。标签值如下:

  • __Opaque__:大部分着色器(法线自发光反射和地形着色器)。
  • __Transparent__:大部分半透明着色器(透明、粒子、字体和地形附加通道着色器)。
  • __TransparentCutout__:遮罩透明度着色器(透明镂空、两个通道植被着色器)。
  • __Background__:天空盒着色器。
  • __Overlay__:GUI 纹理、光环、光晕着色器。
  • __TreeOpaque__:地形引擎树皮。
  • __TreeTransparentCutout__:地形引擎树叶。
  • __TreeBillboard__:地形引擎公告牌树。
  • __Grass__:地形引擎草。
  • __GrassBillboard__:地形引擎公告牌草。

内置场景深度/法线纹理

摄像机内置了渲染深度或深度+法线纹理的功能(可能在某些效果中需要该功能)。请参阅摄像机深度纹理页面。请注意,在某些情况下(取决于硬件),可以使用着色器替换方法在内部渲染深度和深度+法线纹理。因此,务必在着色器中设置正确的“RenderType”标签。

代码示例

Start() 函数指定替换着色器:

void Start() {
    camera.SetReplacementShader (EffectShader, "RenderType");
}

此函数请求 EffectShader 使用 RenderType 键。对于所需的每个 RenderType,EffectShader 都有一个键/值标签。Shader 应如下所示:

Shader "EffectShader" {
     SubShader {
         Tags { "RenderType"="Opaque" }
         Pass {
             ...
         }
     }
     SubShader {
         Tags { "RenderType"="SomethingElse" }
         Pass {
             ...
         }
     }
 ...
 }

SetReplacementShader 将检查场景中的所有对象,不使用它们的普通着色器,而是使用第一个具有指定键的匹配值的子着色器。在此示例中,任何对象的着色器若具有 Rendertype=“Opaque” 标签,都将被 EffectShader 中的第一个子着色器替换,任何对象若具有 RenderType=“SomethingElse” 着色器都将使用第二个替换子着色器,以此类推。如果任何对象的着色器不具有替换着色器中指定键的匹配标签值,则不会渲染这样的对象。

编写着色器时的性能技巧
自定义着色器 GUI