OpenGL 方向。 (从负 z 看的身份旋转)

Posted

技术标签:

【中文标题】OpenGL 方向。 (从负 z 看的身份旋转)【英文标题】:OpenGL orientation. (Identity rotation looking in negative z) 【发布时间】:2012-02-25 23:01:28 【问题描述】:

我正在实现一个渲染器来处理每个翻译-/视图-/模型-/投影-矩阵(我不使用 glRotate/glTranslate 等)。

我已经在正 z 轴上放置了几个蓝色对象,在正 x 轴上放置了一些红色对象(所以我应该能够看到我左边的红色对象和前面使用我的身份旋转的蓝色对象相机)。是右手方向吧?

问题是我必须绕 y 轴转动 180 度才能看到我的对象。它显示为身份旋转正在查看 -z。

我通过取相机矩阵 [Rot Tr] 的逆来构造我的视图矩阵,然后我将它按列放入数组中并将其传递给我的着色器。

对于对象(世界矩阵),我只是将矩阵 [Rot Tr] 按列传递给着色器。我应该否定翻译吗?

投影矩阵现在是在顶点着色器中构建的,因为我正在努力。正如你在下面看到的那样,我正在做

position = proj*view*model*gl_Vertex;

目前我使用 gl_Vertex(我在加载单位矩阵作为我的场景对象后使用 glutSolidCube)。

uniform mat4 view;
uniform mat4 model;

varying vec4 pos;

void main()
   

pos = gl_Vertex;


float aspect = 1.0;
float fovy = 1.5;
float f = 1.0 / tan(fovy * 0.5);
float near = 1.0;
float far = 100.0;
float tt = 1.0 / (near - far);

mat4 proj = mat4(f/aspect, 0.0, 0.0, 0.0,
        0.0, f, 0.0, 0.0,
        0.0, 0.0, (near+far)*tt, -1.0,
        0.0, 0.0, 2.0*near*far*tt, 0.0);

gl_Position = proj * view * model * pos;

在我的片段着色器中,我设置了 color = pos 以便我可以看到轴的颜色并且颜色看起来是正确的。我认为对象已正确放置在场景中,但使用恒等矩阵作为旋转,我仍在寻找相反的方向。

我可能错过了什么?我是否以正确的方式传递了正确的矩阵?

【问题讨论】:

【参考方案1】:

右手坐标系总是向下看 -Z 轴。如果 +X 向右,+Y 向上(这就是 所有 OpenGL 的工作方式),并且视图与 Z 轴对齐,那么 +Z 必须 观众。如果视图向下看 +Z 轴,则空间将是左撇子。

【讨论】:

好吧,我明白了。谢谢。但这需要注意很多,例如我必须在 vec 前面添加减号: vec3 Transformable::getLocalFront() return -vec3(rot.c, rot.f, rot.i); 【参考方案2】:

问题是我必须绕 y 轴转动 180 度才能看到我的对象。它显示为身份旋转正在查看 -z。

是的。以 OpenGL 的形式为 glOrtho 和 glFrustum 提供的坐标系是右手的(用右手,让拇指向右,食指向上,然后食指将指向您)。如果您根据这些对矩阵计算进行建模,那么您也会得到一个右手系统。

【讨论】:

从技术上讲,它不是默认坐标系。这只是他的透视矩阵所期望的坐标系。 @NicolBolas:我在考虑实际的 OpenGL 默认值,即一直到 NDC 空间的身份转换、glDepthRange(0.0, 1.0) 和 glDepthFunc(GL_LESS)。只要投影不包含奇数轴上的否定,它就会保持这种惯用手。 如果是这种情况,则恒等式变换通过 NDC 空间和视口给出一个手坐标系。窗口空间 +X 向右,+Y 向上。 +Z 向前。那是左撇子。 OpenGL 仅使用右手空间,因为 glFrustumgluPerspective 矩阵(大多数人都复制,就像 OP 在这里所做的那样)明确否定 Z。 @NicolBolas:你当然是对的,我的错……为了清楚起见,我调整了我的答案。【参考方案3】:

好吧,昨晚完全重写了这篇文章,如果你还没有想出自己的解决方案或提出类似问题的其他人,我希望你会发现它很有用。

默认情况下,您的前向矢量向下看 -Z,右向矢量向下看 +X,向上矢量向下看 +Y。

当您决定构建您的世界时,如果您有一个 128x128 X,Z 世界并且您位于 64x64 的中间位置,那么您看哪里并不重要,任何玩家怎么会知道他们旋转了 0 度或 180 度.他们根本不会。

现在你提到你不喜欢 glRotatef 和 glTranslatef。我也不会使用处理向量和矩阵数学的方法。首先,我使用一种方法来跟踪向前、向上和向右向量。所以想象你自己在一个圆圈里旋转,这是你在旋转你的前向向量。因此,当玩家想要让我们说直奔前行。您将沿着前向矢量的 X、Z 移动它们,但假设它们也想向右扫射。好吧,你仍然会沿着前向矢量移动它们,但想象一下从前向矢量上移开 90 度。因此,如果我们面对 45 度角,我们将指向 -Z 和 -X 象限。所以扫射会使我们进入 -Z 和 +X 象限。为此,您只需否定 sin 值。下面是两个例子,但是这可以做不同的事情,下面是一个粗略的例子,可以更好地解释上面的内容。

Position.X -= Forward.X; //Run Forward.
Position.Z -= Forward.Z;

Position.X += Forward.Z; //Run Backwards.
Position.Z += Forward.Z 

Position.X += Forward.X; //Strafe Right.
Position.Z -= Forward.Z;

Position.X -= Forward.X; //Strafe Left.
Position.Z += Forward.Z;

下面是我如何初始化我的视图矩阵。这些只能执行一次,不要将其放入任何循环代码中。

glMatrixMode(GL_MODELVIEW);

view_matrix[4] =  0.0f; //UNUSED.

view_matrix[3] =  0.0F; //UNUSED. 
view_matrix[7] =  0.0F; //UNUSED. 
view_matrix[11] = 0.0F; //UNUSED. 
view_matrix[15] = 1.0F; //UNUSED.

update_view();
glLoadMatrix(view_matrix);

然后这是 update_view() 方法。这只能在视图矩阵更改期间调用。

public void update_view()

    view_matrix[0] =  Forward[0];
    view_matrix[1] =  Up[1] *  Forward[1];
    view_matrix[2] =  Up[0] * -Forward[1];

    view_matrix[5] =  Up[0];
    view_matrix[6] =  Up[1];

    view_matrix[8] =  Forward[1];
    view_matrix[9] =  Up[1] * -Forward[0];
    view_matrix[10] = Up[0] *  Forward[0];

位置向量是矩阵 [12]、[13] 和 [14] 并且被否定。您可以选择存储这些或仅使用矩阵[12]、[13]、[14] 作为位置向量。

view_matrix[12] =  -Position.x;
view_matrix[13] =  -Position.y;
view_matrix[14] =  -Position.z;

【讨论】:

以上是关于OpenGL 方向。 (从负 z 看的身份旋转)的主要内容,如果未能解决你的问题,请参考以下文章

Opengl es Android 3D 手指触控旋转object

Three.js:获取相机正在看的方向

Opengl模型矩阵在旋转一圈后不绕原点旋转

如何在 OpenGL 中围绕 Z 轴中心旋转对象?

旋转轴重映射?

OpenGL在给定方向上的旋转