OpenGL坐标系是右手坐标系还是左手坐标系?

6

假设我在OpenGL ES 2.0程序中为模型视图转换矩阵使用单位矩阵。在这种情况下,坐标系是从(-1,-1,-1)到(1,1,1)的典型OpenGL坐标系。

这个坐标系是右手坐标系还是左手坐标系?

更广泛的问题是:是否有一份OpenGL文档可以列出API遵循的所有数学约定?

4个回答

8

永远记住!OpenGL只知道归一化显示坐标(NDC),而且它是左手坐标系!

OpenGL看起来是右手坐标系的幻象,是因为在固定管线中,固定函数是右手坐标系的,比如glOrtho(...)、glFrustrum(...)。所有这些函数在可编程管线时代都已经被弃用了。

OpenGL不关心你在中间矩阵处理中使用的坐标系。你可以使用任何轴坐标系,只要将其转换为NDC即可。

忘掉相机吧!

因为我们的屏幕是一个二维平面。想象一下,你的视口是一个黄色的橡皮正方形。将该正方形的四个角钉在NDC的-Z侧,就像这样:

A wireframe image of an orthonormal cube with corner vertices being all combinations of -1 and +1 in (X, Y, Z), with a visible origin/axes marker in its center that has +X pointing right, +Y pointing up, and +Z pointing away from the viewer, with the -Z cube side facing the viewer colored yellow to highlight it.

在NDC空间中,所有-Z轴上的顶点都在黄色橡胶正方形上,并定义它。然后将黄色橡胶平面拉伸以适应并显示在您的实际屏幕上。


7
规范视图体积,又称标准化设备坐标,是左手坐标系。可以通过传递恒等矩阵并绘制两个三角形来轻松测试此功能。
float points[] = { -1,  1,  -0.5,
                   -1, -1,  -0.5,
                    1, -1,  -0.5,

                    1,  1,   0.5,
                   -1, -1,   0.5,
                    1, -1,   0.5 };

"and looking at the results (with glEnable(GL_DEPTH_TEST))
所以你的顶点着色器将像这样:"
uniform mat4 mvp_mat;

// Incoming per vertex... position (fills in 1 for w if from vec3 buf)
layout (location = 0) in vec4 v_vertex;


void main(void) 
{ 
    // multiplying by identity doesn't transform the geometry
    gl_Position = mvp_mat * v_vertex;
}

或者你甚至可以像这样更简单地测试它,因为单位矩阵什么也不做。
layout (location = 0) in vec4 v_vertex;

void main(void) 
{
    //no transformation, no confusion, just straight to OpenGL
    gl_Position = v_vertex;
}

显然,您需要使三角形的颜色不同,以便您可以看到它们如何重叠。
此外,请参阅此帖子及其中的我的评论/问题:plus.google.com/114825651948330685771/posts/AmnfvYssvSe 我不知道所有错误信息都来自互联网甚至教科书。OpenGL默认情况下仅在涉及三角形绕组以确定前面(默认情况下为逆时针=右手)时才是正确的。世界空间、对象空间和眼睛空间不存在于OpenGL中,只存在于图形程序员中。OpenGL只接受点,剪辑任何位于规范化视图体积[-1,-1,-1] x [1,1,1]之外的内容,并将其转换为屏幕空间/窗口坐标,默认情况下为[0,w)x [0,h)x [0,1]。如果启用深度测试,则默认行为是向左手看去+z。
有几种方法可以解决OpenGL的左手性。大多数人在矩阵中处理它(尽管他们意识不到)。我认为您还可以使用glDepthFunc并将其设置为GL_GREATER来更改它。

http://www.opengl.org/sdk/docs/man3/xhtml/glDepthFunc.xml

进一步证明它是左手坐标系的证据在这里:http://www.opengl.org/sdk/docs/man3/xhtml/glDepthRange.xml “在剪切和除以w之后,深度坐标范围从-1到1,对应于近和远裁剪平面”,即正z向屏幕内部=左手坐标系。您还可以使用DepthRange将其更改为右手坐标系行为。
编辑:针对Bob Cross的坚持认为我错了,这里有一个单个源文件程序,显示我是正确的。 https://github.com/rswinkle/opengl_reference/blob/master/src/left_handed.c 您可以在README中看到截图:https://github.com/rswinkle/opengl_reference 最终编辑:2020年9月,我发布了PortableGL。如果有人想要查看OpenGL管线的内部/数学细节,并且作为我知道自己在谈论什么的证据,请访问http://portablegl.com/

哇!!!这是一个非常好的解释。所以尽管一些矩阵数学可能已经弥补了错误的假设,但我的东西仍然是错的。 - praveen
谢谢。你知道我们程序员,如果看起来运行正常,那么它是如何运行的并不重要。哈。但实际上,我添加了Google+主题的链接,以展示混淆问题的另一个方面。整个行优先与列优先的争论更加混淆了问题。 - rswinkle
抱歉,这是我第一次真正使用StackOverflow。我的意思是上面的评论应该还有更多内容,但是我按了回车键,然后发现在5分钟之后就无法编辑了。不管怎样,我会让它休息一下,但OpenGL的左右手坐标系和矩阵行列优先级的问题一直是我非常反感的事情。 - rswinkle
嘿,Praveen,我知道已经过去了将近一年,我应该当时就问你的,但是你能否更改被接受的答案呢?或者在Bob的评论中提醒他回复我的答案?我不想编辑他的帖子,也没有足够的声望在他的帖子下评论。 - rswinkle
我已经修改了我的示例程序,使其更简单/更清晰,并且它应该可以在任何地方编译和运行。我在代码的注释中包含了使用gcc(或clang)编译它的Linux命令。此外,它现在是一个带有premake的repo的一部分,因此您可以使用它来为任何IDE /平台生成项目。一个漂亮的截图也展示了输出结果。 - rswinkle
显示剩余2条评论

6
我的问题是,这个坐标系是右手坐标系还是左手坐标系?
默认情况下,OpenGL总是使用右手坐标系。您可以通过观察自动法线创建来验证这一点。您可以强制指定每个点的左手法线创建,但通常情况下,都遵循右手规则。有关OpenGL仅支持右手坐标系的更多讨论,请参见OpenGL FAQ中的9.150节
关于API遵循的所有数学约定,您的问题不太清楚。这里使用基本的线性代数,并且非常注重矩阵数学和线性变换。
编辑以回应评论问题:
请记住,如果您使用统一矩阵调用而不是旧的glRotates等,则必须指定您使用的是行主序还是列主序矩阵。在这种情况下(从评论中提到的代码),需要注意。
glUniformMatrix4fv(uniforms[UNIFORM_MVP], 16, GL_FALSE, mvpMatrixZRotation);

在这个调用中,GL_FALSE表示这是一个列主矩阵,因此旋转的结果将是预期的转置。因此,旋转将被反转,看起来像一个左手坐标系。
将其更改为GL_TRUE,一切都会好起来。
以下是来自OpenGL讨论板的非常简单的示例,与此特定主题相关。 针对评论请求的另一个编辑:这是OpenGL矩阵管道的另一个详细解释。请注意带有三个轴的GL_MODELVIEW图表:它们说明了右手坐标系。上述FAQ中的引用仍然适用。

@BobCross 你好,Bob。我正在尝试学习iOS上的OpenGL ES。我相信规范视图体积具有左手坐标系。我的程序代码可以在这里找到:[链接](http://pastie.org/1628587)。[要尝试此代码,请将iOS OpenGL模板项目中由XCode生成的渲染函数替换为此函数] 鉴于角度是正的且系统是右手的,旋转应该发生在逆时针方向。与此相反,旋转发生在顺时针方向。 - praveen
@bobcross 你好Bob,我在发表评论之前阅读了你的编辑和链接。我的代码将旋转矩阵作为列主元,并且因此转置参数应该是GL_False。 - praveen
我认为你的帖子对OpenGL坐标系统有一些误解。只有NDC是左手坐标系。无论你使用什么坐标进行中介转换都是适用的。你可以在逻辑坐标中使用左手或右手世界空间,然后手动将其镜像到NDC。 - ZK_
@zk_,你想要说明什么问题还不太清楚。你认为我有什么误解?我没有回答到原帖中的哪一部分问题? - Bob Cross
@ZK_,你的意思是说我漏掉了“默认情况下”这个短语?它们在第一句话中。此外,在右手坐标系下,Z轴指向你的眼睛。在转换管道中间切换坐标系是不推荐的。 - Bob Cross
显示剩余8条评论

2

Opengl ES坐标系实际上是右手坐标系,包括规范化体积从(-1,-1,-1)到(1,1,1)。我已经通过代码进行了验证。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接