本文永久地址:/article/27.aspx,【文章转载请注明出处!】
Shader "name" { [Properties] Subshaders [Fallback] } 定义了一个着色器。着色器拥有一个 Properties 的列表。着色器包含一个子着色器的列表(SubShaders)。并且至少包含一个(SubShader)。当加载一个着色器时,Unity 将遍历这个列表,获取第一个能被用户机器支持的着色器。如果没有子着色器被支持,Unity
一、着色器文件中的 Properties 块定义了这些参数:
四、Name and tags 名称和标签:一个通道能定义它的 Name 和任意数量的Tags(用于向渲染引擎传递通道的意图的名称/值的字符串)。
五、Render Setup 渲染设置:通道设定显示硬件的各种状态。这些命令如下:
六、Texture Setup 纹理设置:在完成渲染设定后,你能指定一定数量的纹理和当使用 SetTexture 命令时所采用的混合模式:
2、Per-pixel Lighting:每像素光照。每像素光照管线通过多次通道渲染对象来完成。Unity渲染对象一次来获取阴影色和任何顶点光照。然后再在额外的并行通道中渲染出每像素光照的效果。
3、Per-vertex Lighting:每顶点光照。每顶点光照是标准的Direct3D/OpenGL光照模式,通过计算每个顶点的光照来完成。Lighting on命令开启光照。光照被材质块,颜色材质和平行高光命令所影响。
七、有几个特殊的通道能用于反复利用普通功能或是实现几种高端的特效:
1、UsePass:包含来自其他着色器的通道。
2、GrabPass:捕获屏幕到一个纹理,通常使用在靠后的通道中。
八、顶点颜色和灯光(Color, Material, Lighting)是对任何已渲染过后的几何体所添加的第一步效果。这个操作处在顶点级别,用于计算在纹理被应用之前被使用的基础颜色。顶层命令控制是否采用固定函数光照,和一些控制选项,细节如下:
1、Color Color:设定对象的纯色。颜色即可以是括号中的四值(RGBA),也可以是被方框包围的颜色属性名。
3、Lighting On | Off:定义材质块中的设定是否有效,你必须使用 Lighting On 命令开启光照,而颜色则通过 Color 命令直接给出。
4、SeparateSpecular On | Off:这个命令会添加高光光照到着色器通道的末尾,因此贴图对高光没有影响。只在光照开启时有效。
九、Material Block 材质块,包含材质如何和光线产生作用的设定。这些属性都是可以被忽略的,默认为值都被设定为黑色(不产生作用):
十、剔除(Culling)是一种通过避免渲染背对观察者的几何体面来提高性能的优化措施。所有几何体都包含正面和反面。剔除基于大多数对象都是封闭的事实;如果你有一个立方体,你不会看到背离你的那一面(总是只有一面在你的前方),因此我们不需要绘制出背面。因此也被称做背面剔除。另一个使得渲染看起来正确的是深度测试(Depth Testing)。深度测试确保只有场景内的对象的最靠近的表面参与绘制。
1、Cull Back(不绘制背离观察者的几何体面)| Front(不绘制面向观察者的几何体面,用于由内自外的旋转对象) | Off(显示所有面,用于特殊效果):控制几何体的那一面会被剔除(不绘制)
2、ZWrite On | Off:控制是否将来之对象的像素写入深度缓冲(默认开启),如果你正绘制纯色物体,将此项打开。如果你正绘制半透明效果,关闭深度缓冲。
4、Offset Factor , Units:允许你定义用两个参数深度偏移。因子和单位。Factor 缩放Z的最大斜率,几何体的X和Y也一样,units缩放可计算的深度缓冲值。这允许你迫使一个几何体绘制在另一个的上层,尽管他们实际上是在同一个位置。例如偏移0,-1使得靠近摄像机的几何体忽略几何体的斜率,而偏移-1,-1则会几何体在一个几乎擦过的角度被观察使看起来更近些。
十一、纹理(Texturing)在基本的顶点光照被计算后被应用。在着色器中通过 SetTexture 命令来完成。SetTexture 命令在片面程序被使用时不会生效;这种模式下像素操作被完全描述在着色器中。材质贴图可以用来做老风格的混合器效果。你能在一个通道中使用多个SetTexture 命令 - 所有纹理被顺序的应用,如同绘画程序中的层一样。SetTexture 命令必须放置在通道的末尾。
十三、纹理块合并(Combine)命令:
十四、纹理块不变色(ConstantColor)命令:
十五、纹理块矩阵(Matrix)命令:
十六、雾(Fog)参数用于雾命令控制。雾化是通过混合已生成的像素的颜色和基于到镜头的距离来确定的一个不变色来完成。雾化不会改变已经混合的像素的透明度值,只是改变RGB值。
十八、透明度测试(Alpha testing)是阻止像素被写到屏幕的最后机会。 在最终渲染出的颜色被计算出来之后,可选择通过将颜色的透明度值和一个固定值比较。如果比较的结果失败,像素将不会被写到显示输出中。
AlphaValue(一个范围在0到1之间的浮点值。也可以是一个指向浮点属性或是范围属性的索引,在后一种情况下需要使用标准的方括号写法标注索引名字,如([变量名])):设定透明度测试只渲染在某一确定范围内的透明度值的像素。
十九、混合(Blending)被用于制作透明物体。当图像被渲染时,所有着色器被执行以后,所有贴图被应用后,像素将被写到屏幕。通过 Blend 命令控制和已有的图像合并:
二十二、LightMode 标签定义了光照点中的 Pass 任务。可选值如下:
1、Always:总是渲染。没有光照应用。
2、ForwardBase:用于正向渲染,环境主要方向灯和定点光/SH 等的应用。
3、ForwardAdd:用于正向渲染,附加的像素光被应用,每个光照一个 pass。
4、PrepassBase:用于延迟光照,渲染法线/镜面指数。
5、PrepassFinal:用于延迟光照,通过结合纹理,光照和自发光渲染最终颜色。
6、Vertex:用于顶点光照渲染,当物体没有光照映射时,所有顶点光照被应用。
7、VertexLMRGBM:用于顶点光照渲染,当物体有光照映射的时候使用顶点光照渲染。在平台上光照映射是 RGBM 编码。
8、VertexLM:用于顶点光照渲染,当物体有光照映射的时候使用顶点光照渲染。在平台上光照映射是double-LDR 编码(移动平台,及老式台式CPU)。
9、ShadowCaster:将物体当做阴影产生者来渲染。
10、ShadowCollector:为了正向渲染对象的路径,将对象的阴影收集到屏幕空间缓冲区中。
二十三、Name "PassName":为当前通道命名 PassName。一个通道能被赋予一个名字以便UsePass 命令能索引到它。
二十五、Source 可以是下面其中一个:
二十六、Target 可以是下面其中的一个:
本文主要介绍一下如何利用Shader来渲染游戏中的3D角色,以及如何利用Unity提供的Surface Shader来书写自定义Shader。
3、将该Shader赋给一个角色,就可以看到该Shader所能表达出的Diffuse渲染效果。
4、接来我们将以此默认Shader作为蓝本,编写出自定义的Shader。另外,该Shader所用到的参数,我们将在下一章节进行说明。
二、实现多种自定义渲染效果
如果想实现Bump Map效果,可对上述的Shader做如下修改:
1.3 最后修改surf函数,加入对Normal分量的计算:
|
|
这样,角色的材质部分即可变为如下形式(暂定BumpMap的Shader名为“MyShader1”):
(1)首先是title的解释
这种表示表明了该Shader在编辑器中的显示位置,例如我们可在如下地方找到该Shader。
Properties可通过如下语义进行声明:
“name” 是与Shader脚本中对应的名字
“display name”是在材质视图中所显示的名字
这里需要注意的是,如果你在Properties中加入了新的属性,那么你需要在CGPROGRAM中的SubShader中加入同样名字的参数。
(3)接下来是“LOD”语义词的解释。
这里的“LOD”主要是指Shader的LOD程度,即对于超出该范围的物体将不再通过该Shader进行渲染,具体的Shader LOD说明可以参见:
(5)最后,我们在surf函数中获取每个顶点的纹理信息以及法线信息,这些信息将被应用于接下来的Vertex Fragment和Pixel Fragment。
|
Albedo和Alpha分别获取该像素的RGB值和Alpha值,其中“Albedo”是一个漫反射参数,它表示一个表面的漫反射能力,即一个表面上出射光强与入射光强的比值。具体介绍可见:。
如果想实现Blinn-Phong效果,可对上述的Shader做如下修改:
|
|
这里将原有的half4替换为fixed4,这样做是为了提高渲染的性能,因为fixed的精度较之half要低,更高的精度意味着更大的计算量,而这里fixed的精度已经足够,所以使用fixed替代half4,从而来降低计算消耗,增加渲染性能。
|
|
|
|
|
该函数的名称为什么不是“CustomBlinnPhong”呢?这是因为该函数虽然是由“#pragma surface surf CustomBlinnPhong”来调用,但是为了让该函数可以正常工作,我们需要在其名称前加入“Lighting”关键字,这样Unity才能识别出这是一个自定义的光照函数。
通过以上设置,角色的材质部分即可变为如下形式(暂定该Shader名为“MyShader2”):
可以通过对上述Shader做以下改进,来达到这种效果:
|
|
|
|
|
|
|
这里主要是用来计算边缘光照的,首先通过视线与法线的夹角来找到模型的边缘,然后再根据距离的远近来控制发射光的强度。
通过以上设置,角色的材质部分即可变为如下形式(暂定该Shader名为“MyShader3”):
可以看出边缘光照的效果,同时还可以看出明显的明暗变化的卡通渲染效果。
综上所述,本文已经给出了人物的几种基本渲染方法及其Shader实现,在这里我并没有去分析每种渲染效果的原理,而仅是从实际出发,直接给出对应的简单实现方法。如果想要对光照模型进行深入理解,可以Google搜索其原理进行了解。最后,给出各种渲染方法的对比图,显示如下:
编写光照交互的着色器是十分复杂的事情。它们有不同类型的光照,不同的阴影选项,不同的渲染路径(正向渲染和延时渲染),着色器应该以某种合适的方式处理这些的复杂的东西。
Unity3D的表面着色器编写的办法只有通过编写代码产生,这样就使得编写光照着色器比使用低级顶点/像素着色器编程更简单。请注意编写表面着色器没有任何自定义的语言和捷径。它仅仅是通过手动书写来产生一些重复的代码。
你依然可以用CG/HLSL语言来编写它。
这有一些例子,你可以看看:表面着色器 和 自定义照明的表面着色器。
你定义一个“surface function”,将UV或数据作为输入参数,并填充SurfaceOutput作为输出结构体。SurfaceOutput描述了基础的表面属性(光照的颜色反射率、法线、自发光、镜面 等)。你可以用Cg/HLSL编写它。
表面着色器的编译器,指出需要输入什么,在输出中填充什么等等,并产生真实的顶点&像素着色器,并且处理渲染路径为正向渲染或延时渲染。
表面着色器必须放在CGPROGRAM..ENDCG块中,就像其他着色器一样。区别在于:
它必须放在块中,不能放在中。表面着色器将在多个通道内编译自己。
另外,你可以在CGPROGRAM 块中使用#pragma debug指令,然后编译器会产生许多注释的代码。你可以在着色器面板中打开这些已经编译好的着色器中查看它们。
输入结构体Input 包含有着色所需要的纹理坐标。纹理坐标必须在纹理名称后加上"uv"。(或者以"uv2"作为头来命名来使用第二个纹理坐标集)
下列这些附加值 也可放在Input结构中。