ShaderLab:专门为 UnityShader 服务的语言,在 Unity 中所有的 UnityShader 都是使用 ShaderLab 来编写的
对于之前 OpenGL 的学习需要考虑很多事情,包括但不限于模型和资源的加载、着色器的选择与输入、渲染状态的设置等,现在对于 Unity3D 还再多一个跨平台。这样要考虑的事情实在是太多了,而有了 UnityShader 这一抽象层后,开发者只需要使用 ShaderLab 来编写 UnityShader 文件就可以完成所有的工作
ShaderLab 使用了一些嵌套在花括号内部的语义 (syntax) 来描述一个 UnityShader 文件的结构,这些结构包含了许多渲染所需的数据
UnityShader 的基础结构如下所示:
Shader "Test/TestShaderA" //Shader的名字/路径
{
Properties
{
//属性,会显示在材质面板中
}
SubShader
{
//显卡A使用的子着色器
}
SubShader
{
//显卡B使用的子着色器
}
Fallback "Test/TestShaderB"
}
只要新建了 .Shader 文件,都可以在这里找到:
属性(property)定义,这些属性会出现在材质面板中
一个例子如下:
Properties
{
_MainTex("Texture", 2D) = "white" {}
_DepthFade("颜色深度渐变", range(0,30)) = 0.4
_Distance("距离", Float) = 50
[Space]
_WaveScale("波纹参数", Vector) = (0.063,0.25,0.5,1)
_ReflectionTex("倒影", CUBE) = "" {}
_SpecularColor("高光色", color) = (1,1,1,1)
}
对应到的材质面板:
其中 [Space] 可以让面板上对应的两个属性中间空上一个间距
很好理解,其中 Properties 语义块支持的属性类型如下:
属性类型 | 默认值的定义语法 | 例子 |
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 | (num, num, num, num) | _Color("Color", Color) = (1,1,1,1) |
Vector | (num, num, num, num) | _Vector("Vector", Vector) = (2,3,6,1) |
2D | "defaulttexture" {} | _2D("2D", 2D) = "" {} |
Cube | "defaulttexture" {} | _Cube("Cube", Cube) = "white" {} |
3D | "defaulttexture" {} | _3D("3D", 3D) = "black" {} |
后面三个属性的默认值是通过一个字符串后跟一个花括号来指定的,其中字符串可以留空,也可以是一些基本的内置纹理颜色,而花括号原本是用于指定纹理属性的,在5.0后的Unity版本中被废弃,留空即可
需要注意的是:Properties 语义块只是为了让属性可以出现在材质面板中,当然也可以在着色器语言(CG代码片)中直接定义属性,并通过脚本向 Shader 中传递这些属性
每一个 UnityShader 文件可以包含多个 SubShader 语义块,但至少要有一个。当 Unity 需要加载这个 UnityShader 时,Unity 会扫描所有的 SubShader 语义块,然后选择第一个能够在目标平台/显卡上运行的 SubShader,如果都不支持的话,Unity 就会使用 Fallback 语义指定的 UnityShader,当然 Fallback 并不是单纯的尝试用另一个子着色器,而是将对应的子着色器的代码全部插入到这个位置
SubShader 包含的内容大致如下:
SubShader
{
[Tags] //标签,可以没有
[RenderSetup] //状态,可以没有
Pass
{
[Name] //当前Pass的名称
[Tags] //标签,可以没有,只对当前Pass块有效
[RenderSetup] //状态,可以没有,只对当前Pass块有效
//…… //核心代码
}
}
Fallback "候补着色器的名字" //如果没有候补,填 Off
其中 Pass 数目过多可能导致渲染性能下降
常用标签:
标签类型 | 说明 | 例子 | 是否可在Pass块中声明 |
Queue | 控制渲染顺序,指定该物体属于哪—个渲染队列,通过这种方式可以保证所有的透明物体可以在所有不透明物体后面被渲染,也可以自定义使用的渲染队列来控制物体的渲染顺序 | Tags { "Queue"= "Transparent-10" } | X |
RenderType | 对看色器进行分类,例如是否为透明/不透明(Opaque)着色器。可以被用于着色器替换功能 | Tags { "RenderType" = "Opaque" } | X |
DisableBatching | 一些 SubShader 在使用 Unity 的批处理功能时会出现问题,这时可以通过该标签来指明是否对该 SubShader 使用批处理 | Tags { "DisableBatching" = "True" } | X |
ForceNoShadowCasting | 控制使用该 SubShader 的物体是否会投射阴影 | Tags { "ForceNoShdowCasting" = "True" } | X |
lgnoreProjector | 如果该标签值为 "True", 那么使用该 SubShader 的物体将不会受 Projector 的影响,通常用于半透明物体 | Tags { "lgnoreProjector" = "True" } | X |
CanUseSpriteAtlas | 当该 SubShader 是用于 sprites 时,需要将该标签设置为 False | Tags { "CanUseSpriteAtlas" = "False" } | X |
PreviewType | 指明材质面板将如何预览该材质,默认情况下材质 PreviewType 将显示为一个球形,可以通过将该标签的值设为 "Plane"、"SkyBox" 等以改变预览类型 | Tags { "PreviewType" = "Plane" } | X |
LightMode | 定义该 Pass 在 Unity 渲染流水线中的角色 | Tags { "LightMode" = "ForwardBase" } | ✔ |
RequireOptions | 用于指定当满足某些条件时才渲染该 Pass,它的值是一个由空格分隔的字符串 | Tags { "RequireOptions" = "SoftVegetation" } | ✔ |
状态设置:
这些应该就比较熟悉了,例如是否开启深度/模板测试等(都可在 Pass 内部声明)
状态名称 | 设置指令 | 说明 |
Cull | Cull Back I Front I Off | 设置剔除模式:剔除背面 / 正面 / 关闭剔除 |
ZTest | ZTest Less Greater I LEqual I GEqual I Equal I NotEqual I Always | 设置深度测试时使用的函数 |
ZWrite | ZWrite On I Off | 开启 / 关闭深度写入 |
Blend | Blend Srcfactor Dstfactor | 开启并设置混合模式 |
一个 SubShader 的例子:
Subshader
{
Tags { "RenderType"="Opaque" "IgnoreProjector" = "True" "Queue" = "Transparent-10" }
LOD 100
Pass {
Tags{ "LightMode" = "ForwardBase" }
ZTest LEqual ZWrite Off Cull Back
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
Extra: