UnityShader的形式
前面我们讲了UnityShader文件结构以及ShaderLab语法。接下来我们看看着色器代码应该写在哪里。
表面着色器可以写在SubShader语义块中;顶点/片元着色器和固定函数着色器可以写在Pass语义块中。
1 | Shader "MyShader"{ |
Surface Shader
Surface Shader是Unity自创的,需要的代码量少,渲染代价比较大,在背后依旧会转变成相应的Vertex/Fragment Shader。Unity包装好的Surface Shader处理了很多光照细节,来简化Vertex/Fragment Shader的编写。
表面着色器代码示例
1 | Shader "Custom/Simple Surface Shader"{ |
表面着色器被定义在SubShader语义块中的CGPROGRAM和ENDCG之间,不需要开发者使用Pass,只需要定义各种纹理和光照模型即可。
CGPROGRAM和ENDCG之间的代码是用Cg/HLSL编写的,我们需要把Cg/HLSL语言嵌套在ShaderLab语言中。这里的Cg/HLSL是Unity封装后提供的,它的语法和标准的Cg/HLSL几乎一样但还是有细微的不同,有些原生函数和用法Unity并没有提供支持。
Vertex/Fragment Shader
在Unity中我们可以使用Cg/HLSL语言来编写顶点/片元着色器,它们更加复杂,但灵活性也更高。
1 | Shader "Custom/Simple VertexFragment Shader"{ |
顶点/片元着色器也需要定义在CGPROGRAM和ENDCG之间,而且需要在Pass语句块内。我们需要定义每个Pass的代码,提高了灵活性,可以控制渲染的实现细节。
Fixed Function Shader
Fixed Function Shader也需要被定义在Pass语义块中,需要完全使用ShaderLab语法,而非使用Cg/HLSL。Fixed Function Shader是为了支持较古旧的设备(DirectX7.0、OpenGL1.5、OpenGL ES1.1),现在已经被淘汰。
1 | Shader "Tutorial/Basic"{ |
一些建议
- 如果想和各种光源打交道,可以使用表面着色器,但需要小心它在移动平台的表现。
- 如果光照数目非常少,例如只有一个平行光,那么使用顶点/片元着色器。
- 如果有很多自定义风格化渲染效果,请选择顶点/片元着色器。
一些注意的点
Unity Shader不是真正的Shader
在Unity里,Unity Shader实际上指的是一个ShaderLab文件,它以“.shader”作为后缀。
真正的Shader | Unity Shader |
---|---|
仅可以编写特定类型的Shader,例如顶点着色器、片元着色器等。 | 可以在同一个文件里同时包含需要的顶点着色器和片元着色器代码 |
无法设置渲染。 | 可以通过特定的指令来设置Blend、ZTest等 |
需要编写冗长的代码来设置着色器的输入和输出,要小心处理输入输出的位置对应关系等。 | 只需要在Property语句块中声明属性,就可以靠材质来方便地改变。而对于模型自带地数据(顶点位置、纹理坐标、法线等),UnityShader提供了直接访问的方法。 |
UnityShader的缺点:
Unity仅在DirectX11平台下提供曲面细分着色器(Tessellation Shader)、几何着色器(Geometry Shader)的相关功能。
一些高级的Shader语法Unity Shader也不支持
Unity Shader和Cg/HLSL之间的关系
Unity Shader是用ShaderLab语言来编写的,Cg/HLSL通过嵌套在ShaderLab的CGPROGRAM和ENDCG之间来发挥作用。Cg和DX9风格的HLSL几乎是同一种语言,因此在Unity里Cg和HLSL是等价的。
1 | Pass{ |
表面着色器中,Cg/HLSL代码写在SubShader语句块中,我们可以通过一个表面着色器的Inspector窗口点击Show generated code来查看真正生成的顶点/片元着色器代码,可以发现Unity最终还是把它变成了多Pass的,Cg/HLSL语句依然在Pass语句块内。
从本质来讲,Unity中只存在顶点/片元着色器,表面着色器的固定函数着色器到最后都会转化成顶点/片元着色器。
Unity编辑器会把这些Cg片段编译成低级语言,如汇编语言等。通常Unity会使用不同的编译器把这些Cg片段编译到所有相关平台(Direct3D 9、OpenGL、Direct3D 11、OpenGL ES等)上,这样就不会在切换平台时再重新编译,而且如果代码在某些平台上发生错误就可以立即得到错误信息。
在Unity Shader的Inspector面板可以通过Compile and show code按钮来查看Unity对Cg片段编译后的代码。通过单击Compile and show code按钮右端的倒三角可以打开下拉菜单,在这个下拉菜单中可以选择编译的平台种类,如只为当前的显卡设备编译特定的汇编代码,或为所有的平台编译汇编代码,我们也可以自定义选择编译到哪些平台上。
当发布游戏的时候,游戏数据文件中只包含目标平台所需要的编译代码,不需要的是不会放进去的。
使用GLSL来写UnityShader
GLSL的代码需要嵌套在GLSLPROGRAM和ENDGLSL之间,GLSL的代码仅支持Mac OS X、OpenGL ES 2.0和Linux。