Shader学习 之 ShaderLab语法: SubShader

每个shader都由一列SubShader构成。真正用于呈现渲染物体的内容是在SubShader中实现的。Unity在实际运行时,会根据硬件情况从上到下选择最优的一个SubShader来执行。

语法

Subshader {
[Tags]
[CommonState]
Passdef [Passdef ...]
}

细节

每个SubShader都定义了一系列passes,并可对所有passes可选的设置任一状态。另外,还可以指定[Tags]。
当Unity选定了一个SubShader,它会对定义的每一个pass都渲染一遍。有时在某些硬件某些复杂的渲染效果必须在多个pass中完成。

每个pass都可以被定义成 regular PassUse Pass or Grab Pass.

Pass简介

一个pass块引起一次物体的几何学渲染。

  • 语法

    Pass { [Name and Tags] [RenderSetup] }

  • Name and tags
    一个pass块可以定义它的名字和任意数量的Tags。
    内置的Tags都是针对渲染路径的,告诉渲染引擎这个pass块应该在什么路径下被渲染。
    Name一般被用来引用Pass块。pass名字都是大写。
UsePass

UsePass命令可以使用另一个shader中的pass块,从而减少重复劳动。

格式:

UsePass "Shader/Name"

若要UsePass能工作,所引用的pass块必须定义了名字。

GrabPass

GrabPass是一种特殊的pass类型,它可以捕获物体所在位置的屏幕内容并写入到一个纹理中。从而用于后续通道完成高级图像效果。

扫描二维码关注公众号,回复: 16907761 查看本文章

语法:

  • GrabPass{},能捕获当前屏幕的内容到一个纹理中,纹理能在后续通道中通过 _GrabTexture 进行访问。注意:这种形式的捕获通道对于每个使用它的物体将进行昂贵的屏幕捕捉操作。
  • GrabPass { "TextureName" },能捕获屏幕内容到一个纹理中,但对于第一个给定纹理名的物体,只会在每帧中处理一次。在后面的通道中可以通过纹理名获取纹理。当你在一个场景中有多个物体使用grab pass,这是更高效的方法。

另外, GrabPass 能使用 Name 和 Tags 命令。

ShaderLab: SubShader Tags

Subshaders使用标签来告诉引擎如何以及何时将其渲染。

语法:

Tags { "TagName1" = "Value1" "TagName2" = "Value2" } 
指定TagName1具有Value1的值,TagName2具有Value2的值。标签的数目不受限制。

标签基本上是键值对(key-value pairs)。 在SubShader内部,标签用于确定渲染顺序和子渲染器的其他参数。 请注意,Unity识别的以下标记必须在SubShader节内,而不是Pass!

除了由Unity识别的内置标签,你也可以使用自己的标签,并使用Material.GetTag函数查询它们。

Rendering Order - Queue tag 控制渲染顺序-队列标签

你可以使用队列标签来确定对象的绘制顺序。 Shader决定其对象属于哪个渲染队列,这样所有透明的Shader能保证在所有不透明的Shader后渲染。

四个预定义的渲染队列,但是在预定义的渲染队列之间可以有更多的队列。 
预定义队列为:

  • Background:最先被调用的渲染,通常用来渲染背景。

  • Geometry (default):默认值,大多数物体使用此队列,用来渲染不透明的物体。

  • AlphaTest :alpha tested的物体使用此队列。 它是与几何一个独立的队列,因为在绘制所有实体后,渲染经过alpha-tested的对象更有效率。

  • Transparent:这个渲染队列是在Geometry和AlphaTest之后,以从后往前的顺序渲染的。 任何alpha混合(alpha-blended )(即不写入深度缓冲区depth buffer的Shader)应该在这里。例如玻璃,粒子效果。

  • Overlay: 此渲染队列用于叠加效果。 任何最后呈现的东西都应该在这里(例如镜头光晕)。

对于特殊用途,可以使用中间队列。在内部,每个队列由整数索引表示: 
Background=1000,Geometry=2000,AlphaTest=2450,Transparent=3000和Overlay=4000.

如果着色器使用这样的队列: 
Tags { "Queue" = "Geometry+1" } 
这将使对象在所有不透明物体后,但在透明物体之前渲染,作为渲染队列索引将是2001(Geometry+1)。 这在你希望某些物体始终在其他物体集之间绘制的情况下非常有用。 例如,在大多数情况下,透明的水应该在不透明物体之后但在透明物体之前绘制。

队列的值到2500(“Geometry+ 500”)被认为“不透明”,优化对象的绘制顺序以获得最佳性能。 对于“透明物体”考虑较高的渲染队列,并按距离对物体进行排序,从最远的一个开始渲染,并以最近的一个结束。 天空盒在所有不透明和所有透明对象之间绘制。

RenderType tag 渲染类型

RenderType标签将shaders分类为多个预定义组,Unity可以运行时替换符合特定RenderType的所有Shader。

一些渲染特效需要使用一些不同的shaders来渲染场景。比如,一个好的边界提取效果需要由一个记录场景法线信息的纹理才能检测出场景中的朝向变化的地方;其他效果也可能需要一个记录场景深度的纹理等等。要想达到这些效果,我们可能需要使用所有物体的替代Shaders来渲染场景。

Shader更换是从脚本使用 Camera.RenderWithShader 或 Camera.SetReplacementShader 函数来完成的。这两个函数均以一个shader和一个replacementTag作为参数。

工作流程:相机还是像平常一样来渲染场景,物体也还是使用原有的材质,但是他们的真实的shader是在使用时来进行改变:

  • 如果replacementTag是空的,那么场景中的所有物体都用给定的替换着色器来进行渲染。
  • 如果replacementTag不是空的,那么对于每个物体,将进行以下方式进行渲染: 
     按照标签值来查找物体真正的着色器。 
     如果没有标签,物体将不进行渲染。 
     在替换Shader中,我们可以根据一个具有查找值的标签来找到一个子着色器 subshader,如果没有这样的子着色器,该物体将不进行渲染。 
     现在可以应用子着色器来渲染物体。 
     

所以,如果所有shaders都拥有一个渲染类型标签,比如 “Opaque”, “Transparent”, “Background”, “Overlay”,你就可以编写一个含有”RenderType = Solid”的替换着色器来只渲染固体物体。其他标记并不会在该替换着色器中被找到,所以与其对应的物体将不会被渲染。或者,你可以编写拥有不同的”RenderType”标签值的子着色器。所有Unity内置着色器都含有一个”RenderType”标签集。

在Unity内置着色器的shader替换标签

  • Opaque: 用于大多数着色器(法线着色器、自发光着色器、反射着色器以及地形的着色器)。
  • Transparent:用于半透明着色器(透明着色器、粒子着色器、字体着色器、地形额外通道的着色器terrain additive pass shaders)。
  • TransparentCutout: 蒙皮透明着色器masked transparency shaders (Transparent Cutout,两个通道的植被着色器)。
  • Background: Skybox shaders.
  • Overlay: GUITexture,光晕,闪光着色器。
  • TreeOpaque: 地形引擎中的树皮。
  • TreeTransparentCutout: terrain engine tree leaves.
  • TreeBillboard: terrain engine billboarded trees. Grass: terrain
  • GrassBillboard: terrain engine billboarded grass.

代码示例 
在Start()函数中指定替换shaders

void Start() {
    camera.SetReplacementShader (EffectShader, "RenderType");
}
 
 
  
  
  • 1
  • 2
  • 3

这要求EffectShader使用RenderType键。 EffectShader会为每个你想要的RenderType设置键值key-value标签。 Shader中的相应代码:

Shader "EffectShader" {
     SubShader {
         Tags { "RenderType"="Opaque" }
         Pass {
             ...
         }
     }
     SubShader {
         Tags { "RenderType"="SomethingElse" }
         Pass {
             ...
         }
     }
 ...
 }
 
 
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

SetReplacementShader将查看场景中的所有对象,而不是使用它们的普通shader,使用具有指定键的匹配值的第一个subshader。 在此示例中,其shader具有Rendertype =“Opaque”标记的任何对象将被EffectShader中的第一个SubShader替换,任何具有RenderType =“SomethingElse”shader的对象将使用第二个替换SubShader,因此一个。 任何其shader在替换shader中不具有指定键的匹配标签值的对象将不会被渲染。

相关参考: 
Unity官方文档:Rendering with Replaced Shaders 
Unity圣典:使用替换着色器来渲染

DisableBatching tag 禁用批处理

当使用绘制调用批处理 Draw Call Batching 时,一些e shaders(主要是做对象空间顶点变形的shader)不工作 - 这是因为批处理将所有几何转换为世界空间,因此“对象空间”丢失。

DisableBatching标签可以用来消除这个问题。 有三个可能的值: 
“True”(始终禁用此着色器的批处理) 
“False”(不禁用批处理;这是默认值) 
“LODFading”(当LOD衰减活动时禁用批处理;主要用于树)。

ForceNoShadowCasting tag 强制无阴影投射

如果给出了ForceNoShadowCasting标签并且值为“True”,则使用此subshader渲染的对象将永远不会投射阴影。 当你在透明对象上使用shader替换,并且你不会继承来自另一个subshader的阴影传递时,这是最有用的。

IgnoreProjector tag 忽略投影机

如果给定IgnoreProjector标记并且值为“True”,则使用此shader的对象不会受到投影机的影响。 这对半透明对象最有用,因为暂时没有对他们产生投影的比较合适的办法,那么直接忽略掉就行了。。

CanUseSpriteAtlas tag 可以使用Sprite图集

如果shader用于sprite,则将CanUseSpriteAtlas标记设置为“False”,并且当它们打包到地图集时不会工作(请参阅Sprite Packer)。

PreviewType tag 预览类型

PreviewType指示material inspector预览应如何显示材质。 默认情况下,材质显示为球体,但PreviewType也可以设置为“Plane”(显示为2D)或“Skybox”(将显示为天空盒)。

整篇博客参考Unity官方文档:https://docs.unity3d.com/Manual/SL-SubShaderTags.html

猜你喜欢

转载自blog.csdn.net/qq_25189313/article/details/78032125