目录
NormalMap的无黑盒版ShaderForge实现
关于Code代码
第一行:采样法线贴图并解码,使用UnpackNormal方法
第二行:构建TNB矩阵
第三行:将切线空间下的法线转化到世界空间,并归一化。由于矩阵相乘比较特殊所以用mul而不直接*
第四行:输出世界空间下的法线信息
代码版无黑盒NormalMap
定义面板参数
Properties {
_NormalMap ("法线贴图", 2D) = "bump" {}
}
输入结构
// 输入参数
uniform sampler2D _NormalMap;
// 输入结构
struct VertexInput {
float4 vertex : POSITION; // 顶点信息
float2 uv0 : TEXCOORD0; // 需要UV坐标 采样法线贴图
float4 normal : NORMAL; // 法线信息
float4 tangent : TANGENT; // 构建TBN矩阵 需要模型切线信息
};
输出结构
// 输出结构
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0; // UV信息
float3 nDirWS : TEXCOORD1; // 世界空间法线信息
float3 tDirWS : TEXCOORD2; // 世界空间切线信息
float3 bDirWS : TEXCOORD3; // 世界空间切线信息
};
顶点Shader
// 输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0; // 新建一个输出结构
o.pos = UnityObjectToClipPos( v.vertex ); // 变换顶点信息 并将其塞给输出结构
o.uv0 = v.uv0; // 传递UV信息
o.nDirWS = UnityObjectToWorldNormal(v.normal); // 世界空间法线信息
o.tDirWS = normalize(mul( unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); // 世界空间切线信息
o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w); // 世界空间切线信息
return o; // 将输出结构 输出
}
像素Shader
// 输出结构>>>像素
float4 frag(VertexOutput i) : COLOR {
// 获取nDir
float3 var_NormalMap = UnpackNormal(tex2D(_NormalMap, i.uv0)).rgb; // 采样法线纹理并解码 切线空间nDir
float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS); // 构建TBN矩阵
float3 nDir = normalize(mul(var_NormalMap, TBN)); // 世界空间nDir
// 获取lDir
float3 lDir = _WorldSpaceLightPos0.xyz;
// 一般Lambert
float nDotl = dot(nDir, lDir); // nDir点积lDir
float lambert = max(0.0, nDotl); // 截断负值
return float4(lambert, lambert, lambert, 1.0); // 输出最终颜色
}