Unity3d 着色器语法(Shader)
在Unity3D中,着色器是实现各种渲染效果的核心,它通过特定的语法结构来定义物体在场景中的外观。下面将详细介绍Unity3D着色器的语法结构和各个部分的作用。
着色器的基本结构
一个着色器的基本定义格式为:Shader "name" { [Properties] Subshaders [Fallback] }。
- Properties:这是一个参数列表,用于定义着色器中可调节的参数。
- Subshaders:子着色器列表,着色器至少包含一个子着色器。当加载着色器时,Unity会遍历这个列表,选择第一个能被用户机器支持的子着色器。
- Fallback:如果没有子着色器被支持,Unity将尝试使用降级着色器。
Properties 块
着色器文件中的 Properties 块用于定义各种参数,具体如下:
name ("display name", Range (min, max)) = number:定义浮点数范围属性。name ("display name", Color) = (number,number,number,number):定义颜色属性。name ("display name", 2D) = "name" { options }:定义2D纹理属性。name ("display name", Rect) = "name" { options }:定义长方形(非2次方)纹理属性。name ("display name", Cube) = "name" { options }:定义立方贴图纹理属性。name ("display name", Float) = number:定义浮点数属性。name ("display name", Vector) = (number,number,number,number):定义一个四元素的容器(Vector4)属性。
子着色器(Subshader)
子着色器的结构为:Subshader { [Tags] [CommonState] Passdef [Passdef ...] },它由可选标签、通用状态和一个Pass定义的列表构成。
通道(Pass)
基本通道命令的结构为:Pass { [Name and Tags] [RenderSetup] [TextureSetup] },包含一个可选的渲染设置命令列表和可选的被使用的纹理列表。
名称和标签(Name and tags)
一个通道可以定义它的名称(Name)和任意数量的标签(Tags),标签是用于向渲染引擎传递通道意图的名称/值字符串。
渲染设置(Render Setup)
通道通过以下命令来设定显示硬件的各种状态:
Material { Material Block }:定义一个使用顶点光照管线的材质。Lighting On | Off:开启或关闭顶点光照。Cull Back | Front | Off:设置多边形剔除模式。ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always):设置深度测试模式。ZWrite On | Off:设置深度写模式。Fog { Fog Block }:设置雾参数。AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always) CutoffValue:开启 alpha 测试。Blend SourceBlendMode DestBlendMode:设置 alpha 混合模式。Color Color value:设置当顶点光照关闭时所使用的颜色。ColorMask RGB | A | 0 | any combination of R, G, B, A:设置颜色写遮罩。设置为0将关闭所有颜色通道的渲染。Offset OffsetFactor , OffsetUnits:设置深度偏移。SeparateSpecular On | Off:开启或关闭顶点光照相关的平行高光颜色。ColorMaterial AmbientAndDiffuse | Emission:当计算顶点光照时使用每顶点颜色。
纹理设置(Texture Setup)
在完成渲染设定后,可以指定一定数量的纹理和使用 SetTexture 命令时所采用的混合模式:
SetTexture texture property { [Combine options] }:纹理设置配置了固定函数多纹理管线,当自定义 fragment shaders 被使用时,将忽略这个设置。- Per - pixel Lighting(每像素光照):每像素光照管线通过多次通道渲染对象来完成。Unity 先渲染对象一次来获取阴影色和任何顶点光照,然后在额外的并行通道中渲染出每像素光照的效果。
- Per - vertex Lighting(每顶点光照):每顶点光照是标准的 Direct3D/OpenGL 光照模式,通过计算每个顶点的光照来完成。使用
Lighting on命令开启光照,光照会受到材质块、颜色材质和平行高光命令的影响。
特殊通道
有几个特殊的通道可用于反复利用普通功能或实现高端特效:
UsePass:包含来自其他着色器的通道。GrabPass:捕获屏幕到一个纹理,通常在靠后的通道中使用。
顶点颜色和灯光(Color, Material, Lighting)
顶点颜色和灯光是对任何已渲染过后的几何体添加的第一步效果,该操作处于顶点级别,用于计算在纹理被应用之前的基础颜色。相关命令及细节如下:
Color Color:设定对象的纯色。颜色可以是括号中的四值(RGBA),也可以是被方框包围的颜色属性名。Material { Material Block }:材质块用于定义对象的材质属性。Lighting On | Off:定义材质块中的设定是否有效,必须使用Lighting On命令开启光照,而颜色则通过Color命令直接给出。SeparateSpecular On | Off:该命令会在着色器通道的末尾添加高光光照,因此贴图对高光没有影响,只在光照开启时有效。ColorMaterial AmbientAndDiffuse | Emission:使用每顶点的颜色替代材质中的颜色集。AmbientAndDiffuse替代材质的阴影光和漫反射值;Emission替代材质中的光发射值。
材质块(Material Block)
材质块包含材质如何与光线产生作用的设定,这些属性可以被忽略,默认值都被设定为黑色(不产生作用):
Diffuse Color:漫反射颜色构成,是对象的基本颜色。Ambient Color:环境色颜色构成,是当对象被RenderSettings中设定的环境色所照射时对象所表现的颜色。Specular Color:对象反射高光的颜色。Shininess Number:加亮时的光泽度,取值范围在0和1之间。值为0时,较大的高亮看起来像漫反射光照;值为1时,会获得一个细微的亮斑。Emission Color:自发光颜色,即当对象不被任何光照所照到时的颜色。- 最终的计算效果:
Ambient * RenderSettings ambient setting + (Light Color * Diffuse + Light Color * Specular) + Emission。
剔除(Culling)和深度测试(Depth Testing)
剔除是一种通过避免渲染背对观察者的几何体面来提高性能的优化措施。所有几何体都有正面和反面,由于大多数对象是封闭的,如立方体,我们通常看不到背离我们的那一面,因此不需要绘制背面,这也被称为背面剔除。深度测试确保只有场景内对象的最靠近的表面参与绘制。
Cull Back(不绘制背离观察者的几何体面)| Front(不绘制面向观察者的几何体面,用于由内自外的旋转对象) | Off(显示所有面,用于特殊效果):控制几何体的哪一面会被剔除(不绘制)。ZWrite On | Off:控制是否将来自对象的像素写入深度缓冲(默认开启)。绘制纯色物体时,应打开此项;绘制半透明效果时,关闭深度缓冲。ZTest Less | Greater | LEqual | GEqual | Equal | NotEqual | Always:深度测试的执行方式。缺省值是LEqual(绘制和存在的对象一致或是在其中的对象;隐藏它们背后的对象)。Offset Factor , Units:允许通过两个参数定义深度偏移,即因子和单位。Factor缩放Z的最大斜率,几何体的X和Y也一样;units缩放可计算的深度缓冲值。这允许迫使一个几何体绘制在另一个的上层,即使它们实际上在同一个位置。例如,偏移0, -1使得靠近摄像机的几何体忽略几何体的斜率,而偏移-1, -1则会使几何体在一个几乎擦过的角度被观察时看起来更近些。
纹理(Texturing)
纹理在基本的顶点光照计算后被应用,在着色器中通过 SetTexture 命令完成。当片面程序被使用时,SetTexture 命令不会生效,因为这种模式下像素操作被完全描述在着色器中。材质贴图可以实现老风格的混合器效果,一个通道中可以使用多个 SetTexture 命令,所有纹理将按顺序应用,就像绘画程序中的层一样。SetTexture 命令必须放置在通道的末尾。
SetTexture 命令
SetTexture [TexturePropertyName] { Texture Block }:分配一个纹理,TextureName 必须定义为一个纹理属性。纹理块控制纹理的应用方式,其中可以执行三种命令:合并、矩阵和不变色。
纹理块合并(Combine)命令
combine src1 * src2:将源1和源2的元素相乘,结果会比单独输出任何一个都要暗。combine src1 + src2:将源1和源2的元素相加,结果会比单独输出任何一个都要亮。combine src1 - src2:源1减去源2。combine src1 +- src2:先相加,然后减去0.5(添加了一个符号)。combine src1 lerp (src2) src3:使用源2的透明度通道值在源3和源1中进行差值,注意差值是反向的:当透明度值为1时使用源1,透明度为0时使用源3。combine src1 * src2 + src3:源1和源2的透明度相乘,然后加上源3。combine src1 * src2 +- src3:源1和源2的透明度相乘,然后和源3做符号加。combine src1 * src2 - src3:源1和源2的透明度相乘,然后和源3相减。
所有源属性可以是 Previous(上一次 SetTexture 的结果)、Constant(被 ConstantColor 定义的颜色)、Primary(来自光照计算的颜色或是当它绑定时的顶点颜色)、Texture(在 SetTexture 中被定义的纹理的颜色)其中之一。
纹理块不变色(ConstantColor)命令
ConstantColor color:定义在 combine 命令中能被使用的不变颜色。
纹理块矩阵(Matrix)命令
matrix [MatrixPropertyName]:使用给定矩阵变换纹理坐标。
雾(Fog)
雾参数用于雾命令控制,雾化通过混合已生成的像素的颜色和基于到镜头的距离确定的一个不变色来完成。雾化不会改变已经混合的像素的透明度值,只会改变RGB值。
雾命令
Fog { Fog Commands }:在大括号中设定雾命令的内容。
Mode Off | Global | Linear | Exp | Exp2:定义雾模式。缺省是全局的,依据雾在渲染设定中是否打开,可从无变化到平方值。Color ColorValue:设定雾的颜色。Density FloatValue:以指数的方式设定雾的密度。Range FloatValue , FloatValue:为线性的雾设定远近距离。
透明度测试(Alpha testing)
透明度测试是阻止像素被写到屏幕的最后机会。在最终渲染出的颜色计算出来之后,可以选择将颜色的透明度值与一个固定值比较。如果比较结果失败,像素将不会被写到显示输出中。
AlphaTest Off:渲染所有像素(缺省)。AlphaTest Greater(大于)| GEqual(大于等于)| Less(小于)| LEqual(小于等于)| Equal(等于)| NotEqual(不等于)| Always(渲染所有像素)| Never(不渲染任何像素) AlphaValue:AlphaValue是一个范围在0到1之间的浮点值,也可以是一个指向浮点属性或是范围属性的索引,在后一种情况下需要使用标准的方括号写法标注索引名字,如([变量名])。该命令用于设定透明度测试,只渲染在某一确定范围内的透明度值的像素。
混合(Blending)
混合用于制作透明物体。当图像被渲染时,所有着色器执行完毕、所有贴图应用后,像素将被写到屏幕。通过 Blend 命令控制像素与已有的图像合并:
Blend Off:关闭混合。Blend SrcFactor DstFactor:配置并启动混合。产生的颜色乘以SrcFactor,已存在于屏幕的颜色乘以DstFactor,然后两者叠加在一起。Blend SrcFactor DstFactor, SrcFactorA DstFactorA:同上,但使用不同的要素来混合 alpha 通道。BlendOp Min | Max | Sub | RevSub:不将混合颜色相加,而是对它们进行不同的操作。
混合因子
以下属性对 SrcFactor 或 DstFactor 都可用,Source 指的是被计算的颜色,Destination 是已经在屏幕上的颜色。
One:值为1,使用此设置可让源(Source)或目标颜色(Destination)完全通过。Zero:值为0,使用此设置可删除源(Source)或目标值(Destination)。SrcColor:此阶段的值乘以源颜色(Source)的值。SrcAlpha:此阶段的值乘以源(Source)alpha 的值。DstColor:此阶段的值乘以帧缓冲区源颜色(Source)的值。DstAlpha:此阶段的值乘以帧缓冲区源(Source)alpha 的值。OneMinusSrcColor:此阶段的值乘以(1 - 源颜色(Source))。OneMinusSrcAlpha:此阶段的值乘以(1 - 源(Source)alpha)。OneMinusDstColor:此阶段的值乘以(1 - 目标颜色(Destination))。OneMinusDstAlpha:此阶段的值乘以(1 - 目标(Destination)alpha)。
标签(Tags)
Tags { "TagName1" = "Value1" "TagName2" = "Value2" }:指定 TagName1 的值为 Value1,TagName2 的值为 Value2,可以指定任意数量的标签。通过使用标签(Pass Tags),可以告诉渲染引擎在何时以及如何渲染所期望的效果。
LightMode 标签
LightMode 标签定义了光照点中的 Pass 任务,可选值如下:
Always:总是渲染,没有光照应用。ForwardBase:用于正向渲染,应用环境主要方向灯和定点光/SH 等。ForwardAdd:用于正向渲染,附加的像素光被应用,每个光照一个 pass。PrepassBase:用于延迟光照,渲染法线/镜面指数。PrepassFinal:用于延迟光照,通过结合纹理、光照和自发光渲染最终颜色。Vertex:用于顶点光照渲染,当物体没有光照映射时,应用所有顶点光照。VertexLMRGBM:用于顶点光照渲染,当物体有光照映射且在平台上光照映射是 RGBM 编码时使用。VertexLM:用于顶点光照渲染,当物体有光照映射且在平台上光照映射是 double - LDR 编码(移动平台及老式台式 CPU)时使用。ShadowCaster:将物体当作阴影产生者来渲染。ShadowCollector:为了正向渲染对象的路径,将对象的阴影收集到屏幕空间缓冲区中。
通道命名(Name)
Name "PassName":为当前通道命名为 PassName,以便 UsePass 命令能索引到它。
顶点数据映射(BindChannels)
BindChannels { Bind "source", target }:允许指定顶点数据如何映射到显卡中。
Source 可选值
Vertex:顶点的位置。Normal:顶点的法线。Tangent:顶点的切线。Texcoord:主要的 UV 坐标。Texcoord1:次要的 UV 坐标。Color:每个顶点颜色。
Target 可选值
Vertex:顶点的位置。Normal:顶点的法线。Tangent:顶点的切线。Texcoord0, Texcoord1, ...:各个纹理处理阶段的纹理坐标。Texcoord:所有纹理处理阶段的纹理坐标。Color:顶点颜色。