法线映射我也是刚学会的,呵呵
输入到固定渲染管线的顶点结构虽然可以定制,但也不是完全自由的,比如顶点位置必须是float3,纹理坐标float2,法线float3等等。如果使用可编程管线,由于VS的输入可以自由解析,所以相对来说就增加了很多灵活性。
在使用切线空间的法线映射(normalmap)时,一般来说顶点数据中除了法线向量外还需要加入tangent向量和binormal向量信息,以便在VS中计算切线空间变换矩阵。其中tangent是切平面上纹理坐标u的正方向,binormal是切平面上纹理坐标v的正方向。normal,tangent和binormal三者互相垂直,构成了切线空间坐标系,于是切线空间到世界空间的变换矩阵就是 float3x3( tangent, binormal, normal )
法线映射的实现一般来说有两种:
1。在vertex shader中计算出切线空间变换矩阵(如上文所述),并将该矩阵输出。在pixel shader中用得到的矩阵将法线图中采样得到的切线空间的法向量变换到世界空间,然后再进行后续的光照计算。
2。同样在vertex shader中计算出切线变换矩阵,但不输出,而是在VS中将光线方向逆向变换到切线空间,将切线空间的光线方向输出。在PS中所有的计算都在切线空间进行。
上述两种方法本人都试过,得到的画面有些微差异,但很难说哪一种是“正确”的,因为都涉及到象素对顶点信息的插值,只不过一个是对矩阵的插值,一个是对向量的插值。但是从效率上考虑,一般来说PS的压力会比VS大,而第二种方法把一个向量/矩阵乘法从PS端提前到了VS端,所以速度会更快一些。要注意的是如果采用第二种方法并且需要实现基于法线映射的高光的话,视线向量也必须在VS中转换到切线空间并输出到PS。
另外,由于normal,tangent和binormal是正交的,实际上三者中的任何一个都可以通过另外两个向量的叉乘得到,所以实际上顶点数据只需要提供normal和tangent,binormal可以在VS中通过计算得到。这样能节省宝贵的显存带宽,而显卡瓶颈一般会在PS,VS中增加一些计算不会降低帧率(不要相信我,自己去试验一下^^)
现在计算一下顶点结构大小。顶点坐标float3,纹理坐标float2,法线向量float3,tangent向量float3,一共要44个字节。如果要节省的话,实际上normal和tangent向量可以从float3压缩到byte3,当然显卡不会支持byte3这种格式,浪费一个字节就DWORD(也就是COLOR)吧,这样顶点结构就一下减到28字节了。有些情况下这是很有意义的,在处理象地形这种包含大量顶点并且需要每帧生成顶点缓冲的情况下,缩减顶点结构大小就意味着节省大量内存,减小CPU复制顶点的开销,减小显存带宽的占用真是一举数得嘿嘿……当然,代价是降低了切线空间的精度,但是考虑到最多会引入1/256的误差,而且本来法线图的精度也只有0~255(单分量),而且还经过了象素插值,最终的画面对比用肉眼几乎看不出差别。
还有更厉害的。如果正好是用在地形渲染,并且一次渲染的地形块尺寸小于256(均匀网格的情况下),甚至顶点位置和纹理坐标也可以压缩,能再节省12个字节!声明一下这个我还没有试过是否真正可行,不知道是否允许pos不是float3的。。。
再次抱歉,没有图