Unity Shader的结构
一个Unity Shader的基础结构如下所示:
1 | Shader "ShaderName"{ |
Unity会根据目标平台来把这些结构编译成真正的代码和Shader文件。
Shader名
每一个Unity Shader文件的第一行都需要通过“Shader”语义来指定该Unity Shader的名字。
1 | Shader"Custom/MyShader"{ } |
Properties
Properties语义块中包含了一系列属性(Property)这些属性将会出现在材质面板中。
Properties语义块定义:
1 | Properties{ |
Name:Shader声明的属性名,供Shader内部使用。这些属性名通常由一个下划线开始。
display name:材质面板中显示的名字。
PropertyType:属性的本质类型。
属性类型 | 默认值的定义语法 | 例子 |
---|---|---|
Int | number | _Int (“Int”, Int) = 2 |
Float | number | _Float (“Float”, Float) = 1.5 |
Range(min,max) | number | _Range (“Range”, Range(0.0,5.0)) = 3.0 |
Color | (number,number,number,number) | _Color (“Color”, Color) = (1,1,1,1) |
Vector | (number,number,number,number) | _Vector (“Vector”, Vector) = (2,3,6,1) |
2D | “defaulttexture”{} | _2D (“2D”, 2D) = “” {} |
Cube | “defaulttexture”{} | _Cube (“Cube”, Cube) = “white” {} |
3D | “defaulttexture”{} | _3D (“3D”, 3D) = “black” {} |
2D、Cube、3D属于纹理类型,它们的默认值是通过一个字符串后跟一个花括号来指定的。
字符串可以为空,也可以设置为内置的纹理名称:“white”、“black”、“gray”或者“bump”。
花括号内部原本是用于指定一些纹理属性。在老版本Unity固定管线中比较有用。新版本Unity移除了这些纹理选项。只能通过编写顶点着色器代码来代替。
1 | Shader "Custom/ShaderLabProperties" { |
有时,我们想要在材质面板上显示更多类型的变量,可以使用Unity编辑器拓展来拓展材质面板。
Redify.Shader
1 | Shader "Unity Shaders Book/Chapter 3/Redify" { |
Editor文件夹内的CustomShaderGUI
脚本
1 | public class CustomShaderGUI : ShaderGUI |
需要注意的是,这个自定义编辑器中访问的Shader属性是写在Shader的Cg代码片(CGPROGRAM)内的。我们的Properties语义块的作用仅仅是为了让这些属性可以出现在材质面板中
SubShader
每一个Unity Shader文件可以包含多个SubShader语义块,但最少要有一个。
当Unity需要加载这个Unity Shader时,Unity会扫描所有的SubShader语义块,然后选择第一个能够在目标平台上运行的SubShader。如果都不支持的话,Unity就会使用Fallback语义指定的Unity Shader。
SubShader的意义是在旧的显卡使用计算复杂度较低的着色器,在高级的显卡使用复杂度高的着色器。
SubShader的语义块定义:
1 | SubShader{ |
SubShader中定义了一系列Pass以及可选的状态([RenderSetup])和标签([Tags])设置。
每个Pass定义了一次完整的流程,Pass过多会造成渲染性能的下降。
RenderSetup和Tags同样可以在Pass中声明。不同的是,SubShader中的一些Tags是特定的,这个Tag和Pass中使用的不一样。而RenderSetup在Pass中和SubShader中语法都一样,只不过SubShader的RenderSetup作用于所有的Pass。
状态(RenderSetup)设置
常见的状态设置选项
状态名称 | 设置指令 | 解释 |
---|---|---|
Cull | Cull Back | Front | Off | 设置剔除模式,剔除背面/正面/关闭剔除 |
ZTest | ZTest Less Greater | LEqual | GEqual | Equal | NotEqual | Always | 设置深度测试时使用的函数 |
ZWrite | ZWrite On | Off | 开启/关闭深度写入 |
Blend | Blend SrcFactor DstFactor | 开启并设置混合模式 |
当在SubShader块中设置了上述渲染状态,将会应用到所有的Pass。如果不想这样(例如在双面渲染中,我们希望第一个Pass中剔除正面来对背面进行渲染,在第二个Pass中剔除背面来对正面进行渲染),可以在Pass语义块中单独进行上面的设置。
SubShader的Tags
SubShader的Tags是一个键值对(Key/Value Pair),它的键和值都是字符串类型。它们用来告诉渲染引擎:我希望怎样以及何时渲染这个对象。
标签的结构:
1 | Tags { "TagName1" = "Value1" "TagName2" = "Value2" } |
SubShader的标签块支持的标签类型:
标签类型 | 说明 | 例子 |
---|---|---|
Queue | 控制渲染顺序,指定该物体属于哪一个渲染队列,通过这种方式可以保证所有的透明物体可以在所有不透明物体后面被渲染,我们也可以自定义使用的渲染队列来控制物体的渲染顺序 | Tags { “Queue” = “Transparent” } |
RenderType | 对着色器进行分类,例如这是一个不透明的着色器,或是一个透明的着色器等。这可以被用于着色器替换(Shader Replacement)功能 | Tags { “RanderType” = “Opaque” } |
DisableBatching | 一些SubShader在使用Unity的批处理功能时会出现问题,例如使用了模型空间下的坐标进行顶点动画。这时可以通过该标签来直接指明是否对该SubShader使用批处理。 | Tags { “DisableBatching” = “True” } |
ForceNoShadowCasting | 控制使用该SubShader的物体是否会投射阴影 | Tags { “ForceNoShadowCasting” = “True” } |
IgnoreProjector | 如果该标签设置为“True”,那么使用该SubShader的物体将不受Projector影响。通常用于半透明物体 | Tags { “IgnoreProjector” = “True” } |
CanUseSpriteAtlas | 当该SubShader是用于Sprites时,将该标签设置为False | Tags { “CanUseSpriteAtlas” = “False” } |
PreviewType | 指明材质预览面板的物体显示类型,可以设置为“Plane”、“SkyBox”等 | Tags { “PreviewType” = “Plane” } |
上述标签仅可以在SubShader中声明,不可以在Pass块中声明。Pass块中的标签是不同于SubShader标签的类型。
Pass语义块
Pass语义块的定义
1 | Pass{ |
首先,我们可以Pass中定义该Pass的名称,例如:
1 | Name "MyPassName" |
通过这个名称可以使用ShaderLab的UsePass命令来直接使用其他UnityShader中的Pass。例如:
1 | UsePass "MyShader/MYPASSNAME" |
Unity内部会把所有Pass的名称转换成大写字母表示。因此,在使用UsePass命令时必须使用大写形式的名字。
我们可以对Pass设置RenderSetup,它可使用和上述SubShader相同的状态设置,除此之外在Pass之中还可以使用固定渲染管线着色器命令。
Pass中的标签不同于SubShader的标签。这些标签也是用于告诉引擎我们希望怎样来渲染物体。
标签类型 | 说明 | 例子 |
---|---|---|
LightMode | 定义该Pass在Unity渲染流水线中的角色 | Tags { “LightMode” = “ForwardBase” } |
RequireOptions | 用于指定当满足某些条件时才渲染该Pass,它的值是一个由空格分开的字符串。目前,Unity支持的选项有:SoftVegetaion。 | Tags { “RequireOptions” = “SoftVegetation” } |
除了上面普通的Pass定义之外,Unity Shader还支持一些特殊的Pass:
- UsePass:使用该命令来复用其他UnityShader中的Pass
- GrabPass:该Pass负责抓取屏幕并将结果存储在一张纹理中,用于后续的Pass处理。
FallBack
如果SubShader在当前显卡都不能运行,可以使用Fallback指令来让Unity返回一些适应性较广的Shader预设。
1 | Fallback "name" |
我们可以通过一个字符串来指定这个预设。也可以直接关闭Fallback。
1 | Fallback "VertexLit"//顶点照明 |
Fallback还会影响阴影的投射。在渲染阴影纹理时,Unity会在每个UnityShader中寻找一个阴影投射的Pass。通常情况下,我们不需要自己专门实现一个Pass,Fallback的预设中包含了投射阴影的通用Pass。
ShaderLab其他语义
CustomEditor:拓展编辑器界面
1 | CustomEditor "Editor_Extension_Script_Name" |
引号内指定应用此Shader一些参数来拓展编辑器的编辑器拓展脚本的名称。
Category:对UnityShader中的命令进行分组。