简体   繁体   English

openGL中glFrustum的分解

[英]Decomposition of glFrustum in openGL

I'm trying to understand the projection matrix created with glFrustum() in OpenGL, and the transformations that bring it into the Normalized Device Coordinates of x=[-1,1] , y=[-1,1] , and z=[-1,1] and the series of 4x4 matrix multiplications that take place resulting in the projection matrix of 我正在尝试了解在OpenGL中使用glFrustum()创建的投影矩阵,以及将其转换为x = [-1,1]y = [-1,1]z =规范化设备坐标的转换[-1,1]和发生的一系列4x4矩阵乘法 ,导致投影矩阵为

I understand that the final results (in NDC) are obtained by dividing by the w component after the successive transformations are applied, but what are those successive transformations? 我知道最终结果(在NDC中)是通过应用连续变换后除以w分量获得的,但是那些连续变换又是什么呢?

That is what are the matrices T (in terms of near , far , left , right , top , down variables) in the expression 那就是表达式中的矩阵T就近变量而言)

Such that each T represents only a scale , translate , rotation , or shear operation/transformation? 这样每个T仅代表scale平移旋转剪切运算/变换?

I read a somewhat related post about Is OpenGL LH or RH , and the Projection Matrix tutorial , but I'm still lost as to the elementary operations (ie The scale , translate , rotation , or shear operations) taking place. 我读了一些有关OpenGL LH或RH的文章 ,以及Projection Matrix教程 ,但是我对正在进行的基本操作(即缩放平移旋转剪切操作)仍然不了解。

The perspective transformation matrix cannot be decomposed into only scale, translate rotate and shear operations. 透视变换矩阵不能仅分解为缩放,平移旋转和剪切操作。 Those operations are all affine , while the perspective transformation is projective (which is not affine; in particular, the perspective will not preserve parallelity of lines). 这些操作都是仿射的 ,而透视变换是投影的 (不是仿射的;特别是,透视将不会保留线的平行性)。

The "target volume" is an axis-aligned cube in normalized device space. “目标体积”是归一化设备空间中与轴对齐的立方体。 In standard OpenGL, this is going from -1 to 1 in all dimensions (Direct3D, and also Vulkan, use a slightly different convention: [-1,1] for x and y, but [0,1] for z. This means the third row of the matrix will look a bit different, but the concepts are the same). 在标准OpenGL中,所有尺寸的值从-1变为1(Direct3D以及Vulkan都使用稍微不同的约定:[-1,1]用于x和y,但是[0,1]用于z。这意味着矩阵的第三行看起来会有所不同,但是概念是相同的)。

The projection matrix is constructed such that the pyramid frustum is transformed into that normalized volume. 构造投影矩阵,以使锥体视锥转化为该标准化体积。 OpenGL also used the convention that in eye space, the camera is oriented towards -z . OpenGL还使用以下约定:在眼睛空间中,相机朝向-z方向。 To create the perspective effect, you simply have to project each point onte a plane, by intersecting the ray conneting the projection center and the point in question with the actual viewing plane. 要创建透视效果,只需将通过投影中心和相关点连接的光线与实际观察平面相交,即可将每个点投影到一个平面上。

The above perspective matrix assumes that the image plane is parallel to the xy plane (if you want a different one, you could apply some affine rotation). 上面的透视矩阵假定图像平面平行于xy平面(如果需要其他平面,则可以应用仿射旋转)。 In OpenGL eye space, the projection center is always at the origin. 在OpenGL眼空间中,投影中心始终位于原点。 When you do the math, you will see that the perspective boils down to a simple instance of the intercept theorem. 在进行数学运算时,您会看到透视图可以归结为截距定理的简单实例。 If you want to project all points to a plane which is 1 unit in front of the center ("camera"), you end up with dividing x and y by -z . 如果要将所有点投影到中心前方1个单位的平面(“相机”),则最终将xy除以-z

This could be written in matrix form as 这可以用矩阵形式写成

(  1   0   0   0 )
(  0   1   0   0 )
(  0   0   1   0 )
(  0   0  -1   0 )

It works by setting w_clip = -z_eye , so when the division by clip space w is carried out, we get: 它通过设置w_clip = -z_eye ,因此当执行按片段空间w的除法时,我们得到:

 x_ndc = x_clip / w_clip = - x_eye / z_eye
 y_ndc = y_clip / w_clip = - y_eye / z_eye

Note that this also applied to z: 请注意,这也适用于z:

 z_ndc = z_clip / w_clip = - z_eye / z_eye = 1

Such a matrix is typically not used for rendering, because the depth information is lost - all points are actually porjected onto a single plane. 这样的矩阵通常不用于渲染,因为深度信息会丢失-所有点实际上都注入到单个平面上。 Usually, we want to preserve depth (maybe in some non-linearily deviated way). 通常,我们要保留深度(也许以某种非线性偏离的方式)。

To do this, we can tweak the formula for z (third row). 为此,我们可以调整z的公式(第三行)。 Since we do not want any dependency of z on x and y, there is only the last element we can tweak. 由于我们不希望z依赖于x和y,因此只有最后一个元素可以调整。 By using a row of the form (0 0 AB) , we get the following equation: 通过使用(0 0 AB)形式的行,我们得到以下方程式:

z_ndc =  - A * z_eye / z_eye - B / z_eye = -A - B / z_eye

which is just a hyperbolically transformed variant of the eye space z value - depth is still preserved - and the matrix becomes invertible. 这只是眼睛空间z值的双曲线变换变体-深度仍然保留-矩阵变为可逆。 We just have to calculate A and B. 我们只需要计算A和B。

Let us call the function z_ndc(z_eye) = -A - B / z_eye just Z(z_eye) . 让我们将函数z_ndc(z_eye) = -A - B / z_eye Z(z_eye) Since the viewing volume is bounded by z_ndc = -1 (front plane) and z_ndc = 1 , and the distances of the near and far plane in eye space are given as parameters, we have to map the near plane z_eye=-n to -1, and the far plane z_eye=-f to 1. To chose A and B, we have to solve a system of 2 (non-linear) equations: 由于观看量由z_ndc = -1 (前平面)和z_ndc = 1界定,并且z_ndc = 1平面和z_ndc = 1平面在眼空间中的距离作为参数给出,因此我们必须将近视平面z_eye=-n映射到- 1,远平面z_eye=-f 1。要选择A和B,我们必须求解一个由2个(非线性)方程组成的系统:

Z(-n) = -1
Z(-f) =  1

This will result in exactly the two coefficients you find in the third row of your matrix. 这将精确地得出您在矩阵第三行中找到的两个系数。

For x and y, we want to control two things: the field of view angle, and the asymetry of the frustum (which is similiar to the "lens shift" known from projectors). 对于x和y,我们要控制两件事:视场角和视锥的不对称性(与投影仪中已知的“镜头移位”类似)。 The field of view is defined by the x and y range on the image plane which is mapped to [-1,1] in NDC. 视场由在NDC中映射到[-1,1]的图像平面上的x和y范围定义。 So you can imagine just an axis-aligned rectangle on an arbitrary plane parallel to image plane. 因此,您可以想象在与图像平面平行的任意平面上仅出现一个与轴对齐的矩形。 This rectangle describes the part of the scene which is mapped to the visible viewport, at that chosen distance from the camera. 此矩形描述了场景的一部分,该部分已映射到可见视口,并且距摄像机的选定距离为该部分。 Changing the field of view just means scaling that rectangle in x and y. 更改视野仅意味着在x和y上缩放该矩形。

And conceptually, the lens shift is just a translation, so you might think it should be put in the last column. 从概念上讲,镜头移位只是翻译,因此您可能认为它应该放在最后一栏中。 However, since the division by w=-z will be carried out after the matrix multiplication, we have to multiply that translation by -z first. 但是,由于将在矩阵乘法之后执行w=-z的除法运算,因此我们必须先将该转换乘以 -z This means that the translational part is now in the third column, and we have a matrix of the form 这意味着翻译部分现在位于第三列中,并且我们具有以下形式的矩阵

( C   0   D   0 )
( 0   E   F   0 )
( 0   0   A   B )
( 0   0  -1   0 )

For x, this gives: 对于x,这给出:

x_clip = (x_eye * C + D * z_eye ) / (-z_eye) = -x_eye / z_eye - D

Now we just have to find the correct coefficients C and D which will map x_eye=l to x_ndc=-1 and x_eye=r to x_ndc=1 . 现在我们只需要找到正确的系数C和D即可将x_eye=l映射到x_ndc=-1并将x_eye=r x_ndc=1x_ndc=1 Note that the classical GL frustum function interprets the values of l and r here as distances on the near plane, so we have to calculate all this for z_eye=-n . 请注意,经典的GL视锥体将此处的lr的值解释为在近平面上的距离,因此我们必须为z_eye=-n计算所有这些。 Solving that new system of 2 equations, you will lead to those coefficients you see in the frustum matrix. 解决这个由2个方程组成的新系统,将得出在平截头体矩阵中看到的那些系数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM