如何在OpenGL 3.x中翻译单个对象?

16
我有一定的OpenGL 2编程经验,现在想学习使用OpenGL 3。为此,我购买了Addison Wesley出版社的“红皮书”和“橙皮书”(GLSL),这些书介绍了弃用固定功能和新的可编程管线(着色器)。但是,我无法理解如何在不使用弃用的translate*、rotate*和scale*函数的情况下构建具有多个对象的场景。
在OGL2中,我使用translate和rotate函数在三维空间中进行移动,并使用glBegin…glEnd在本地坐标系中创建对象。在OGL3中,这些函数都已被弃用,并且据我所知,被着色器取代。但是,我不能为每个对象调用一个着色器程序,这样不会影响其他对象吗?
我不确定是否已经对我的问题做出了满意的解释,但问题的核心是如何在OpenGL 3.1中以本地坐标定义多个对象的场景。我找到的所有初学者教程只使用单个对象,并没有解决这个问题。
编辑:想象一下你想要两个旋转的立方体。手动修改每个顶点坐标将是一件麻烦的事情,而且你不能简单地修改模型视图矩阵,因为那样只会使相机绕着两个静态立方体旋转...
2个回答

20

让我们从基础知识开始。

通常,您希望通过以下步骤转换本地三角形顶点:

本地坐标 -> 世界坐标 -> 视图坐标 -> 裁剪坐标

在标准的GL中,前两个变换是通过GL_MODELVIEW_MATRIX完成的,第三个变换是通过GL_PROJECTION_MATRIX完成的。

对于我们通常想要应用的许多有趣的变换(例如平移、缩放和旋转),这些模型视图变换恰好可以在齐次坐标中表示为向量矩阵乘法。通常,顶点V =(x,y,z)在该系统中表示为(x,y,z,1)

好的。假设我们想通过平移、旋转和平移来转换一个顶点V_local。每个变换都可以表示为一个矩阵*,让我们称它们为T1、R1、T2。我们要将变换应用于每个顶点:V_view = V_local * T1 * R1 * T2。由于矩阵乘法是可交换的,我们可以一次计算出M = T1 * R1 * T2

这样,我们只需要将M传递给顶点程序,并计算V_view = V_local * M。最终,典型的顶点着色器将顶点位置乘以一个单独的矩阵。计算该矩阵的所有工作都是将对象从局部空间移动到裁剪空间的方法。

好的...我忽略了许多重要的细节。

首先,到目前为止我描述的只涵盖了我们通常想要在视图空间之上进行的变换,而不是剪裁空间。然而,硬件期望顶点着色器的输出位置以那个特殊的剪裁空间表示。很难用简单的语言解释剪裁空间坐标,所以我会把它留出来,但重要的是,将顶点带到那个剪裁空间的变换通常可以表示为相同类型的矩阵乘法。这就是旧的gluPerspective、glFrustum和glOrtho计算的内容。

其次,这是应用于顶点位置的内容。变换法线的数学方法有些不同。那是因为你希望法线在变换后仍然垂直于表面(作为参考,一般情况下需要通过模型视图的逆转置乘法来实现,但在许多情况下可以简化)

第三,你从不将4D坐标发送到顶点着色器。通常你传递3D坐标。OpenGL将转换这些3D坐标(或2D),使得顶点着色器不必添加额外的坐标。它扩展每个顶点以添加1作为w坐标。

所以...要将所有这些内容重新组合起来,对于每个对象,你需要根据你想要应用于该对象的所有变换计算那些神奇的M矩阵。在着色器内部,你需要将每个顶点位置乘以该矩阵,并将其传递给顶点着色器的位置输出。典型的代码大致如下(这是使用旧术语):

mat4 MVP;
gl_Position=MVP * gl_Vertex;

* 实际的矩阵可以在网络上找到,特别是在每个函数的 man 页面上:rotatetranslatescaleperspectiveortho


1
非常感谢您提供如此详尽的答案!我之前忽略了一个细节,就是在调用glDrawElements之间可以更改MVP矩阵(例如声明为uniform)...不过,Khronos让程序员自己来规定这些非常常见的矩阵,这个决定有点奇怪。希望它们能够很快地被整合到glu或类似的库中... - Wonko
这就是中间件的作用。GL3.2对于快速编码来说表现不够充分。但是之前的版本在实际应用中抽象层次过高了。它需要一个状态管理框架来支持它。 另外,假设你想要保留矩阵。那么驱动程序必须保留所有矩阵堆栈,如何将它们传递给所有需要它们的着色器(不仅仅是顶点),找出你需要的类型 - M、MV、MVP、IT(MV)、IT(M)。最糟糕的部分?只有应用程序可以通过一次运行多个矩阵操作来使数学更有效率。GL无法高效地完成这项工作。 - Bahbar

1

这些函数显然已经被弃用,但从技术上讲仍然完全可用,而且确实可以编译。因此,您肯定仍然可以使用translate3f(...)等函数。

然而,这个教程很好地解释了新的着色器等工作原理,以及如何在空间中处理多个对象。

您可以创建x个顶点数组,并将它们绑定到x个VAO对象中,然后使用着色器等渲染场景...嗯,最好还是阅读一下 - 这是一个真正好的阅读材料,可以掌握新概念。

此外,OpenGL 'Red Book'有一个新版本 - 学习OpenGL 3.0和3.1的官方指南。其中包括“关于OpenGL废弃机制的讨论以及如何验证您的程序是否适用于未来版本的OpenGL”。

希望这对您有所帮助!


再次感谢您的快速回复。我已经阅读了您提到的教程,但是尽管他创建了两个三角形,但他是在全局坐标系下创建它们的,而不是像我想要的那样在本地坐标系下创建。问题在于,当您拥有一个更复杂的模型时,如果该模型移动,使用全局坐标系可能会很麻烦。此外,我想从.obj文件中加载一个预制对象,并将其放置在3D空间中的某个位置。 - Wonko
8
第一个链接失效了。 - Jeff

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