上文介绍了渲染管线、固定管线着色器和表面着色器,如下:
固定管线着色器通过命令方式实现光照和贴图等效果,表面着色器通过给 SurfaceOutput 赋值实现光照、贴图和法线贴图等效果,它们都不用关注光照算法是如何实现的,只需要传值就行。
顶点和片元着色器给用户提供了更灵活的用法,但使用也更困难。另外,顶点着色器可以通过控制 MVP 矩阵变换实现对模型位置和姿态的控制。
在 Assets 窗口右键,依次选择【Create→Shader→Standard Surface Shader】创建 Shader 脚本,实现固定颜色 Shader 代码如下:
VFShader.shader
- Shader "MyShader/VFShaderTest" {
- Properties
- {
- // 属性名 ("面板显示名称", 类型) = 默认值
- _MainColor ("显示颜色", Color) = (1, 0, 0, 1)
- }
-
- SubShader
- {
- Pass
- {
- CGPROGRAM // CG语言的开始
- // 编译指令 着色器名称 函数名称
- #pragma vertex vert // 顶点着色器, 每个顶点执行一次
- #pragma fragment frag // 片段着色器, 每个像素执行一次
- // 导入头文件
- #include "UnityCG.cginc"
-
- // 声明属性变量, 必须与外部属性变量名称一致
- fixed4 _MainColor;
-
- // 顶点着色器
- float4 vert(float4 vertex: POSITION) : SV_POSITION
- {
- // 将局部坐标系下坐标转换为裁剪坐标系下坐标
- return UnityObjectToClipPos(vertex); // 等价于: mul(UNITY_MATRIX_MVP, vertex)
- }
-
- // 片元着色器
- fixed4 frag(): COLOR
- {
- return _MainColor;
- }
-
- ENDCG // CG语言的结束
- }
- }
-
- FallBack "Diffuse"
- }
创建一个 Material,并将 ShaderTest 绑定到该 Material 上,如下:

将该 Material 拖拽到一个 Cube 和 Sphere 游戏对象上。选中绑定的 Material,在 Inspector 窗口调整 Shader 中固定颜色,显示效果如下:

1)光照原理
Phong 光照模型和 Blinn Phong 光照模型是应用比较广泛的光照模型,两者区别在与镜面反射光的计算,Phong 光照模型根据反向量和观察向量计算镜面反射光,Blinn Phong 光照模型根据半向量和法向量计算镜面反射光。

光照计算如下:
- // 模型自身颜色
- fixed4 albedo = tex2D(_MainTex, i.uv) * _ModelColor;
- // 环境光
- fixed4 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo;
- // 漫反射光
- fixed4 diffuse = _LightColor0 * albedo * max(0, dot(normal, lightDir));
- // 镜面反射光(Phong光照模型)
- // fixed4 specular = _LightColor0 * _Specular * pow(max(0, dot(reflectDir, viewDir)), _Gloss);
- // 镜面反射光(Blinn Phong光照模型)
- fixed4 specular = _LightColor0 * _Specular * pow(max(0, dot(normal, halfDir)), _Gloss);
- // 合成颜色
- fixed4 finalColor = fixed4(ambient + diffuse + specular, 1.0);
2)代码实现
VFShader.shader
- Shader "MyShader/VFShaderTest" {
- Properties {
- _ModelColor ("Model Color", Color) = (1, 1, 1, 1) // 模型颜色
- _Specular ("Specular Color", Color) = (1, 1, 1, 1) // 镜面反射颜色
- _Gloss ("Gloss", Range(8.0, 256)) = 20 // 镜面反射光泽度
- }
-
- SubShader {
- Tags { "RenderType"="Opaque" }
-
- Pass {
- Tags { "LightMode"="ForwardBase" }
-
- CGPROGRAM
-
- #pragma vertex vert
- #pragma fragment frag
-
- #include "UnityCG.cginc"
- #include "Lighting.cginc"
-
- fixed4 _ModelColor; // 模型颜色
- fixed4 _Specular; // 镜面反射颜色
- float _Gloss; // 镜面反射光泽度
-
- struct a2v {
- float4 vertex : POSITION; // 模型空间顶点坐标
- float3 normal : NORMAL; // 模型空间顶点法线向量
- };
-
- struct v2f {
- float4 pos : SV_POSITION; // 裁剪空间顶点坐标
- float3 normal : Normal; // 世界空间顶点法线向量
- float3 worldPos : TEXCOORD0; // 世界空间顶点坐标
- };
-
- v2f vert(a2v v) {
- v2f o;
- o.pos = UnityObjectToClipPos(v.vertex); // 模型空间顶点坐标变换到裁剪空间, 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
- o.normal = UnityObjectToWorldNormal(v.normal); // 将模型空间法线向量变换到世界空间
- o.worldPos = mul(unity_ObjectToWorld, v.vertex); // 将模型空间顶点坐标变换到世界空间
- return o;
- }
-
- fixed4 frag(v2f i) : SV_Target {
- fixed3 normal = normalize(i.normal); // 世界空间法线向量
- fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // 世界空间灯光向量
- fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); // 世界空间观察向量
- fixed3 halfDir = normalize(lightDir + viewDir); // 半向量
- fixed3 albedo = _ModelColor; // 模型自身颜色
- fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo; // 环境光
- fixed3 diffuse = _LightColor0 * albedo * max(0, dot(normal, lightDir)); // 漫反射光
- fixed3 specular = _LightColor0 * _Specular * pow(max(0, dot(normal, halfDir)), _Gloss); // 镜面反射光(Blinn Phong光照模型)
- return fixed4(ambient + diffuse + specular, 1);
- }
-
- ENDCG
- }
- }
-
- FallBack "Specular"
- }
选中绑定的 Material,在 Inspector 窗口调整 Shader 中光照颜色,显示效果如下:

VFShader.shader
- Shader "MyShader/VFShaderTest" {
- Properties
- {
- // 属性名 ("面板显示名称", 类型) = 默认值
- _MainTex ("2阶贴图", 2D) = "white" {}
- }
-
- SubShader
- {
- Pass
- {
- Tags {"LightMode"="ForwardBase"}
- CGPROGRAM // CG语言的开始
- // 编译指令 着色器名称 函数名称
- #pragma vertex vert // 顶点着色器, 每个顶点执行一次
- #pragma fragment frag // 片段着色器, 每个像素执行一次
-
- // 导入头文件
- #include "UnityCG.cginc"
-
- // 声明属性变量, 必须与外部属性变量名称一致
- sampler2D _MainTex;
-
- struct a2v // 顶点着色器输入结构体
- {
- float4 vertex : POSITION; // 模型空间顶点坐标
- half2 texcoord : TEXCOORD0; // 纹理uv坐标
- };
-
- struct v2f // 顶点着色器输出结构体
- {
- float4 pos : SV_POSITION; // 裁剪空间顶点坐标
- half2 uv : TEXCOORD0; // 纹理uv坐标
- };
-
- // 顶点着色器
- v2f vert(a2v v)
- {
- v2f o;
- o.pos = UnityObjectToClipPos(v.vertex); // 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
- o.uv = v.texcoord;
- return o;
- }
-
- // 片元着色器
- fixed4 frag(v2f i) : SV_Target
- {
- return tex2D(_MainTex, i.uv);
- }
-
- ENDCG // CG语言的结束
- }
- }
-
- FallBack "Diffuse"
- }
选中绑定的 Material,在 Inspector 窗口选择贴图图片,显示效果如下:
