NormalMap就是法线映射,简单的讲就是通过读取一张存储着发现信息的纹理来计算光照(而不通过顶点法线的插值),这样可以明显增强图像的真实感。

NormalMap的实现原理很简单,就是用一张纹理存储法线信息,这样shader就可以得到每个像素的法线信息,通过计算光照,在视觉上产生凹凸不平的效果(当然这也就是说,在没有光照的情况下是看不出立体感的o.o)

但说到具体实现上,就要注意了,直接从纹理中采样得到的信息是不能直接作为法线使用的,因为纹理中所存的法线信息是和纹理坐标一样,是存在于切线空间的数据。所以要想使用这里的法线数据,就必须把它变换到世界空间(因为光照是在这个空间中计算的)。

//----------------------------------------------------
 	// 将法线贴图的采样值转换到世界空间.
 	//----------------------------------------------------
float3 NormalSampleToWorldSpace(float3 normalMapSample, float3 unitNormalW, float3 tangentW)
{                         //从纹理中采样到的法线//    //变化到世界坐标系的顶点法线//    //变换到世界坐标系中的切线//
 		// 将每个分量从[0,1]解压到[-1,1].
 		float3 normalT = 2.0f*normalMapSample - 1.0f;
  		// 创建TBN基.	
  		float3 N = unitNormalW;
  		float3 T = normalize(tangentW - dot(tangentW, N)*N);
  		float3 B = cross(N, T);
  		float3x3 TBN = float3x3(T, B, N);
  		// 从切线空间转换到世界空间.
  		float3 bumpedNormalW = mul(normalT, TBN); 
  		return bumpedNormalW;
}

这里有一点需要注意:参数中的 unitNormalW 不是由顶点法线×世界变化矩阵而来的因为,因为不等比的缩放等操作会使得法线变形,所以这里是由 顶点法线×逆转置世界变化矩阵 而得来的。

示例


ShiweyYan

A game developer who graduates from SCUT.