自动计算顶点缓冲中所有顶点的法线
2010-02-2615:38:42|分类:游戏程序制作|举报|字号订阅
问题
当绘制自定义的结构时,你会发现光照不正确.
这是因为你没有指定正确的法线向量,显卡要求每个顶点都有法线信息,这样它才可以决定每个三角形获得多少光照,详细信息可见第六章.
为每个顶点计算法线向量看起来很复杂,因为大多数顶点被多个三角形共享.
解决方案
如果每个顶点只被一个三角形使用,你只需找到三角形的法线向量(换句话说,这个向量垂直于三角形)并将这个向量作为三个顶点的法线向量.
但是在一个结构中,所有顶点被几个三角形共享.要获取平滑的效果,每个顶点需要存储周围三角形所有法线的平均值.
工作原理
使用下列伪代码,你可以找到每个顶点正确的法线:
对于结构中的每个顶点,找到使用顶点的三角形.
计算这些三角形的法线向量.
求所有法线向量的平均值.
将这个平均法线存储到顶点中.
求平均值的过程是必须的,因为你总是要归一化存储在顶点中的法线向量(换句话说,让长度变为1).
注意:因为在vertex和pixelshader中要使用法线向量计算光线因子,所以要让法线向量长度变为1.当光线因子只由入射光和法线之间的夹角决定时,一个较大的法线向量会导致光线因子变大,具体解释可见第六章.
你可以将上述步骤变为具体代码,但如果你交换步骤1和2,会变得更容易:
对于结构中的每个三角形,计算法线向量.
将这个向量添加到三角形的三个顶点的法线中.对所有三角形进行这个操作后,执行以下操作:
归一化结构中的每个顶点的法线向量.
计算三角形的法线:叉乘的定义
在计算前,你需要知道什么是法线.简单的说,法线是垂直于三角形的方向,这意味着三角形上的任一点法线都是相同的.因为法线垂直于三角形平面,所以它也垂直于三角形的任何一个顶点.
那么如何计算一个三角形的法线向量呢?你可以使用叉乘,因为两个向量的叉乘返回垂直于两个向量决定的平面的向量.
你可以取三角形的两条边,通过叉乘获取垂直这个三角形的向量,如图5-13所示.这个法线的长度基于两条边的长度和夹角,所以需要将法线向量归一化.
图5-13获取三角形的法线向量
注意:Vector3.Cross(Vec1,Vec2)和Vector3.Cross(Vec2,Vec1)计算结果是不同的.这两个结果长度相同但方向相反.这是因为一个平面有两个垂直方向:一个指向纸外,一个指向纸内.
GenerateNormalsForTriangleList方法
当定义一个大对象时,你通常希望使用索引定义结构,因为这是顶点被多个三角形共享的唯一方式,这让你可以平滑光照(见教程6-2).所以这个教程基于结构中的顶点数组和索引数组进行计算:
PrivateVertexPositionNormalTexture[]GenerateNormalsForTriangleList(VertexPositionNormalTexture[]vertices,int[]indices)
{
}
这个方法接受一个不包含法线数据顶点数组,然后将正确的法线信息存储在每个顶点中并返回这个数组.根据索引信息,这个方法可以判断哪些顶点构成了三角形.但是,根据使用的是TriangleList还是TriangleStrip,索引数组的内容会不同,所以针对两者情况代码会有一些区别.
基于TriangleList计算法线
如果顶点已经包含法线数据,首先要将它们变为0:
for(inti=0;i
