Shader即着色器,是一中运行在GPU上的程序,用来对三维物体进行着色处理,光与影的计算,纹理颜色的呈现等,从而将游戏引擎中一个个作为抽象的几何数据存在的模型,场景和特效,以和真实世界类似的光与影的形式呈现于玩家的眼中。通过Shader可以改变物体的形状,大小,位置,旋转等,甚至可以做PS的功能效果。伴随着GPU硬件性能的提升,shader编程方式经历了从最初的固定管线,到可编程流水线的发展。Shader有顶点Shader和片段Shader两个基本类型,顶点Shader有着可以处理,变换最终会渲染到屏幕上的网格物体的顶点位置的功能,但是不可以生成新的顶点。Shader作为一款在GPU上运行上的程序,目前有三种高级图形语言可供选择:HLSL,GLSL,CG。Unity对shader编程语言支持的重点是CG。
Unity中的Shader:
以关键字shader开始,在Unity中新建一个Shader默认如下
Shader "Custom/NewShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
真正用于呈现渲染物体的内容是在SubShader中实现的,不同的显卡使用不同的SubShader,SubShader数量不限,不过最好只有两三个。SubShader中添加标签,可以告诉Unity渲染引擎或者其他用户如何认证这个SubShader。
Tags{"Queue"="Geometry""RenderType"="Opaque""IgnoreProjector"="True" }
Queue表示渲染队列,希望渲染引擎在什么时候渲染自己。Queue有5个可选值,它们是Background,Geometry,AlphaTest,Transparent,Overlay,分别对应数字1000,2000,2450,3000,4000。所以也可以表示
Tags{"Queue"="Geometry+1314"}
Unity内置Shader按照上面顺序渲染,下一个RenderType标签,内置值有Opaque,Transparent,TransparentCutout,Background和Overlay。IgnoreProjector值为TRUE,表示当前物体忽略Projector的影响。在做代替渲染时候也可以添加自定义标签。
SubShader包装了一个渲染方案,这个方案是由一个个Pass块来执行的。
往上面代码添加一个SubShader
SubShader{
Pass {
Name "MYM"
Material{
Diffuse(1,0.7,0.4,1)
Ambient(1,0.7,0.4,1)
}
Lighting On
SetTexture[_]{combine primary}
}
}
使用这个新加的Pass
Shader "Custom/NewShader1" {
SubShader {
UsePass "Custom/NewShader/MYM"
}
}
如果所有的SubShader都失败了,一般会使用Unity预制的Shader实现,使用FallBack。
在Unity的ShaderLab所提供的结构中,既可以用GLSL来写Shader的逻辑代码,也可以用Cg/HLSL,如果使用Cg,那么代码必须位于CGPROGRAM和ENDCG之间。
Unity中Shader的三种形态
1.固定管线在老一代GPU能力有限,对Shader的约束性比较高的一种形态,未来会逐步淘汰,下面是固定管线的代码例子:
固定管线的相关代码都必须处于一个Pass
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Color ("Main Color",Color) =(1,1,1,0.5)
_SpecColor("Spec Color",Color) = (1,1,1,1);
_Emission("Emmisie Color",Color)=(0,0,0,0);
_Shininess("Shininess",Range(0.01,1))=0.7;
SubShader {
Pass {
Material {
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
Specular [_SpecColor]
Emission [_Emission]
}
Lighting On
SeparateSpecular On
SetTexture [_MainTex] {
ConstantColor [_Color]
Combine texture * primary DOUBLE,texture * ConstantColor
}
}
}
2.可编程Shader 顶点+片段着色器
Properties {
_MyTexture("Texture (RGB)",2D) = "white"{}
_MyColor("Color of object",Color) =(1,1,1,1)
SubShader {
Tags{"Queue"="Geometry""RenderType"="Opaque""IgnoreProjector"="True"}
Pass {
CGPROGRAM
#pragma Vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MyColor;
struct v2f{
float4 pos::SV_POSITION;
};
v2f vert(appdata_full v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.Vertex);
return o;
}
float4 frag(v2f i)
{
return float4(i);
}
ENDCG
}
}
FallBack "Diffuse"
3.表面着色器
Unity通过SurfaceShader可以处理不同的照明,点光源,平行光,光照贴图等,又能处理不同的阴影选项,还能同时在Unity两个渲染路径下正常工作。例子代码就是Unity创建的默认Shader
Shader "Custom/NewShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
surf函数中 SurfaceOutput是一个包含大多数描述一个物体表面渲染特征的结构
struct SurfaceOutput{
half3 Albedo;//颜色纹理
half3 Normal;
half3 Emission;//自发光,不受照明影响
half Specular;//高光指数
half Gloss;//光泽度
half Alpha;//Alpha通道
};
表面着色器最终会被编译成一个复杂的顶点+片段着色器。