作为一款号称跨平台性最好的游戏开发引擎,Unity3D使用Mono这个开源的.NET来实现。对于要适应不同GPU的Shader来说,Unity使用自定义ShaderLab来组织Shader的内容,并将针对不同的平台进行编译。
2.1.1 关键字Shader
Unity的Shader文件是通过Shader这个关键字开始的,用户可以像目录一样组织Shader的命名。Shader的文件名和引用名不必一样,举例如下:
Shader "Tut/NewBie/FirstShader"
Properties{
_MainTex ("Base (RGB)”,2D)="white"{}
}
Subshader{
...}
Subshader{
...}
FallBack "Diffuse"
}
真正用于呈现渲染物体的内容是在SubShader中实现的。之所以用SubShader,是为了能让开发者针对不同性能的显卡编写不同的Shader,因为现实中并不是每个人都用相同的显卡。由于显卡千差万别,为了能让用户编写的游戏最大化地在各种各样的GPU上运行,尽可能地呈现最好的效果,就用SubShader来组织具体的实现,使Unity在运行时会针对实际的运行环境,从上到下选出最优的SubShader实现来呈现开发者的作品。从理论上来说,SubShader的数量是没有限制的,但实际操作中为了减少文件的大小,一般写两只个SubShader就行了,即针对目前最流行的一代显卡写一个,针对老旧的显卡写一个。
2.1.3SubShader的重要标签
给SubShader添加标签(Tags{}块),其实就是一系列指示牌,这些标签可以告诉Unity演染引擎或者其他用户如何认证这个SubShader。下面的代码是适应于SubShader的BuildIn类Tags:
SubShader{
Tags{"Queue"="Geometry""RenderType"="Opaque""IgnoreProjector"="True"}
...
}
Queue就是队列的意思,在这里就是渲染队列的意思,表示希望Unity渲染引擎在什么时候渲染自己。Queue有5个可选值,它们是Background、Geometry、 AIphaTest、Transparent和Overlay,分别对应数字1000, 2000, 2450, 3000和4000。既然可以对应成数字,当然也可以把这些单词当作整型变量来看待,例如:
Tags{"Queue"="Geometry+1314”}
当你混合使用自定义的Shader和Unity的内置Shader时,一定要尊重上面的单词和字母的对应关系,因为Unity的内置Shader就是按照这个顺序来渲染的。
Tags{"MyTag"="Lucifer"}
2.1.4SubShader中的Pass块
SubShader包装了一个渲染方案,而这个方案是由一个个Pass块来执行的。SubShader可以包括多个Pass块,每一个Pass块都包含了渲染一个几何体的具体代码。我们如果写Shader,大部分费神费力且能体现每位读者的劳动价值的地方就在Pass块中。
2.1.5 Pass块的标签及其名字的意义
Pass块内置的那些标签都是针对渲染路径的,告诉渲染引擎这个Pass应该在什么渲染路径下被渲染,这个内容会在后面相应的章节一一讲到。
Pass块的Name一般用来引用此Pass。这种引用意味着你可以定义一个Pass块,然后在其他Shader的Pass块中多次引用它。这是一种减少重复劳动的技巧。下面是这种技巧的一个演示:
Shader "Tut/NewBie/SecondShader"{
SubShader{
Pass{
Name ”HYC“
Material{
Diffuse(1, 0.7,0.4,1)
Ambient(1,0.7, 0.9,1)
}
Lighting On
SetTexture[ _ ] {combine primary}
}
}
}
这个Shader命名了一个Pass块,由于Unity的原因,命名时必须使用大写。下面这个Shader则通过这个名字引用了此Pass块:
Shader "Tut/NewBie/ThirdShader"{
SubShader{
UsePass "Tut/NewBie/SecondShader/HYC"
}
}
2.1.6 使用FaIIBack保证Shader的广泛适应性
如果用户所有的SubShader都失败了,为了在用户的计算机上呈现设定的机制,一般会使用FallBack。 FallBack是Unity自己预制的Shader实现,一般能够在所有显卡上运行。我们在开发Shader的时候一般不使用FallBack,只有在实际发布时才会为了追求平台的最大适用性而加上。