我对GLM lookAt函数的理解不一致 [英] An inconsistency in my understanding of the GLM lookAt function

查看:243
本文介绍了我对GLM lookAt函数的理解不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,如果您想了解GLM lookAt算法的解释,请查看此问题提供的答案: http:/ /stackoverflow.com/a/19740748/1525061

  mat4x4 lookAt(vec3 const& eye,vec3 const& ; center,vec3 const& up)
{
vec3 f = normalize(center-eye);
vec3 u = normalize(up);
vec3 s = normalize(cross(f,u));
u = cross(s,f);

mat4x4结果(1);
Result [0] [0] = s.x;
结果[1] [0] = s.y;
Result [2] [0] = s.z;
Result [0] [1] = u.x;
结果[1] [1] = u.y;
Result [2] [1] = u.z;
Result [0] [2] = -f.x;
Result [1] [2] = -f.y;
Result [2] [2] = -f.z;
Result [3] [0] = -dot(s,eye);
Result [3] [1] = -dot(u,eye);
结果[3] [2] = dot(f,eye);
return Result;
}



现在我要告诉你为什么我似乎有一个概念这个算法的问题。这个视图矩阵有两个部分,平移和旋转。翻译执行正确的逆变换,使相机位置到原点,而不是原点位置到相机。类似地,您希望相机定义的旋转在被放入此视图矩阵之前反转。我看不到发生在这里,这是我的问题。



考虑向前的向量,这是你的相机看。因此,这个前向矢量需要映射到-Z轴,这是openGL使用的正向。假设这个视图矩阵的工作方式是在视图矩阵的列中创建一个正交基,所以当你乘这个矩阵右侧的顶点时,你基本上只是将它的坐标转换为不同轴的坐标。



当我播放作为这个转换的结果发生的旋转在我心中,我看到一个旋转不是相机的反向旋转,像假设发生,而我看到非逆。也就是说,我发现-Z轴正在映射到-Z轴,而不是找到相机向前映射到-Z轴。



如果你不理解我的意思,考虑这里发生的相同类型的事情的2D示例。假设前向矢量是(sqr(2)/ 2,sqr(2)/ 2)或45度的sin / cos,我们还假设这个2D相机的侧向矢量是-45度的sin / cos。我们想将这个前向矢量映射到(0,1),正Y轴。正Y轴可以被认为是类似于openGL空间中的-Z轴。让我们考虑与我们的前向矢量相同方向的顶点,即(1,1)。通过使用GLM.lookAt的逻辑,我们应该能够通过使用由第一列中的前向向量和第二列中的侧向向量组成的2x2矩阵将(1,1)映射到Y轴。这是该计算的等效计算 +1



请注意,你不会得到你的(1,1)顶点映射正Y轴像你想要的,而是你映射到正X轴。你也可以考虑如果你应用这个转换,一个顶点在正Y轴上发生了什么。果然,它被转换为向前的向量。



因此,看起来像使用GLM算法非常鱼腥的东西。但是,我怀疑这种算法是不正确的,因为它是如此受欢迎。

解决方案

查看Mesa中的GLU源代码: http://cgit.freedesktop.org/mesa/glu/tree/src/libutil/project.c < a>



首先在gluPerspective的实现中,注意 -1 正在使用索引 [2] [3] -2 * zNear * zFar /(zFar - zNear)正在使用 3] [2] 。这意味着索引是 [column] [row]



现在在执行 gluLookAt ,第一行设置为 side ,下一个设置为 up 最后一个到 -forward



GLM似乎在使用相同的 [column] [row] 索引(从代码)。你刚刚为 lookAt 发布的文章与更标准的 gluLookAt (包括翻译部分)一致。所以,至少GLM和GLU同意。



让我们一步一步推导完整的建设。注意 C 中心位置和 E 眼睛位置。


  1. 移动整个场景以将眼睛位置置于原点,即应用 -E 的翻译。


  2. 旋转场景,使相机的轴与标准(x,y,z)轴对齐。 / p>

    2.1计算相机的正正交基准:

      f =标准化(C-E)(指向中心)
    s = normalize(fxu)(指向眼睛的右侧)
    u = sxf(向上)

    (s,u,-f)



    2.2找到旋转矩阵 R ,aligns映射 u,-f)轴转换为标准(x,y,z)。反向旋转矩阵 R ^ -1 做相反的操作,并将标准轴与照相机轴对齐,根据定义,这意味着:

     (sx ux -fx)
    R ^ -1 =(syuy -fy)
    (sz uz -fz)

    由于 R ^ -1 = R ^ T

     (sx sy sz)
    R =(ux uy uz)
    (-fx -fy - fz)


  3. 将翻译与旋转组合。 A点 M 通过查看变换映射到 R(M-E)= RM- RE = RM + t 。因此,查看的最终4×4变换矩阵的确是:

     (sx sy sz tx)(sx sy sz -sE )
    L =(ux uy uz ty)=(ux uy uz -uE)
    (-fx -fy -fz tz)(-fx -fy -fz fE)
    0 1)(0 0 0 1)


所以当你写:


也就是说,我找不到相机向前映射到-Z
轴-Z轴映射到相机前进。


这是非常令人惊讶的,因为通过构造,看看变换图摄像机前进轴到-z轴。这个看看变换应该被认为是移动整个场景,以使照相机与标准原点/轴对齐,这是真正的工作。



使用您的2D示例:


通过使用GLM.lookAt的逻辑,我们应该能够将(1,1)映射到Y
使用由
第一列中的向前向量和第二列中的侧向量组成的2x2矩阵。


这是相反的,根据我描述的结构,你需要一个2x2矩阵,前向和行向量作为,而不是列映射(1,1),另一个向量到y和x轴。要使用矩阵系数的定义,您需要通过变换获得标准基本矢量的图像。这直接给出了矩阵的列。但是因为你正在寻找的是相反的(将你的向量映射到标准基本向量),你必须反转变换(转置,因为它是一个旋转)。然后,您的引用向量将成为,而不是列。


Firstly, if you would like an explanation of the GLM lookAt algorithm, please look at the answer provided on this question: http://stackoverflow.com/a/19740748/1525061

mat4x4 lookAt(vec3  const & eye, vec3  const & center, vec3  const & up)
{
vec3  f = normalize(center - eye);
vec3  u = normalize(up);
vec3  s = normalize(cross(f, u));
u = cross(s, f);

mat4x4 Result(1);
Result[0][0] = s.x;
Result[1][0] = s.y;
Result[2][0] = s.z;
Result[0][1] = u.x;
Result[1][1] = u.y;
Result[2][1] = u.z;
Result[0][2] =-f.x;
Result[1][2] =-f.y;
Result[2][2] =-f.z;
Result[3][0] =-dot(s, eye);
Result[3][1] =-dot(u, eye);
Result[3][2] = dot(f, eye);
return Result;
}

Now I'm going to tell you why I seem to be having a conceptual issue with this algorithm. There are two parts to this view matrix, the translation and the rotation. The translation does the correct inverse transformation, bringing the camera position to the origin, instead of the origin position to the camera. Similarly, you expect the rotation that the camera defines to be inversed before being put into this view matrix as well. I can't see that happening here, that's my issue.

Consider the forward vector, this is where your camera looks at. Consequently, this forward vector needs to be mapped to the -Z axis, which is the forward direction used by openGL. The way this view matrix is suppose to work is by creating an orthonormal basis in the columns of the view matrix, so when you multiply a vertex on the right hand side of this matrix, you are essentially just converting it's coordinates to that of different axes.

When I play the rotation that occurs as a result of this transformation in my mind, I see a rotation that is not the inverse rotation of the camera, like what's suppose to happen, rather I see the non-inverse. That is, instead of finding the camera forward being mapped to the -Z axis, I find the -Z axis being mapped to the camera forward.

If you don't understand what I mean, consider a 2D example of the same type of thing that is happening here. Let's say the forward vector is (sqr(2)/2 , sqr(2)/2), or sin/cos of 45 degrees, and let's also say a side vector for this 2D camera is sin/cos of -45 degrees. We want to map this forward vector to (0,1), the positive Y axis. The positive Y axis can be thought of as the analogy to the -Z axis in openGL space. Let's consider a vertex in the same direction as our forward vector, namely (1,1). By using the logic of GLM.lookAt, we should be able to map (1,1) to the Y axis by using a 2x2 matrix that consists of the forward vector in the first column and the side vector in the second column. This is an equivalent calculation of that calculation http://www.wolframalpha.com/input/?i=%28sqr%282%29%2F2+%2C+sqr%282%29%2F2%29++1+%2B+%28sqr%282%29%2F2%2C+-sqr%282%29%2F2+%29+1.

Note that you don't get your (1,1) vertex mapped the positive Y axis like you wanted, instead you have it mapped to the positive X axis. You might also consider what happened to a vertex that was on the positive Y axis if you applied this transformation. Sure enough, it is transformed to the forward vector.

Therefore it seems like something very fishy is going on with the GLM algorithm. However, I doubt this algorithm is incorrect since it is so popular. What am I missing?

解决方案

Have a look at GLU source code in Mesa: http://cgit.freedesktop.org/mesa/glu/tree/src/libutil/project.c

First in the implementation of gluPerspective, notice the -1 is using the indices [2][3] and the -2 * zNear * zFar / (zFar - zNear) is using [3][2]. This implies that the indexing is [column][row].

Now in the implementation of gluLookAt, the first row is set to side, the next one to up and the final one to -forward. This gives you the rotation matrix which is post-multiplied by the translation that brings the eye to the origin.

GLM seems to be using the same [column][row] indexing (from the code). And the piece you just posted for lookAt is consistent with the more standard gluLookAt (including the translational part). So at least GLM and GLU agree.

Let's then derive the full construction step by step. Noting C the center position and E the eye position.

  1. Move the whole scene to put the eye position at the origin, i.e. apply a translation of -E.

  2. Rotate the scene to align the axes of the camera with the standard (x, y, z) axes.

    2.1 Compute a positive orthonormal basis for the camera:

    f = normalize(C - E) (pointing towards the center)
    s = normalize(f x u) (pointing to the right side of the eye)
    u = s x f            (pointing up)
    

    with this, (s, u, -f) is a positive orthonormal basis for the camera.

    2.2 Find the rotation matrix R that aligns maps the (s, u, -f) axes to the standard ones (x, y, z). The inverse rotation matrix R^-1 does the opposite and aligns the standard axes to the camera ones, which by definition means that:

           (sx ux -fx)
    R^-1 = (sy uy -fy)
           (sz uz -fz)
    

    Since R^-1 = R^T, we have:

        ( sx  sy  sz)
    R = ( ux  uy  uz)
        (-fx -fy -fz)
    

  3. Combine the translation with the rotation. A point M is mapped by the "look at" transform to R (M - E) = R M - R E = R M + t. So the final 4x4 transform matrix for "look at" is indeed:

        ( sx  sy  sz tx )   ( sx  sy  sz -s.E )
    L = ( ux  uy  uz ty ) = ( ux  uy  uz -u.E )
        (-fx -fy -fz tz )   (-fx -fy -fz  f.E )
        (  0   0   0  1 )   (  0   0   0    1 )
    

So when you write:

That is, instead of finding the camera forward being mapped to the -Z axis, I find the -Z axis being mapped to the camera forward.

it is very surprising, because by construction, the "look at" transform maps the camera forward axis to the -z axis. This "look at" transform should be thought as moving the whole scene to align the camera with the standard origin/axes, it's really what it does.

Using your 2D example:

By using the logic of GLM.lookAt, we should be able to map (1,1) to the Y axis by using a 2x2 matrix that consists of the forward vector in the first column and the side vector in the second column.

That's the opposite, following the construction I described, you need a 2x2 matrix with the forward and row vector as rows and not columns to map (1, 1) and the other vector to the y and x axes. To use the definition of the matrix coefficients, you need to have the images of the standard basis vectors by your transform. This gives directly the columns of the matrix. But since what you are looking for is the opposite (mapping your vectors to the standard basis vectors), you have to invert the transformation (transpose, since it's a rotation). And your reference vectors then become rows and not columns.

这篇关于我对GLM lookAt函数的理解不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆