zoukankan      html  css  js  c++  java
  • [翻译转载]OpenGL投影矩阵(Projection Matrix)构造方法

    OpenGL Projection Matrix

    原文地址:原文

    Overview

    电脑显示器是一个二维平面, 而OpenGL渲染出来的场景却是三维的 , 所以必须要投影到二维的电脑屏幕上. 可以使用 GL_PROJCETION matrix 来进行投影转换. 首先,它把顶点数据从 eye coordinates(视点坐标) 转换到 clip coordinates(裁剪坐标). 在将这些坐标除以(w) 坐标分量来转换到NDC(标准化设备坐标)上

    因此,我们应该清楚 裁剪(可视平截头体的裁剪) 和 NDC 的转换都包含在了 GL_PROJECTION 矩阵中了. 下一段将会说明如何通过l,r,b,t,n,f(左,右,下,上,近和远)这六个边界值来构建透视矩阵.

    注意 可视平截头体的裁剪(裁剪) 是在 clip coordinates(裁剪坐标) 中, 在除以 (w_c) 前执行的.
    clip coordinates 的 (x_c,y_c,z_c) 会通过 (w_c) 来测试, 如果任何一个大于(w_c) 或 小于(-w_c), 那么这个顶点就会被丢弃.

    [-w_c<x_c,y_c,z_c<w_c ]

    当有丢弃时,OpenGL 将会重新构建多边形的边.

    一个被平截头体剪裁的三角形
    一个被平截头体剪裁的三角形

    ## Perspective Projection(透视投影)

    在透视投影中, truncated pyramid frustum (eye coordinates) (截锥体平截头体(视点坐标)) 中 三维的点呗映射到一个立方体(NDC); 三个坐标分量分别映射到 ([-1,1]. x: [l,r] => [-1,1], y:[b,t] => [-1,1], z:[n,f] => [-1,1])

    注意 eye coordinates 是定义在右手坐标中的, 但 NDC 是在左手坐标中的. 因此 源点摄像机在 eye space (视觉空间) 中看向 (z轴) 负向 而在 NDC中 看向(z轴) 正向. 由于 glFrustum() 对由进到远只接受正值, 我们需要在构造 GL_PROJECTION 矩阵时 对他们取反.

    截锥体平截头体和标准化设备坐标
    截锥体平截头体和标准化设备坐标

    在OpenGL在, 在 eye space 中的三维点 会被投影到 near plane(projection plane) (近平面(投影平面)) 上, 下面这张图显示了如何将 (p(x_e,y_e,z_e)) 投影到 (p(x_p,y_p,z_p)) 上.

    视锥体的顶视图

    视锥体的顶视图

    视锥体的侧视图

    视锥体的侧视图

     

    在顶视图中,(x_e),eye space 中的的x坐标, 通过相似三角形的比值的映射到 (x_p);

    (frac{x_p}{x_e} = frac{-n}{z_e})
    (x_p = frac{-n*x_e}{z_e} = frac{n*x_e}{-z_e})

    在侧视图中,(y_p)也是通过相似的方法计算出来的;

    (frac{y_p}{y_e} = frac{-n}{z_e})
    (y_p = frac{-n*y_e}{z_e} = frac{n*y_e}{-z_e})

    注意(x_p和y_p)都与(z_e)有关; 与(-z_e)成反比即除以(-z_e). 这是构造 GL_PROJECTION 矩阵的第一条线索. 在 eye coordinates 与 GL_PROJECTION 矩阵相乘完成变换后, clip coordinates 依然是 homogeneous coordinates(齐次坐标). 最终将其除以他的w分量来得到NDC.(更多细节OpenGL Transformation)

    [egin{pmatrix}x_{clip}\y_{clip}\ z_{clip}\w_{clip}end{pmatrix} = M_{projection} imes egin{pmatrix}x_{eye}\y_{eye}\ z_{eye}\w_{eye}end{pmatrix}, egin{pmatrix}x_{ndc}\y_{ndc}\ z_{ndc}end{pmatrix} = egin{pmatrix}x_{clip}/w_{clip}\y_{ndc}/w_{clip}\ z_{ndc}/w_{clip}end{pmatrix} ]

    因此,我们可以用 (-z_e) 作为 clip coordinates 的 w分量. 于是 GL_PROJECTION 矩阵的第四行变成了 ((0,0,-1,0).)

    [egin{pmatrix}x_{c}\y_{c}\ z_{c}\w_{c}end{pmatrix} = egin{pmatrix} .& . & . & .\ .& . & . &. \ .& . & .&. \ 0& 0 & -1 & 0 end{pmatrix} imes egin{pmatrix}x_{e}\y_{e}\ z_{e}\w_{e}end{pmatrix}, herefore w_c = -z_e ]

    接下来,我们通过线性关系把 (x_p,y_p) 映射到 NDC中的(x_n,y_n)上; ([l,r] => [-1,1] 和 [b,t] => [-1,1])

    把$x_p$映射到$x_n$

    (x_p)映射到(x_n)

    [x_n = frac{1-(-1)}{r-l}*x_p + eta ]

    [1 = frac{2r}{r-l}+ eta (用(r,1)代换(x_p,x_n)) ]

    [eta = 1-frac{2r}{r-l} = frac{r-l}{r-l}-frac{2r}{r-l} = frac{r-l-2r}{r-l} = frac{-r-l}{r-l} = -frac{r+l}{r-l} ]

    [ herefore x_n = frac{2x_p}{r-l} - frac{r+l}{r-l} ]

     

    把$y_p$映射到$y_n$

    (y_p)映射到(y_n)

    [y_n = frac{1-(-1)}{t-b}*y_p + eta ]

    [1 = frac{2t}{t-b}+ eta (用(t,1)代换(y_p,y_n)) ]

    [eta = 1-frac{2t}{t-b} = frac{t-b}{t-b}-frac{2t}{t-b} = frac{t-b-2t}{t-b} = frac{-t-b}{t-b} = -frac{t+b}{t-b} ]

    [ herefore y_n = frac{2y_p}{t-b} - frac{t+b}{t-b} ]

     

    然后把(x_p和y_p变量代换到上述式子中)

    (x_n = frac{2x_p}{r-l}-frac{r+l}{r-l} (x_p = frac{nxe}{-z_e}))

    (x_n = frac{2*frac{nx_e}{-z_e}}{r-l} - frac{r+l}{r-l})

    (x_n = frac{2n*x_e}{(r-l)(-z_e)} - frac{r+l}{r-l})

    (x_n = frac{frac{2n}{r-l}*x_e}{-z_e} - frac{r+l}{r-l})

    (x_n = frac{frac{2n}{r-l}*x_e}{-z_e} + frac{frac{r+l}{r-l}*z_e} {-z_e})

    (x_n = (frac{2n}{r-l}*x_e+frac{r+l}{r-l}*z_e)/-z_e = x_c / -z_e)

    同理可得

    (y_n = (frac{2n}{t-b}*y_e+frac{t+b}{t-b}*z_e)/-z_e = y_c/-z_e)

    注意我们使每个方程的两个项都除以(-z_e) 来表示perspective division(透视除法)((x_c/w_c,y_c/w_c)). 而且我们之前已经把(w_c设成了-z_e)了, 所以括号内的项已经是 clip coordinates 的 (x_c和y_c)了.

    于是得到了GL_PROJECTION 矩阵的前两行

    [egin{pmatrix}x_{c}\y_{c}\ z_{c}\w_{c}end{pmatrix} = egin{pmatrix} frac{2n}{r-l}& 0 & frac{r+l}{r-l} & 0\ 0& frac{2n}{t-b} & frac{t+b}{t-b} &0 \ .& . & .&. \ 0& 0 & -1 & 0 end{pmatrix} imes egin{pmatrix}x_{e}\y_{e}\ z_{e}\w_{e}end{pmatrix}]

    现在我们只剩GL_PROJECTION 矩阵的第三行需要解出了. 但解(z_n)并不像其他坐标那样简单,因为 eye space 的(z_e)总是被投影到近平面的-n上. 但我们为了 clipping(裁剪)和 depth test(深度测试)需要保证z坐标的唯一性.,而且还要能够反投影(还原变换). 因为z并不依赖于x和y坐标,我们借用w分量 来找到 (z_n和z_e)之间的关系. 因此我们可以像下面这样来指定 GL_PROJECTION 矩阵的第三行.

    [egin{pmatrix}x_{c}\y_{c}\ z_{c}\w_{c}end{pmatrix} = egin{pmatrix} frac{2n}{r-l}& 0 & frac{r+l}{r-l} & 0\ 0& frac{2n}{t-b} & frac{t+b}{t-b} &0 \ .& . & A&B \ 0& 0 & -1 & 0 end{pmatrix} imes egin{pmatrix}x_{e}\y_{e}\ z_{e}\w_{e}end{pmatrix}, z_n=z_c/w_c=frac{Az_e+Bw_e}{-z_e}]

    在 eye space中, (w_e) 等于1. 因此等式变成
    (z_n = frac{Az_e+B}{-z_e})

    我们用((z_e,z_n))的关系来找到系数A和B;将((-n,-1)和(-f,1))回代到上式中
    (left{egin{matrix} frac{-An+B}{n} = -1\ frac{-Af+B}{f} = 1 end{matrix} ight. ightarrow left{egin{matrix} -An+B = -n ;(1)\ -Af+B = f ;(2) end{matrix} ight.)

    重写等式(1);

    (B=An-n ; (1'))

    将B带入(2);

    (-Af +(An-n) = f ; (2))
    $-(f-n)A = f + n ( )A = -frac{f+n}{f-n}$

    把A回代到(1)中;

    ((frac{f+n}{f-n})n + B = -n ; (1))
    (B = -n - (frac{f+n}{f-n})n = -(1+frac{f+n}{f-n})n = -(frac{f-n+f+n}{f-n})n = -frac{2fn}{f-n})

    解出A和B后就可以得到(Z_e和Z_n)的关系;

    (Z_n = frac{-frac{f+n}{f-n}z_e - frac{2fn}{f-n}}{-z_e} ; (3))

    最终解出了整个 GL_PROJECTION 矩阵

    [egin{pmatrix} frac{2n}{r-l}& 0 & frac{r+l}{r-l} & 0\ 0& frac{2n}{t-b} & frac{t+b}{t-b} &0 \ 0& 0 & frac{-{f+n}}{f-n}& frac{-2fn}{f-n} \ 0& 0 & -1 & 0 end{pmatrix} ]

    这个投影矩阵是一种通用形式,如果可视平截头体是对称的,即(r=-l 和 t=-b),可以对其化简

    [left{egin{matrix} r+l=0\ r-l=2r ; (宽) end{matrix} ight. , left{egin{matrix} t+b=0 \ t-b=2t ;(高) end{matrix} ight.]

    [egin{pmatrix} frac{n}{r}& 0 & 0 & 0\ 0& frac{n}{t} & 0 &0 \ 0& 0 & frac{-{f+n}}{f-n}& frac{-2fn}{f-n} \ 0& 0 & -1 & 0 end{pmatrix}]

    在继续之前,请观察一下等式(3)中(z_e和z_n)的关系,你会发现他们并不是线性关系而是分式关系,这意味着在近平面会有非常高的精度而远平面的精度很低.如果([-n,-f])的范围很大,就会导致深度精度问题(z-fighting(深度冲突)); 在远平面(z_e)值小改动不会影响到(z_n)的值. 所以(n和f)的距离应该越小越好从而减少深度缓冲的精度问题.

    深度缓冲精度的比较
    深度缓冲精度的比较

    Orthographic Projection(正射投影)

    为正射投影构造 GL_PROJECTION 矩阵 比透视模式下的要简单的多

    正射视锥和标准化设备坐标(NDC)
    正射视锥和标准化设备坐标(NDC)

    eye space 中所有的(x_e,y_e和z_e)分量都线性映射到 NDC. 我们只需要把长方体视锥缩放正方体,然后把它移动到原点. 让我们来通过线性关系来解出 GL_PROJECTION 里的元素吧.

    把$x_e映射到x_n$

    (x_e映射到x_n)

    [x_n = frac{1-(-1)}{r-l}*x_e + eta ]

    [1 = frac{2r}{r-l} + eta ; (用(r,1)代换(x_e,x_n)) ]

    [eta = 1 - frac{2r}{r-l} = - frac{r+l}{r-l} ]

    [ herefore x_n = frac{2}{r-l}*x_e - frac{r+l}{r-l} ]

     

    把$y_e映射到y_n$

    (y_e映射到y_n)

    [y_n = frac{1-(-1)}{t-b}*y_e + eta ]

    [1 = frac{2t}{t-b} + eta ; (用(t,1)代换(y_e,y_n)) ]

    [eta = 1 - frac{2t}{t-b} = - frac{t+b}{t-b} ]

    [ herefore y_n = frac{2}{t-b}*y_e - frac{t+b}{t-b} ]

     

    把$z_e映射到z_n$

    (z_e映射到z_n)

    [z_n = frac{1-(-1)}{-f-(-n)}*z_e + eta ]

    [1 = frac{2f}{f-n} + eta ; (用(-f,1)代换(z_e,z_n)) ]

    [eta = 1 - frac{2f}{f-n} = - frac{f+n}{f-n} ]

    [ herefore z_n = frac{-2}{f-n}*z_e - frac{f+n}{f-n} ]

     

    由于在正射投影中不再需要w分量, GL_PROJECTION 矩阵的第四行 保留成(0,0,0,1), 于是可以得到 正射投影的 GL_PROJECTION 矩阵

    [egin{pmatrix} frac{2}{r-l}& 0 & 0 & -frac{r+l}{r-l}\ 0& frac{2}{t-b} & 0 &-frac{t+b}{t-b} \ 0& 0 & frac{-2}{f-n}& -frac{f+n}{f-n} \ 0& 0 & 0 & 1 end{pmatrix} ]

    同样的,如果视锥是对称的,即(r=-l 和 t=-b),可以对其化简

    [left{egin{matrix} r+l=0\ r-l=2r ; (宽) end{matrix} ight. , left{egin{matrix} t+b=0 \ t-b=2t ;(高) end{matrix} ight.]

    [egin{pmatrix} frac{1}{r}& 0 & 0 & 0\ 0& frac{1}{t} & 0 &0 \ 0& 0 & frac{-{2}}{f-n}& -frac{f+n}{f-n} \ 0& 0 & 0 & 1 end{pmatrix}]

  • 相关阅读:
    【转】CUDA5/CentOS6.4
    【转】centos 6.4 samba 安装配置
    【转】Install MATLAB 2013a on CentOS 6.4 x64 with mode silent
    【转】Getting xrdp to work on CentOS 6.4
    【VLFeat】使用matlab版本计算HOG
    Unofficial Windows Binaries for Python Extension Packages
    March 06th, 2018 Week 10th Tuesday
    March 05th, 2018 Week 10th Monday
    March 04th, 2018 Week 10th Sunday
    March 03rd, 2018 Week 9th Saturday
  • 原文地址:https://www.cnblogs.com/xxrlz/p/12506060.html
Copyright © 2011-2022 走看看