像素的颜色还没有计算出来。这意味着你可以再次之前传入顶点的法向量来影响光照的计算。
片段着色器(Fragment Shader)有着同样的工作流程,但事实上,片段着色器中必须有Vertex Function(上图中的Vertex Function部分就是可选的(Optional)),而且需要在像素处理阶段做很多的工作才能产生最终的像素。而表面着色器隐藏了这些。(译者注:给我的感觉就是片段着色器向用户提供了更多的接口进行更高级的渲染)。 下图展示了你的代码如何被调用以及代码构成
从上图我们可以看到,当你写一个shader的时候,你可能得有一些属性值(properties),并且有一个或多个Subshaders。具体使用哪个Subshader进行处理取决于你的运行平台。你应该还要指定一个Fallback shader,当你的subshader没有一个能运行在你的目标设备上,将使用Fallback shader(译者注:有点像备胎)。
每个Subshader都至少有一个通道(pass)作为数据的输入和输出。你可以使用多个通道(passes)执行不同的操作,比如在一个Grab Pass中,你可以获取将要呈现到屏幕上的像素值(译者注:类似于glsl中的fragment buffer)。当你想制作高级的扭曲效果,这非常有用。虽然当你开始学习shader编程时,你可能并不会使用到它。另外一个使用多通
道(multiple passes)的原因是在不同时刻,你可能需要写入或者禁止写入深度缓存的使用。
当你写表面着色器时,我们将直接在Subshader这个层次上写代码,系统将把我们的代码编译成若干个合适的通道(pass)。
尽管shader最终产生的是二维像素,但是其实这些像素除了保存xy坐标外,本身保存着深度值(即每个像素点上的内容在原先3D场景中离照相机的远近),这样距离照相机近的物体就会把距离照相机远的物体遮挡住,在屏幕上显示时,就是将其像素值覆盖。
你可以控制是否在你的shader中使用深度缓存(Z-buffer)产生一些特效,或者在Pass中使用一些指令决定shader是否可以写入Z-buffer:比如使用ZWrite Off时,任何你输出的东西都不会更新Z-buffer的值,即关闭的Z-Buffer的写入功能。
你可以使用Z-buffer技术在别的物体上掏出一个洞,你可以先写入需要打洞区域的深度值,但不输出打洞区域所属的像素值,然后在你模型后面的物体的深度值将无法写入(因为Z-buffer觉得你的模型已经挡住了后面的物体)(译者注:这样你打洞区域显示的就是一开始使用的背景色,会造成一个洞穿过了这些物体的效果)。 下面是一些shader代码:
希望你能看出上面代码是由Properties,SubShader,Fallback三段代码组成的。 理解Shader代码
文章剩下的部分将讲述上面那段简单代码到底做了什么?真正的干货马上就来了,你必须好好掌握这些内容。 当你进行shader编程时,你必须使用正确的变量名和函数名来调用它们,事实上变量的名称在某些情况下能让人一眼看出它的特定含义。 创建并使用默认Shader
(译者注:在详细介绍Shader之前,我们先简单介绍下shader如何使用。)
1. 我们先打开Unity(我的版本是4.6.1),创建新工程,并在Assets文件夹下创建三个目录,如下:
2. 我们再创建一个cube。
可以在Inspector面板看到新创建的cube所使用的Material如下。
3. 打开Material文件夹,我们在其中创建一个Shader和一个Material。
此时New Material的默认Shader为Diffuse。
我们将NewShader拖到New Material上。
可以看到该材质所使用的Shader变成我们新建的NewShader了。当然你也可以直接点击材质编辑器中Shader下拉框,选择相应的Shader。
4. 最后将New Material拖到cube上。可以看到cube所使用的材质和Shader都变成了我们新创建的材质和Shader了。
Properties(属性值)简介
你在shader代码中的Properties{…}部分定义Shader中的属性值(属性值就是用户传入给shader的数据,比如纹理之类的,然后shader处理这些纹理,产生特效。可以理解为属性值相当于一种全局变量,而Shader就是那个主函数,Unity的优势在于给这个全局变量赋值可以在Inspector面板进行)。注意Properties(属性值)是所有Subshader代码中的共享的,意味着所有SubShader代码中都可以使用这些属性值。
属性值(property)定义的形式:
_Name(“Displayed Name”,type) = default value[{options}]
_Name 属性值的名称,是在shader代码内部使用的,区别于下面的Displayed Name,后者是在Inspector 面板上显示的,作为外界(用户)的输入提示。
Displayed Name 呈现在材质编辑器中的属性值名称,在Inspector面板上显示。
总结:打开我们创建的NewShader。可以看到_MainTex是在代码中使用的,而Base (RGB)是在材质编辑器中使用的
type 属性值的类型,包括:
Color – 表示纯色,使用了RGBA表示法
2D – 代表尺寸为2的幂次的纹理(如2,4,8,16…256,512) Rect – 代表纹理(texture),不同于上面的纹理,此处纹理的大小不一定是2的幂次。
Cube – 用于3d中的cube map,经常提到的天空盒就是使用了cube map。
Range(min, max) – 在min和max之间的一个值,在面板中可用滑动条改变其值大小。