已经知道不能直接用模型变换矩阵来变换Normal,好比使用某含有非一致性缩放(在x,y,z方向上进行不程度的拉伸)的变换矩阵来变换一球体,则可能获得以下列图示的结果: 安全
左图为原始球体及其表面上的法向分布(2D投影后);中间为直接使用变换矩阵操做后的法向分布,但注意其明显与表面不垂直;右图为正确变换后的法向分布。
为何直接变换不正确呢?网上有多种说明版本,可是对比了一下感受仍是PBRT上的解释比较好一些。这里假设某一点处的法向量为n,切向量为t,由二者在曲面上的垂直关系可知: 工具
若是对于模型进行空间变换的矩阵为M,变换后在该点获得的新的切向量为,那么可得
(这里假设切向量并非由变换矩阵计算获得的,而是直接经过对模型表面进行几何分析计算获得的);变换后在该点获得新的法向量为
,如果获得的正确法向量,则其一定仍然与切向量垂直。假设正确变换获得的法向量是在变换矩阵S下进行的,那么有
,由法、切的垂直关系得: spa
在上式的最后阶段中能够看出,若是要知足成立条件则有,直接变换便可得
,因此也就有:
.net
这里就获得了一般咱们所说的采用逆的转置矩阵来代替原始变换矩阵来对法向量进行操做。
上述推导中使用的一个依据是切向量与法向量之间的垂直关系,其实这是创建在另一个基础上,那就是:切向量的计算通常是直接使用顶点与UV来进行,这样的话它就是直接与顶点相关,于是只要直接使用变换矩阵获得的顶点正确那么在此基础上计算而来的切向量也就正确,可是法向量却不是直接经过顶点计算、而是经过变换获得的(固然,若是Normal 也在网格顶点变换以后直接计算,而不是对原始的法向量用变换矩阵做空间变换的话就不会存在这一问题了) orm
另外,在实际操做中对于变换矩阵(通常为4x4的)并不必定可逆(好比一个由3D到2D的投影矩阵),于是上述S就无法计算,这种状况下更安全的一种方法是只使用原始4x4变换矩阵的左上角3x3矩阵,即不考虑平移部分,其实这也理所固然,平移操做本就不影响法向量。这一部分在Realtime Rendering中也有稍详细的说明。 get
固然,使用逆的转置来进行Normal变换只是正确方法的一种,不过也有其它的方法,好比从一个变换矩阵中只抽取出Rotation的部分来施加到Normal上,这样就免去了Translation和Scale的影响。矩阵的R, T, S分解也有不少经典的方法,能够参考一个这个帖子:http://www.gamedev.net/topic/441695-transform-matrix-decomposition/(虽然这种方法的效率与复杂度须要另外讨论,但毕竟也是一个途径) it
不过通常状况下,咱们对于场景中三维模型的变换基本上都是进行三向一致的缩放操做,这样的话M就是一个正交的矩阵,如此一来就有S等于M,于是直接使用M对法向量做变换也不会有什么问题出现(或者有差异也被忽略了^_*)。不过任意的缩放变换是建模工具的一个基本需求,于是在作工具时须要重视这一问题。 io