前言:本篇博客只是一个简单的实现漫反射功能的例子,主要是当做笔记使用。
核心要点:如下所示:
1.使用法向量和光照向量在相同坐标系中进行点积得到光照强度。点积值小于0表示光照在两向量所在平面的背面,此时无需光照颜色。点积值大于等于0时表示光照在两向量所在平面的正面,此时点积值越大,两向量夹角越小,光照强度就越强。所以可以将点积值使用saturate函数限定在0~1之间来乘以光照颜色,从而得到每个顶点的对应强度光照颜色。
2.光照向量可以使用_WorldSpaceLightPos0(在前向渲染路径下的世界空间坐标系中),而光照颜色可以使用_LightColor0(光照模型为ForwardBase)。
3.模型顶点数据传递给unity,unity将这些数据以值拷贝的形式传递给顶点着色器接收变量中。其中这些数据就包含模型空间中的法线向量。为了得到不受模型缩放影响的世界空间中法向量,此时可以使用模型到世界矩阵的逆矩阵(也就是世界到模型矩阵)的转置矩阵来对模型空间中的法向量进行矩阵变换。由于shader中的mul接口第二个参数放矩阵的话,实际上就是使用该矩阵的转置矩阵来影响第一个参数传入的模型空间法向量。
4.顶点着色器中计算光照时效率高,但是颜色不够细腻平滑。片段着色器中计算光照时效率低,但是颜色却是十分细腻平滑。
核心代码:如下所示:
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Custom/demo10" {
SubShader {
pass {
tags { "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
#include "lighting.cginc"
struct v2f {
float4 pos:POSITION;
fixed4 col:COLOR;
};
v2f vert(appdata_base i)
{
v2f o;
// 模型顶点坐标经过MVP矩阵变换后,转换到齐次空间坐标系中
o.pos = mul(UNITY_MATRIX_MVP, i.vertex);
// 获取模型空间中归一化的法线向量
float3 normal = normalize(i.normal);
//为了得到模型缩放无关的法向量,通常使用模型到世界矩阵的逆矩阵(也就是世界到模型)的转置矩阵来变换法向量,此时将矩阵放在mul的第二个参数就是用来取矩阵的转置矩阵来变换指定向量
normal = mul(float4(normal, 0), unity_WorldToObject).xyz;
normal = normalize(normal);
// 获取世界空间中归一化的光照向量:顶点指向光源的方向
float3 light = normalize(_WorldSpaceLightPos0);
// 获取法线向量和光照向量的点积值:值越大,两向量夹角越小,光强度越大。
float dotValue = dot(normal, light);
// 将点积值限制在0~1的范围内:因为点积值为负数时,表示光照在平面背面,此时可以不做光照。
dotValue = saturate(dotValue);
// 使用光照颜色乘以光照强度点积值加上环境光,得到顶点的光照颜色。
o.col = _LightColor0 * dotValue + UNITY_LIGHTMODEL_AMBIENT;
return o;
}
fixed4 frag(v2f i):COLOR
{
return i.col;
}
ENDCG
}
}
}
运行效果:如下所示:
此处的两个Cube一个使用系统的Diffuse一个使用自己编写的shader。两个Sphere对应的缩放值不同,且一个使用系统的Diffuse一个使用自己编写的shader。