Unity Shader:
说到底,Shader其实只是一段规定好输入(颜色,贴图等)和输出(渲染器能读懂的点和颜色的对应关系)的程序。那么,设计一个Shader的过程其实就是根据输入,进行计算变换从而产生输出而已。
1.分类:
在Unity中的Shader分为两类:
- 表面着色器(Surface Shader):已经为我们完成了大部分的工作,只需要简单的操作即可得到不错的效果;
- 片段着色器(Fragment Shader):可以自己设计出很多东西,因为可自行设置的内容更多,但也更加难写。使用片段着色器的目的是可以在更加底层进行更复杂(或者针对目标设备更高效)的开发。
2.Shader程序基本结构:
使用Unity中的框架来编写Shader程序,其实相对于其他游戏引擎要简单一些,在Cocos2d中还得从OpenGL层面开始编写逻辑,但是在Unity只需要往框架中填入需要控制的内容即可,一个Shader程序的基本结构如下图所示:
Shader(着色器)Property Definition(属性定义)SubShader(子着色器:开始)PassPass......SubShader(子着色器:结束)Fallback(回滚)
- 首先,定义一些属性,用来指定代码将有哪些输入;
- 其次,会有一个或者多个子着色器,但是在实际运行中哪一个子着色器被使用是由运行的平台所决定的;
- 子着色器是代码的主体,每个子着色器包含一个或多个Pass;
- 最后指定一个回滚,用来处理所有Subshader都不能运行的情况(比如设备太老)。
执行着色时,平台选择最优先可以使用的子着色器,然后依次执行该子着色器中的Pass,然后输出结果。
创建第一个Shader,并附上注释:
Shader "Custom/SimpleShader" {
//属性,定义所需的各种属性
Properties{
_Color("Color", Color) = (1,1,1,1)
}
//针对某个显卡的SubShader语义块,当Unity需要加载这个UnityShader时,Unity会扫描所有的SubShader语义块,
//然后选择一个能够在目标平台上运行的SubShader。如果都不支持的话,Unity会使用Fallback语义指定的Unity Shader
SubShader{
Tags { "RenderType" = "Opaque" } //标签
LOD 200
Pass{
Name "MyPassName" //通过这个标签,可以在其他的Shader中通过UsePass “SimplesShader/MYPASSNAME"来说使用该Pass
CGPROGRAM //从CGPROGRAM到ENDCG为CG代码片段
//编译指令
#pragma vertex vert
#pragma fragment frag
fixed4 _Color;//定义一个和属性名称和类型都匹配的变量
//a application v vertex shader
struct a2v {
float4 vertex:POSITION;//把模型顶点坐标填充到vertex输入参数中
float3 normal:NORMAL;//把模型法线输入到normal参数中
float4 texcoord:TEXCOORD0;//把模型贴图输入到texcoord参数中
}; //;不能省略
//f fragment shader
struct v2f {
float4 pos :SV_POSITION; //pos包含顶点在裁剪空间中的位置信息
fixed3 color : COLOR0; //COLOR语义可以用于储存颜色信息
};
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//v.normal包含了顶点的法线方向,其分量范围在[-1.0,1.0]
//下面的代码把分量范围映射到[0.0,1.0]
//储存到o.color中传递给片元着色器
o.color = v.normal*0.5 + fixed3(0.5, 0.5, 0.5);
return o;
}
fixed4 frag(v2f i) :SV_Target{
fixed3 c = i.color;
c *= _Color.rgb;
return fixed4(c, 1.0);
}
ENDCG
}
}
FallBack "VertexLit"
}