【UnityShader】凹凸映射(世界空间下)
切线空间下的计算我们已经涉及过,下文来介绍在世界空间下实现凹凸映射:
与切线空间下不同的是,我们在v2f结构体中做了修改:
struct v2f{
float4 pos:SV_POSITION;
float4 uv:TEXCOORD0;//纹理采样用 两个纹理所以用float4
//切线空间到世界空间变化矩阵的每一行 w分量中存储世界顶点坐标
float4 Trow0:TEXCOORD1;
float4 Trow1:TEXCOORD2;
float4 Trow2:TEXCOORD3;
};
Trow矩阵分开每行分别计算。其中w分量存储世界空间下的顶点坐标。
切线空间到世界空间将空间坐标轴的矢量表示按列排列即可
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' Shader "Custom/Chapter7-NormalMapWorldSpace" { Properties{ _Color ("Color Tint", Color) = (1, 1, 1, 1) _MainTex ("Main Tex", 2D) = "white" {} _BumpMap ("Normal Map", 2D) = "bump" {} _BumpScale ("Bump Scale", Float) = 1.0 _Specular ("Specular", Color) = (1, 1, 1, 1) _Gloss ("Gloss", Range(8.0, 256)) = 20 } SubShader{ pass{ Tags{"LightMode" = "ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Color; sampler2D _MainTex; sampler2D _BumpMap; float4 _BumpMap_ST; float _BumpScale; fixed4 _Specular; float _Gloss; float4 _MainTex_ST;//纹理类型属性 struct a2v{ float4 vertex:POSITION; float3 normal:NORMAL; float4 tangent:TANGENT; //顶点切线方向填充,四维的原因是要用w决定副切线的方向性 float4 texcoord:TEXCOORD0;//存储纹理坐标 }; struct v2f{ float4 pos:SV_POSITION; float4 uv:TEXCOORD0;//纹理采样用 两个纹理所以用float4 //切线空间到世界空间变化矩阵的每一行 w分量中存储世界顶点坐标 float4 Trow0:TEXCOORD1; float4 Trow1:TEXCOORD2; float4 Trow2:TEXCOORD3; }; 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); fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); fixed3 worldBinnormal = cross(worldNormal,worldTangent)*v.tangent.w; //计算转化矩阵 o.Trow0 = float4(worldTangent.x,worldBinnormal.x,worldNormal.x,worldPos.x); o.Trow1 = float4(worldTangent.y,worldBinnormal.y,worldNormal.y,worldPos.y); o.Trow2 = float4(worldTangent.z,worldBinnormal.z,worldNormal.z,worldPos.z); return o; } fixed4 frag(v2f i):SV_Target{ float3 worldPos = float3(i.Trow0.w,i.Trow1.w,i.Trow2.w); fixed3 LightDir = normalize(UnityWorldSpaceLightDir(worldPos)); fixed3 ViewDir = normalize(UnityWorldSpaceViewDir(worldPos)); //首先对法线纹理进行采样 fixed4 packedNormal = tex2D(_BumpMap,i.uv.zw); //对像素反映射得到原来的发现方向,由于再切线空间先 保证z为正 //纹理类型不为Normal map时 Unity一般为Normal map 所以下面方式计算的话结果会出差 //tangentNormal.xy = (packedNormal.xy*2-1)*_BumpScale; //tangentNormal.z = sqrt(1.0-saturate(dot(tangentNormal.xy,tangentNormal.xy)));//因为是单位矢量,所以可以通过xy计算z fixed3 bump = UnpackNormal(packedNormal); bump.xy *=_BumpScale; bump.z = sqrt(1.0-saturate(dot(bump.xy,bump.xy))); bump = normalize(half3(dot(i.Trow0.xyz,bump),dot(i.Trow1.xyz,bump),dot(i.Trow2.xyz,bump))); //法线坐标转化 通过点乘实现3x3 * 3*1 fixed3 albedo = tex2D(_MainTex,i.uv).rgb*_Color.rgb; fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo; fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(bump,LightDir)); fixed3 halfDir = normalize(LightDir+ViewDir); fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(bump,halfDir)),_Gloss); return fixed4(ambient+diffuse+specular,1.0); } ENDCG } } FallBack "Diffuse" }
视觉上两个空间的计算并没有什么差别。

浙公网安备 33010602011771号