一、ShaderLab
Shader Lab是Unity提供的编写 Unity Shader 的一种说明性语言。
从设计上来说,Shader Lab类似与CgFX和Direct3D Effects(.FX)语言,他们都定义了要显示一个材质所需的所有东西,而不仅仅是着色器代码。
Shader "ShaderName"{
Properties{
//属性
}
SubShader{
//显卡A使用的子着色器
}
SubShader{
//显卡B使用的子着色器
}
Fallback "VertexLit"
}
二、Unity Shader的结构
(1)Properties
Properties{
Name ("DisplayName",PropertiesType)=DefaultValue
Name ("DisplayName",PropertiesType)=DefaultValue
//更多属性
}
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,4,5) |
2D | "defaulttexture"{} | _2D("2D",2D)=""{} |
Cube | "defaulttexture"{} | _Cube("Cube",Cube)="white"{} |
3D | "defaulttexture"{} | _3D("3D",3D)="back"{} |
属性类型的例子:
Shader"Custom/ShaderLabProperties"{
Properties{
//Number and Sliders
_Int("Int",Int)=2
_Float("Float",Float)=1.0
_Range("Range",Rnage(1.0,2.0))=1.5
//Colors and Vectors
_Color("Color",Color)=(1,1,1,1)
_Vector("Vector",Vector)=(1,2,3,4)
//Texctures
_2D("2D",2D)=""{}
_Cube("Cube",Cube)="white"{}
_3D("3D",3D)="black"{}
}
FallBack "Diffuse"
}
(2)SubShader
SubShader{
//可选的
[Tags]
//可选的
[RenderSetup]
Pass{
}
//Other Passes
}
每一个Pass定义了一次完整的渲染流程,但如果Pass的数目过多,往往会造成渲染性能的下降。
SubShader 和 Pass 中的标签设置不一样,但状态设置的语法是相同的。
SubShader 进行的设置会应用到所有的Pass。
状态设置
常见的渲染状态设置选项
状态名称 | 设置指令 | 解释 |
Cull | Cull Back|Front|Off | 设置剔除模式:剔除背面/正面/关闭剔除 |
ZTest | ZTest Less Greater|LEqual|GEqual|Equal|NotEqual|Always | 设置深度测试时使用的函数 |
ZWrite | ZWrite On|Off | 开启/关闭深度写入 |
Blend | Blend Off|SrcFactor DstFactor | 关闭/开启设置混合模式 |
SubShader的标签
SubShader 的标签(Tags)是一个键值对(Key/Value Pair),它的键和值都是字符串类型。这些键值对是SubShader和渲染引擎之间的沟通桥梁。
Tags{ "TagName 1" = "Value1" "TagName 2" = "Value2" }
SubShader的标签类型
标签类型 | 说明 | 例子 |
Queue | 控制渲染顺序,指定该物体属于哪一个渲染队列。 这种方式可以保证所有的透明物体可以在不透明物体后渲染。 也可自定义渲染顺序。 | Tags{ "Queue" = "Transparent"} |
RenderType | 对着色器进行分类。 例如这是一个不透明着色器 或 是一个透明着色器等。 可被用于着色器替换(ShaderReplacement)功能。 | Tags{ "RenderType" = "Opaque"} |
DisableBatching | 一些SubShader在使用批处理时会出现问题。 例如:使用模型空间下的坐标进行顶点动画。 这时可以通过该标签直接指明是否对该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"} |
Pass语义块
Pass{
[Name]
[Tags]
[RenderSetup]
//Other code
}
可以在Pass中定义该Pass的名称,如:
Name "MyPassName"
通过这个名称,可以使用Shader Lab的Use Pass命令来直接使用其他Unity Shader中的Pass。
UsePass "MyShader/MYPASSNAME"
//Unity内部会把所有Pass的名称转换成大写字母
//使用UsePass命令时,Pass名字必须大写
Pass中还可以使用固定管线的着色器命令。
Pass的标签也是用于告诉渲染引擎怎么来渲染该物体。
Pass的标签类型
标签类型 | 说明 | 例子 |
LightMode | 定义该Pass在Unity的渲染流水线中的角色 | Tags{ "LightMode" = "ForwardBase"} |
RequireOptions | 用于指定当满足某些条件时渲染该Pass,它的值是一个由空格分隔的字符串。 目前支持的选项有:SoftVegectation | Tags{ "RequireOptions" = "SoftVegetation"} |
UnityShader还支持一些特殊的Pass,以便进行代码复用 或 实现更复杂的效果。
Use Pass:复用其他Unity Shader中的Pass
Grab Pass:该Pass负责抓取屏幕并将结果存储在一张纹理中,以用于后续的Pass处理。
(3)FallBack
Fallback "name"
//或者
Fallback Off
Fallback还会影响阴影的投射。
Fallback使用的内置Shader中包含了一个通用的阴影投射的Pass。
正确设置Fallback也非常重要。
三、UnityShader的形式
着色器代码写在SubShader语义块中是表面着色器的做法,写在Pass语义块中,是顶点/片元着色器和固定函数着色器的做法。
Shader "MyShader" {
Properties{
//所需的各种属性
}
SubShader{
//真正意义上的Shader代码会出现在这里
//表面着色(Surface Shader)或者
//顶点/片元着色器(Vertex/Fragment Shader)或者
//固定函数着色器(Fixed Function Shader)
}
SubShader{
//和上一个SubShader类似
}
}
(1)表面着色器(Surface Shader)
表面着色器是Unity自己创造的一种着色器代码类型。
代码量很少,但渲染代价很大。
在背后仍旧把它转换成对应的顶点/片元着色器。
它存在的价值在于,为我们处理了很多光照细节。
Shader "Custom/Simple Surface Shader"{
SubShader{
Tags{ "RenderType" = "Opaque"}
CGPROGRAM
#pragma surface surf Lambert
struct Input{
float4 color:COLOP;
};
void surf (Input IN, inout SurfaceOutput o ){
o.Albedo = 1;
}
ENDCG
}
Fallback "Diffuse"
}
CGPROGRAM 和 ENDCG 之间的代码是使用 CG/HLSL 编写的
(2)顶点/片元着色器(Vertex/Fragment Shader)
灵活性高,可控制渲染细节。
Shader "Custom/Simple VertecFragment Shader"{
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#peagma fragment farag
float4 vert(float4 v : POSITION) : SV_POSITION{
return mul (UNITY_MATRIX_MVP, v );
}
float4 frag() : SV_Target {
return fixed4(1.0,0..0,0.0,1.0);
}
ENDCG
}
}
}
(3)固定函数着色器(Fixed Function Shader)
不支持可编程管线着色器,就需要使用固定函数着色器来完成渲染。
Shader "Tutorial/Basic" {
Properties {
_Color ("Main Color",Color) = (1,0.5,0.5,1)
}
SubShader {
Pass {
Material {
Diffuse [_Color]
}
Lighting On
}
}
}
(4)选择哪种UnityShader形式
- 和各种光源打交道,选表面着色器。
- 光源数目比较少,有很多自定义渲染效果的,选顶点/片元着色器。