第N次重新推到Camera变换矩阵后的总结

这个轮回我已经做过3次了:写DirectX的API driver,然后纠结几个小时把ViewPerspective给推导一遍。可能还有第4或这第5次,既然如此这次就留点东西,让下次再轮回时少浪费点时间。

前面的废话

这里就不记WorldView了。

orthogonal 变换

  • 目的(简单描述版):把view空间的一个AABB变换到graphics API所处理的NDC(normalized device coordinate)里,不要近大远小,平行的线看起来距离一直不变。
  • 目的(详细描述版,以DX为例):把view空间一个AABB[Min=(-w/2, -h/2, zNear), Max=(w/2,h/2,zFar)]用一个matrix4x4变到DirectX所规定的NDC space[Min=(-1,-1,0),Max=(1,1,1)]里
  • 实现(简单描述版):对AABB先做平移,让原来AABB在zNear的那个面对齐到z=0,然后再缩放,把AABB和NDC的大小对上。结束
  • 实现(详细描述版):对输入坐标(view space坐标)。先乘一个Translate(0, 0, -zNear),再乘一个Scale(2/w,2/h,1/(f-n))。结束

perspective 变换

  • 目的(简单版描述):把view space的AABB变换到graphics API所处理的NDC里,但是有近大远小,也就是说:沿着视线方向直线上的2个点会在屏幕上处于相同位置

  • 目的(详细版):使用一个matrix4x4对输入坐标做变换,具体来说要让输出结果的x/w和y/w对于在同一条视线上的2个点是相同的,并且z/w仍然是随z增大而单调递增,并且视锥台(因为要切掉近平面和eye之间的空间)要能被map到NDC.视锥台空间[Min=(-w/2,-h/2,zNear), Max=(zFarw/(2zNear),zFarh/(2zNear),zFar)]
    -第N次重新推到Camera变换矩阵后的总结_第1张图片

  • 实现:perspective变换可以分成2个步骤(1)view space->non-NDC orthogonal space(2)non-NDC orthogonal space->NDC.所谓的non-NDC orthognal space是一个正交空间。所以第2步可以直接用一个orthogonal矩阵,第一步需要另外推算

view space->non-NDC orthogonal space变换

  • 目的(简略版):把view space的视锥台空间变换到AABB space
  • 目的(详细版):znear、zfar的值都不变。视锥台空间的znear到了AABB space还是znear,视锥台空间的zfar到了AABB space 还是zfar。另外视锥台空间的znear完全不变地进入AABB space。变化地地方在于:视锥台空间地zfar平面(以及视锥台内处znear平面上的其他点)都要根据z值来scale XY坐标。要使得同一视线上的点在变换后x/w和y/w都相同.
  • 实现
    • 对于输入点的xy坐标,考虑到z轴上的点(0,0,z)仍然是(0,0,?),所以对于xy坐标的变换是x’ = zNear * x / depth和y’ = zNear * y / depth。由于变换的方式是乘上Matrix4x4再xyz分别除w。所以Matrix4x4上对应xy的scale应该是zNea,所以x’ = zNear * x, y’ = zNear * y. 此时w的计算公式是w’= z
    • 如果矩阵上z的scale是1,那z/w的结果是1,这样深度信息就全没了。由于是Matrix4x4,所以对于z能做的变换顶多是z’ = a * z + b, 此时z’/w’ = a + b/z,这个有2个问题:(1)和z是反相关(2)不再NDC要求的[0,1] range 里。所以要求得一个g(z) = a + b/z,要能让g(zNear) = 0, g(zFar) = 1。求解结果是 a = -f / (n-f), b = f*n/(n-f)
    • 如此便有了view space->non-NDC orthogonal space的变换矩阵

主要推导过程
第N次重新推到Camera变换矩阵后的总结_第2张图片

你可能感兴趣的:(Camera)