# Directx11教程十二之NormalMap(法线贴图)

## 一，LightMap(法线贴图)的简介.

,由光滑表面的法向量建立起的光照效果当然不够逼真，不能模拟真实世界隆起面的光照效果，自然而然的让隆起感大打折扣，真实实在不足,

看这就是法线贴图,那么为什么法线总体上是显示蓝色的，假设此NormalMap像素为(rn,gn,bn,an),由于bn比rn和gn大的多，在RGB中占比大，所以呈现蓝色.

x=2*r/255-1;         y=2*g/255-1;   z=2*b/255-1;

x=2*r-1;        y=2*g-1;    z=2*b-1;

e0=v1-v0,e1=v2-v0

e0和e1为3D三角面的两个边向量,e0(e0x,e0y,e0z),，e1(e1x,e1y,e1z)

e0和e1分别对应的三角面纹理向量为(△U0,△V0)=(u1-u0),(△U1,△V1)=(u2-u0,v2-v0);

e0=△U0*T+△V0B;

e1=△U1*T+△V1B;

行列式那章的计算公式：

而切向量t由局部空间变换到世界空间是乘以世界变换矩阵.

void ModelClass::CalculateTangentBinormal(TempVertexType vertex1, TempVertexType vertex2, TempVertexType vertex3,
VectorType& tangent, VectorType& binormal)
{

float Edge1[3], Edge2[3];
float TexEdge1[2], TexEdge2[2];

//计算面的两个向量
//边向量1
Edge1[0] = vertex2.x - vertex1.x; //E0X
Edge1[1] = vertex2.y - vertex1.y; //E0Y
Edge1[2] = vertex2.z - vertex1.z; //E0Z

//边向量2
Edge2[0] = vertex3.x - vertex1.x; //E1X
Edge2[1] = vertex3.y - vertex1.y; //E1Y
Edge2[2] = vertex3.z - vertex1.z; //E1Z

//纹理边向量1
TexEdge1[0] = vertex2.u - vertex1.u; //U0
TexEdge1[1] = vertex2.v - vertex1.v; //V0

//纹理边向量2
TexEdge2[0] = vertex3.u - vertex1.u; //U1
TexEdge2[1] = vertex3.v - vertex1.v; //V1

//求出TB在模型空间坐标的方程系数
float den = 1.0f / (TexEdge1[0] * TexEdge2[1] - TexEdge1[1] * TexEdge2[0]);

//求出Tangent
tangent.x=den*(TexEdge2[1] * Edge1[0] - TexEdge1[1] * Edge2[0]);
tangent.y=den*(TexEdge2[1] * Edge1[1] - TexEdge1[1] * Edge2[1]);
tangent.z=den*(TexEdge2[1] * Edge1[2] - TexEdge1[1] * Edge2[2]);

//求出Binormal
binormal.x = den*(-TexEdge2[0] * Edge1[0] + TexEdge1[0] * Edge2[0]);
binormal.y = den*(-TexEdge2[0] * Edge1[1] + TexEdge1[0] * Edge2[1]);
binormal.z= den*(-TexEdge2[0] * Edge1[2] + TexEdge1[0] * Edge2[2]);

}

<pre name="code" class="cpp">Texture2D ShaderTexture[3];  //纹理资源数组
SamplerState SampleType:register(s0);   //采样方式

cbuffer CBMatrix:register(b0)
{
matrix World;
matrix View;
matrix Proj;
matrix WorldInvTranpose;
};

cbuffer CBLight:register(b1)
{
float4 AmbientColor;
float4 DiffuseColor;
float3 LightDirection;
};

struct VertexIn
{
float3 Pos:POSITION;
float2 Tex:TEXCOORD0;  //多重纹理可以用其它数字
float3 Normal:NORMAL;
float3 Tangent:TANGENT;
float3 Binormal:BINORMAL;
};

struct VertexOut
{
float4 Pos:SV_POSITION;
float2 Tex:TEXCOORD0;
float3 Normal_W:NORMAL;
float3 Tangent_W:TANGENT;
float3 Binormal_W:BINORMAL;
};

VertexOut VS(VertexIn ina)
{
VertexOut outa;

//变换坐标到齐次裁剪空间(CVV)
outa.Pos = mul(float4(ina.Pos,1.0f), World);
outa.Pos = mul(outa.Pos, View);
outa.Pos = mul(outa.Pos, Proj);
outa.Tex= ina.Tex;

//将法线量由局部空间变换到世界空间，并进行规格化
outa.Normal_W = mul(ina.Normal, (float3x3)WorldInvTranpose);
outa.Normal_W = normalize(outa.Normal_W);

//将切向量由局部空间变换到世界空间，并且进行规格化
outa.Tangent_W = mul(ina.Tangent,(float3x3)World);
outa.Tangent_W = normalize(outa.Tangent_W);

//将切向量由局部空间变换到世界空间，并且进行规格化
outa.Binormal_W = mul(ina.Binormal, (float3x3)World);
outa.Binormal_W = normalize(outa.Binormal_W);

return outa;
}

float4 PS(VertexOut outa) : SV_Target
{
float4 BasePixel;
float3 BumpNormal;  //隆起法向量
float4 color;

//增加漫反射光颜色
color = AmbientColor;

//求每个像素的纹理像素颜色

//求每个像素的隆起法向量（切线空间）
BumpNormal = (2.0f*BumpNormal) - 1.0f;

//-----求出TBN矩阵（已经和世界变换矩阵结合在一起）--------
float3 N = outa.Normal_W;
float3 T = outa.Tangent_W;
float3 B = outa.Binormal_W;

//将隆起法向量由切线空间变换到局部空间，再到世界空间,然后规格化
BumpNormal= mul(BumpNormal,float3x3(T,B,N));
BumpNormal = normalize(BumpNormal);

//求出漫反射因子
float3 InvLightDirection = -LightDirection;
float DiffuseFactor = saturate(dot(BumpNormal, InvLightDirection));
color += DiffuseColor*DiffuseFactor;
color = saturate(color);

//乘以基础纹理颜色
color = color*BasePixel;

return color;
}

float4 PS(VertexOut outa) : SV_Target
{
float4 BasePixel;
float3 BumpNormal;  //隆起法向量
float4 color;
float DiffuseFactor;  //漫反射因子
float SpecularFactor; //镜面反射因子
float4 Specular; //镜面反射颜色
float4 SpecularIntensity; //镜面强度

//增加漫反射光颜色
color = AmbientColor;

//求每个像素的纹理像素颜色

//求每个像素的隆起法向量（切线空间）
BumpNormal = (2.0f*BumpNormal) - 1.0f;

//-----求出TBN矩阵（已经和世界变换矩阵结合在一起）--------
float3 N = outa.Normal_W;
float3 T = outa.Tangent_W;
float3 B = outa.Binormal_W;

//将隆起法向量由切线空间变换到局部空间，再到世界空间,然后规格化
<span style="color:#ff0000;">BumpNormal= mul(BumpNormal,float3x3(T,B,N));
//BumpNormal = N + BumpNormal.x*T + BumpNormal.y*B;</span>
BumpNormal = normalize(BumpNormal);

//求出漫反射因子
float3 InvLightDirection = -LightDirection;
DiffuseFactor = saturate(dot(BumpNormal, InvLightDirection));
color += DiffuseColor*DiffuseFactor;
color = saturate(color);

//乘以基础纹理颜色
color = color*BasePixel;

//如果漫射因子为正时,漫反射光和镜面才存在意义
if (DiffuseFactor > 0)
{

//求出入射光的反射向量，此时的法线量应该为法线贴图的法向量，别把参数位置搞反了
float3 ReflectLightDir = normalize(reflect(LightDirection,BumpNormal));
//float3 ReflectLightDir = normalize(2 * DiffuseFactor*BumpNormal - InvLightDirection);
//求每个像素的镜面强度

//求出镜面反射因子
SpecularFactor = pow(saturate(dot(outa.LookDirection, ReflectLightDir)), SpecularPow);

//求出镜面颜色,为什么这里用不上SpecularColor？？
Specular = SpecularFactor  *SpecularIntensity;
color = color + Specular;  //确实只有镜面光被计算 才加上

}
color = saturate(color);

return color;
}