Blend
混合。控制了每个Shader的输出如何和屏幕上已有的颜色混合。 用法:
Blend Off: 关闭混合
Blend SrcFactor DstFactor:最终颜色 = Shader产生的颜色 × SrcFactor + 屏幕上原来的颜色 × DstFactor
Blend SrcFactor DstFactor, SrcFactorA DstFactor:和上面一样,只是Alpha通道使用后面两个参数计算 常用的Blend模式有:
Blend SrcAlpha OneMinusSrcAlpha // Alpha blending Blend One One // Additive
Blend OneMinusDstColor One // Soft Additive Blend DstColor Zero // Multiplicative Blend DstColor SrcColor // 2x Multiplicative 具体参考这里
?
Unity5开始下列固定功能的Shader命令被标记为过时了,这些命令的功能现在建议在Shader(Cg)中通过代码来实现,这里列出是为了方便阅读以前写的Shader:
? ? ? ?
Lighting On | Off
Material { Material Block } SeparateSpecular On | Off Color Color-value
? ? ?
ColorMaterial AmbientAndDiffuse | Emission Fog { Fog Block }
AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)
CutoffValue
? SetTexture textureProperty { combine options }
Surface Shader
Surface Shader 隐藏了很多光照处理的细节,它的设计初衷是为了让用户仅仅使用一些指令(#pragma)就可以完成很多事情,并且封装了很多常用的光照模型和函数。相比底层的Vertex And Fragment Shader,Suface Shader的限制比较多,它只能有一次Pass。如果做一些常规的功能又需要光照,可以用Surface Shader写,比较快速便捷。如果要写比较高级的Shader还是建议使用Vertex Shader 和 Fragment Shader。
Surface Shader主要有两部分组成,一个是#pragma后面的指令,一个是surf函数。 pragma的语法是 #pragma surface surfaceFunction lightModel [optionalparams] - surfaceFunction 通常就是名为surf的函数, 函数名可以自己取 surf函数原型是:void surf (Input IN, inout SurfaceOutput o)
- lightModel是Unity内置的光照模型,可以是Lambert,Blinn-Phong等。 - optionalparams: 包含很多指令 详细参数参考这里
surf函数主要有一个Input结构的输入和SurfaceOutput结构的输出。
Input
Input 结构需要在Shader中定义。它可以包含如下字段, 如果你定义了这些字段就可以在surf函数中使用它们(好神奇的黑科技)
? ?
多个贴图的uv坐标,名字必须符合格式uv+贴图名。例如 float2 uv_MainTex float3 viewDir - 视图方向( view direction)值。为了计算视差效果(Parallax
effects),边缘光照(rim lighting)等,需要包含视图方向( view direction)值。
? ?
float4 with COLOR semantic - 每个顶点(per-vertex)颜色的插值。
float4 screenPos - 屏幕空间中的位置。 为了反射效果,需要包含屏幕空间中的位
置信息。比如在Dark Unity中所使用的 WetStreet着色器。
? ?
float3 worldPos - 世界空间中的位置。
float3 worldRefl - 世界空间中的反射向量。如果表面着色器(surface shader)不写
入法线(o.Normal)参数,将包含这个参数。 请参考这个例子:Reflect-Diffuse 着色器。
? float3 worldNormal - 世界空间中的法线向量(normal vector)。如果表面着色器
(surface shader)不写入法线(o.Normal)参数,将包含这个参数。
? float3 worldRefl; INTERNAL_DATA - 世界空间中的反射向量。如果表面着色器
(surface shader)不写入法线(o.Normal)参数,将包含这个参数。
? float3 worldNormal; INTERNAL_DATA -世界空间中的法线向量(normal
vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。
SurfaceOutput
SurfaceOutput 描述了表面的特性(光照的颜色反射率、法线、散射、镜面等),这个结构是固定的,不需要在Shader中再定义。
struct SurfaceOutput { half3 Albedo; //反射率,一般就是在光照之前的原始颜色 half3 Normal; //法线 half3 Emission; //自发光,用于增强物体自身的亮度,使之看起来好像可以自己发光 half Specular; //镜面 half Gloss; //光泽 half Alpha; //透明 }; Unity5 由于引入了基于物理的光照模型,所以新增加了两个Output
struct SurfaceOutputStandard { fixed3 Albedo; // base (diffuse or specular) color fixed3 Normal; // tangent space normal, if written half3 Emission; half Metallic; //0=non-metal, 1=metal half Smoothness; //0=rough, 1=smooth half Occlusion; // occlusion (default 1) fixed Alpha; // alpha for transparencies }; struct SurfaceOutputStandardSpecular { fixed3 Albedo; // diffuse color fixed3 Specular; // specular color fixed3 Normal; // tangent space normal, if written half3 Emission; half Smoothness; //0=rough, 1=smooth half Occlusion; // occlusion (default 1) fixed Alpha; // alpha for transparencies }; Unity提供了一些基本的SurfaceShader的例子,有助于我们理解输入输出是如何被使用的。
Unity提供的SurfaceShader的例子
Vertex Shader
如果不想使用Surface Shader而直接编写opengl和Direct3D中常见的顶点着色器和片段着色器,可以通过Cg代码段嵌入到Pass中:
Pass { // ... the usual pass state setup ... CGPROGRAM
// compilation directives for this snippet, e.g.: #pragma vertex vert #pragma fragment frag // the Cg/HLSL code itself ENDCG
// ... the rest of pass setup ... }
其中vert就是顶点着色器函数,frag就是片段着色器函数。一般来说,可以在顶点着色器中进行的计算就不应该放到片段着色器中去算,因为顶点着色器是逐顶点计算的而片段着色器是逐像素计算的,一个模型顶点总比表明像素少很多吧。
编写顶点和片段着色器一般需要包含Unity预定义的一个帮助文件UnityCG.cginc,里面预定义了一些常用的结构和方法。Windows版Unity这个文件位于({unity install
path}/Data/CGIncludes/UnityCG.cginc。 Mac版位于
/Applications/Unity/Unity.app/Contents/CGIncludes/UnityCG.cginc。
在代码中我们只需要添加 #include \就可以使用里面的结构和方法。
Input
顶点着色器的原型是 v2f vert (appdata v)
appdata 是输入,可以自己定义也可以使用Unity预定义的。Unity在UnityCG.cginc预定义了三种常用的输入结构:appdata_base,appdata_tan,appdata_full。
struct appdata_base { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct appdata_tan { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };