- 0x00 基本概念
“Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出。绘图单元可以依据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上对应的Shader,以及对Shader的特定的参数设置,将这些内容(Shader及输入参数)打包存储在一起,得到的就是一个Material(材质)。之后,我们便可以将材质赋予合适的renderer(渲染器)来进行渲染(输出)了。”
“所以说Shader并没有什么特别神奇的,它只是一段规定好输入(颜色,贴图等)和输出(渲染器能够读懂的点和颜色的对应关系)的程序。而Shader开发者要做的就是根据输入,进行计算变换,产生输出而已。”
上述文字来自:猫都能学会的Unity3D Shader入门指南(一) - 0x01 Unity Shader 与 Shader
Unity Shader与其他游戏引擎的Shader并不是同一种东西。Unity Shader在传统的Shader基础上进行了再次的封装,简化了一些开发者需要处理的繁琐细节。
Unity Shader与Shader的不同之处:
- 在传统的Shader中,我们仅可以编写特定类型的Shader,例如定点着色器、片元着色器等。而在Unity Shader中,我们可以在同一个文件里同时包含需要的定点着色器和片元着色器代码。
- 在传统的Shader中,我们无法设置一些渲染设置,例如是否开启混合、深度测试等,这些是开发者在另外的代码中自行设置的。而在Unity Shader中,我们通过一行特定的指令就可以完成这些设置。
- 在传统的Shader中,我们需要编写冗长的代码来设置着色器的输入输出,要小心地处理这些输入输出的位置对应关系等。而在Unity Shader中,我们只需要在特定语句块中声明一些属性,就可以依靠材质来方便地改变这些属性。
- 0x02 Unity Shader的分类
- 顶点着色器(Vertex Shader)
产生纹理坐标、颜色、点大小、雾坐标,然后把它们传递给裁剪极端。 - 片元着色器(Fragment Shader)
进行纹理查找,决定什么时候执行纹理查找,是否进行纹理查找,及把什么作为纹理坐标。
- 顶点着色器(Vertex Shader)
Shader "ShaderSample"
{
SubShader{
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
float4 vert(float4 v : POSITION) : SV_POSITION{
return mul (UNITY_MATRIX_MVP, v);
}
fixed4 frag() : SV_Target{
return fixed4(1.0, 0.0, 0.0, 1.0);
}
ENDCG
}
}
}
3.表面着色器(Surface Shader)
表面着色器是Unity自己创造的一种着色器代码类型。它需要的代码量较之实现的功能要少很多,Unity在背后做了很多工作,本质上Unity仍旧是将表面着色器转化为顶点着色器和片元着色器。可以通过下述方式查看表面着色器转化后的代码:
表面着色器是Unity对顶点着色器和片元着色器的一层封装,尤其是处理了很多光照细节。
- 0x03 Unity Shader关键字
1.Properties语义块
包含了一些属性,这些属性将会出现在材质面板中。
Properties{
// 编辑器显示的名称| 属性类型 | 属性默认值
Name("display name", PropertyType) = DefaultValue
}
2.SubShader
每个Unity Shader文件需要包含至少一个SubShader语义块。当Unity Shader被加载时,Unity会扫描所有的SubShader语义块,然后选择第一个能够在目标平台上运行的SubShader。如果都不支持,Unity会使用Fallback语义指定的Unity Shader。
SubShader的标签是一个键值对,它的键和值都是字符串类型。
Tags{"TagName1" = "Value1" "TagName2" = "Value2"}
常见的标签类型有:
标签名称 | 说明 | 用法 |
---|---|---|
Queue | 控制渲染顺序,指定渲染队列 | Tags{“Queue” = “Transparent”} |
RenderType | 对着色器进行分类 | Tags{“RenderType” = “Opaque”} |
IgnoreProjector | 为True时,忽略投影 | Tags{“IgnoreProector” = “True”} |
3. Pass
一般来说Cg/HLSL实现的Unity Shader部分都写在Pass语义块中:
Pass {
CGPROGRAM
...
ENDCG
}
4.Fallback
在每个Unity Shader的最后,我们都会加上Fallback作为备胎。表明在此之上都没有找到适合当前设备的Unity Shader便执行这个Shader。有点类似于C++中Switch-case中的default语句。
Fallback "default shader name"
//也可以关闭Fallback
Fallback Off
- 0x04 参考资料: