Shader的Properties段中定义外,还需要在Cg中声明方可使用。例如上面表面着色器的例子中我们定义了_MainTex这个类型为2D的属性,还需要在Cg中声明 sampler2D _MainTex。
? ?
全局变量:Shader有一组SetGlobalXXX方法,可以对Shader的在Cg中定义而没有在属性中定义的uniform变量进行设置。这个设置是全局的,所有定义了该uniform的Shader都会受到影响。例如我们希望场景随着时间变化而改变颜色,就可以给场景所使用到的Shader设置统一的全局颜色变量,然后在脚本中通过设置该颜色来改变场景的颜色。在角色释放技能时场景变黑也可以使用这个方法。
?
Unity shader 中允许定义的属性类型有:
关键字 类型 对应Cg类型 例
Float 浮点数 float _MyFloat (“My float”, Float) = 0.5
Range 浮点数 (在指定范围内) float _MyRange (“My Range”, Range(0.01, 0.5)) = 0.1
Color 浮点四元组 float4 _MyColor (“Some Color”, Color) = (1,1,1,1)
Vector 浮点四元组 float4 _MyVector(“Some Vector”,Vector) = (1,1,1,1)
2D 2的阶数大小的贴图 sampler2D _MyTexture (“Texture”, 2D) = “white” {}
Rect 非2的阶数大小的贴图 sampler2D _MyRect(“My Rect”, Rect) = “white” {}
CUBE CubeMap samplerCUBE _MyCubemap (“Cubemap”, CUBE) = “” {}
注:CubeMap 是6张有联系的2D贴图的组合主要用来做反射效果(比如天空盒和动态反射)
SubShader
SubShader中除了Pass,有两个标签值得关注:LOD和Tags
LOD
LOD是 Level of Detail的简写,确切地说是Shader Level of Detail的简写,因为Unity中还有一个模型的LOD概念,这是两个不同的东西。我们这里只介绍Shader中LOD,模型的LOD请参考这里。
Shader LOD 就是让我们设置一个数值,这个数值决定了我们能用什么样的Shader。可以通过Shader.maximumLOD或者Shader.globalMaximumLOD 设定允许的最大LOD,当设定的LOD小于SubShader所指定的LOD时,这个SubShader将不可用。通过LOD,我们就可以为某个材质写一组SubShader,指定不同的LOD,LOD越大则渲染效果越好,当然对硬件的要求也可能越高,然后根据不同的终端硬件配置来设置 globalMaximumLOD来达到兼顾性能的最佳显示效果。
Unity内建Shader定义了一组LOD的数值,我们在实现自己的Shader的时候可以将其作为参考来设定自己的LOD数值
? ? ? ?
VertexLit及其系列 = 100 Decal, Reflective VertexLit = 150 Diffuse = 200
Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
? ? ? ?
Bumped, Specular = 300 Bumped Specular = 400 Parallax = 500
Parallax Specular = 600
Tag
SubShader可以被若干的标签(tags)所修饰,而硬件将通过判定这些标签来决定什么时候调用该着色器。 比较常见的标签有:
?
Queue
这个标签很重要,它定义了一个整数,决定了Shader的渲染的次序,数字越小就越早被渲染,早渲染就意味着可能被后面渲染的东西覆盖掉看不见。 预定义的Queue有:
名字
值
描述
Background 1000 最早被调用的渲染,用来渲染天空盒或者背景
Geometry 2000 这是默认值,用来渲染非透明物体(普通情况下,场景中的绝大多数物体应该是非透明
的)
AlphaTest 2450 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的
考虑
Transparent 3000 以从后往前的顺序渲染透明物体
Overlay 4000 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效)
? RenderType
“Opaque”或”Transparent”是两个常用的RenderType。如果输出中都是非透明物体,那写在Opaque里;如果想渲染透明或者半透明的像素,那应该写在Transparent中。这个Tag主要用ShaderReplacement,一般情况下这Tag好像也没什么作用。
CommonState
SubShader中可以定义一组Render State,基本上就是一些渲染的开关选项,他们对该SubShader的所有的Pass都有效,所以称Common。这些Render State也可以在每个Pass中分别定义,将在Pass中详细介绍。
Pass
Render State
Render State主要就是控制渲染过程的一些开关选项,例如是否开启alpha blending ,是否开启depth testing。 常用的Render State有:
?
Cull
用法:Cull Back | Front | Off
多边形表面剔除开关。Back表示背面剔除,Front表示正面剔除,Off表示关闭表面剔除即双面渲染。有时候如裙摆,飘带之类很薄的东西在建模时会做成一个面片,这就需要设置Cull Off来双面渲染,否则背面会是黑色。
? ?
ZWrite
用法:ZWrite On | Off
控制当前对象的像素是否写入深度缓冲区(depth buffer),默认是开启的。一般来说绘制不透明物体的话ZWrite开启,绘制透明或半透明物体则ZWrite关闭。
深度缓冲区:当图形处理卡渲染物体的时候,每一个所生成的像素的深度(即 z 坐标)就保存在一个缓冲区中。这个缓冲区叫作 z 缓冲区或者深度缓冲区,这个缓冲区通常组织成一个保存每个屏幕像素深度的 x-y 二维数组。如果场景中的另外一个物体也在同一个像素生成渲染结果,那么图形处理卡就会比较二者的深度,并且保留距离观察者较近的物体。然后这个所保留的物体点深度保存到深度缓冲区中。最后,图形卡就可以根据深度缓冲区正确地生成通常的深度感知效果:较近的物体遮挡较远的物体。
理解了深度缓冲区也就理解了为什么绘制透明或半透明物体需要关闭ZWrite, 如果不关闭,透明物体的depth也会被写入深度缓冲区,从而会剔除掉它后面的物体,后面的物体就不会被渲染,看不见后面的物体还能叫透明吗?因此我们使用Alpha blending的时候需要设置ZWrite Off。
? ?
ZTest
用法:ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)
控制如何进行深度测试,也就是上面说的图形处理卡比较二者的深度的比较方法。默认是LEqual。
值得一提的是使用Aplha blending的时候ZWrite需要关闭但是ZTest是要开启的,因为如果透明物体前面还有不透明物体,透明物体还是应该被遮挡剔除的。
? ?