Normal Map 分为Object Space 和Tangent Space。下面是Tagent Space的实现。
贴上Normal Map在DX 上的实现。
sampler NormalMap =
sampler_state
{
Texture = <g_Texture1>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
};
struct VS_INPUT_Mesh_N
{
float4 Position : POSITION;
float3 Normal : NORMAL;
float2 Tex0 : TEXCOORD0;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
};
struct VS_OUTPUT_Mesh_N
{
float4 Position : POSITION;
float2 Tex0 : TEXCOORD0;
float3 Normal : TEXCOORD1;
float3 Tangent : TEXCOORD2;
float3 Binormal : TEXCOORD3;
float3 VertexPos : TEXCOORD4;
};
VS_OUTPUT_Mesh_N VShaderMeshNormalMap( VS_INPUT_Mesh_N In )
{
VS_OUTPUT_Mesh_N Out;
Out.Position = 0;
Out.Normal = 0;
Out.Tangent = 0;
Out.Binormal = 0;
Out.VertexPos = In.Position.xyz;
float4 position = mul(In.Position, g_mWorld);
Out.Position = mul(float4(position.xyz, 1.0f), g_mViewProj);
Out.Normal = normalize(mul(In.Normal, (float3x3)g_mWorld)); // normal (world space)
Out.Tangent = normalize(mul(-In.Tangent, (float3x3)g_mWorld)); //maya exporter perhaps "-"
Out.Binormal = normalize(mul(-In.Binormal, (float3x3)g_mWorld));
//Out.Binormal = cross( Out.Normal, Out.Tangent );
// Pass the texture coordinate
Out.Tex0 = In.Tex0;
return Out;
}
PS_OUTPUT PShaderMeshNormalMap( VS_OUTPUT_Mesh_N In)
{
PS_OUTPUT Out;
float4 diffuse_color = tex2D(DiffuseMap, In.Tex0);
float3 normal_map = tex2D( NormalMap, In.Tex0 ).xyz;
float3 L = normalize(g_LightDir[0].xyz);
float3 V = normalize ( g_vCameraPosition - In.VertexPos ) ;
float3 H = normalize ( V + L ) ;
float3 N = normalize(normal_map . xyz/* * 2.0f - 0.5f*/) ;
float3x3 TBNMatrix = float3x3(In.Tangent, In.Binormal, In.Normal);
N = normalize(mul(N, TBNMatrix));
float intensity = saturate( dot(N, L) );
float3 ambient = g_LightAmbient;
float3 diffuse = intensity * g_LightDiffuse[0];
float3 light = lerp( ambient + diffuse, float3(1,1,1), emissive ) ;
float3 specular_light = pow(max(dot(H , N) , 0.001f) , g_MaterialShininess) * g_LightDiffuse[0] ;
Out.RGBColor.xyz = diffuse_color.xyz * light + specular_light;
Out.RGBColor.w = diffuse_color.w;
return Out;
}
technique MeshNormalMap
{
pass P0
{
VertexShader = compile vs_2_0 VShaderMeshNormalMap();
PixelShader = compile ps_2_0 PShaderMeshNormalMap();
}
}