DirectX Geometry Pipeline的投影变换不是D3DXMatrixShadow或者几何书上的投影变换。
几何书上的投影变换是这样的:
分别是平行投影和透视投影,把空间中的三维物体变成二维平面上的图形。
而DirectX Geometry Pipeline的投影变换是这样的:
上图分别是 Perspective Camera
和 Orthographic Camera
的视景体1(图中的坐标架代表摄像机坐标系),不同的视景体决定了不同的投影类型,常见的是透视投影和正投影。DirectX Geometry Pipeline的投影变换是把视景体都变成DirectX规定的长方体 H(齐次裁剪空间):
w>0:2
齐次坐标
前者是三维到二维的变换,后者是三维到三维的变换;
后者去掉深度信息(z坐标)就相当于前者;
前者补上深度信息可以得到后者。
现在来求 把Perspective Camera的视景体变成DirectX规定的长方体的透视矩阵,
思路是先计算三维到二维的透视投影,再加上深度向量。
E是透视投影线的汇聚点,P’ 位于投影平面上,该平面过点Q,法向是N(单位法向量)朝右,
由质点几何易知P’的齐次坐标为 ((P−Q)N⊤E+(Q−E)N⊤P,(P−E)N⊤) 。
深度向量 d=((P−Q)N⊤N,0) .
要还原P’的深度信息,只需 把P’的位置坐标加上深度向量d 即可
但是因为含有 (P−E)N⊤(P−Q)N⊤N ,无法写成对 (P,1)的线性变换。这样我们不得不放弃使用真正的深度值了。
深度缓冲区是用来进行深度测试,处理物体的遮挡的。只要能保持相对深度关系,即使不是真正的深度值也没有关系。
如果我们把P’的齐次坐标和深度向量 d 直接相加:
得到的这个矩阵叫 伪透视矩阵
,它把 [0,+∞) 的实际深度值映射成[0,1],如下图:
zn 代表近裁剪平面(相对摄像机原点)的位置,x代表实际深度值(到近裁剪平面的距离),f(x)代表伪深度值。可见,太远的深度值会产生精度上的问题。
对于Perspective Camera的视景体,伪透视矩阵 把 [0,zf−zn] 的深度值映射成 [0,zf−znzf] .
现在把 E=(0,0,0),N=(0,0,1),Q=(0,0,zn)=znN 代入,伪透视矩阵
=
伪透视矩阵
就把Perspective Camera的视景体变成了
宽w高h深zf−znzf 的长方体,不过,摄像机坐标架的位置还没变。
接下来要做的就是把这个 宽w高h深zf−znzf 的长方体变成DirectX规定的”宽2高2深1“的长方体,并且把摄像机坐标架平移到下图所示的位置。
所以, 记s=zfzf−zn
这就是DirectX Perspective Camera的透视矩阵。它的第3行第4列的元素是1,所以若 P=(x,y,z,1) 是摄像机坐标系中的点,则 PM=(x′,y′,z′,z) . 这样就能直接用变换后点的 w 坐标当做深度信息,而不用 z′/z 。即 w-based depth buffer, or w-buffer3.
所以,虽然上面矩阵乘以任意的非零常数 得到的也都是透视矩阵,但是见脚注4。