pixel = (normal + 1) / 2
normal = pixel * 2 - 1
根据法线贴图判断信息存储空间
如果法线贴图是整体偏蓝色的,信息就是存储在切线空间里了。
如果法线贴图是五颜六色的,信息就是存储在模型空间下
法线贴图代码:
Shader"Custom/9 nine"{
Properties{
_MainTex("MainTex",2D) = "white"{}
_Color("Color",Color) = (1,1,1,1)
_NormalMap("Normal Map",2D) = "bump"{}
}
SubShader{
Pass{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex;
float4 _MainTex_ST;
声明法线贴图和uv坐标
sampler2D _NormalMap;
float4 _NormalMap_ST;
fixed3 _Color;
struct a2v{
float4 vertex:POSITION;
//切线空间是通过模型里的法线及模型里的切线确定的
float3 normal:NORMAL;
float4 tangent:TANGENT;//用了确定切线空间坐标轴方向
//获取uv坐标
float4 textcoord:TEXCOORD0;
};
struct v2f{
float4 svPos:SV_POSITION;
float3 LightDir : TEXCOORD0;
float4 worldVertex:TEXCOORD1;
///传递uv坐标
float4 uv:TEXCOORD2;///xy存储maintex纹理坐标、zw存储法线贴图的纹理坐标
};
v2f vert(a2v v){
v2f f;
f.svPos = UnityObjectToClipPos(v.vertex);
f.worldVertex = mul(v.vertex,unity_WorldToObject);
乘以xy轴实现多图,加上zw实现纹理偏移
f.uv.xy = v.textcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
f.uv.zw = v.textcoord.xy*_NormalMap_ST.xy+_NormalMap_ST.zw;
TANGENT_SPACE_ROTATION;//调用宏以后得到rotation的矩阵,用来把模型空间方向换为切线空间下
//ObjSpaceLightDir(v.vertex);模型空间下的平行光方向
f.LightDir = mul(rotation,ObjSpaceLightDir(v.vertex));
return f;
}
///所有跟法线有关的运算放在切线空间下(因为法线贴图取得的法线方向是切线空间的)
fixed4 frag(v2f f):SV_Target{
/// 获取法线贴图颜色
float4 normalColor = tex2D(_NormalMap,f.uv.zw);
// 变换到切线空间取法线
// Unity封装方法,自己计算会出现问题
fixed3 tangentNormal = normalize(UnpackNormal(normalColor));
//fixed3 tangentNormal = normalize(normalColor.xyz*2-1);
fixed3 LightDir = normalize(f.LightDir);
fixed3 texColor = tex2D(_MainTex,f.uv) * _Color;
fixed3 diffuse = _LightColor0.rgb * texColor * max(dot(tangentNormal,LightDir),0);
fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rgb * texColor;
return fixed4(tempColor,1);
}
ENDCG
}
}
Fallback "specular"
}
凹凸参数:
只需要控制法线贴图的xy方向就可以了。