Part1.代码逐段解析
struct a2v{
float4 vertex : POSITION; //顶点模型空间位置
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord : TEXCOORD0; //纹理uv
};
在顶点着色器的输入结构中,我们需要获取模型空间下顶点的位置、法向量、切向量、纹理uv
struct v2f{
float4 pos : SV_POSITION; //顶点在裁剪空间的位置
float4 uv : TEXCOORD0; //纹理uv
float4 TtoW0 : TEXCOORD1;
float4 TtoW1 : TEXCOORD2;
float4 TtoW2 : TEXCOORD3;
};
在从顶点着色器到片元着色器的通信结构体中,需要获取顶点在裁剪空间的位置,经过尺度、偏移变换后的纹理uv坐标,以及三组float4类型的值,用来存储从切线空间到世界空间的变换矩阵,以及顶点在世界空间的位置
v2f vert(a2v v){
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
//计算世界空间的顶点坐标
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
//计算世界空间下的法向量
fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
//计算世界空间下的切向量
fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
//法向量与切向量叉乘,再乘以方向因子,得到副切向量
fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
//将代表x轴的切向量,代表y轴的副切向量,代表z轴的法线方向按列排列,即可得到从切线空间到世界空间的变换矩阵
//这里需要将变换矩阵存储在插值寄存器中,为了节省空间,使用闲置的w分量来存储世界坐标
o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
o.TtoW1 = float4(worldTangent.y, worldB