【问题标题】:How do I translate single objects in OpenGL 3.x?如何在 OpenGL 3.x 中翻译单个对象?
【发布时间】:2009-10-28 16:11:56
【问题描述】:

我有一些编写 OpenGL 2 应用程序的经验,并且想学习使用 OpenGL 3。为此,我购买了 Addison Wesley 的“红皮书”和“橙皮书”(GLSL),它们描述了已弃用固定功能和新的可编程管道(着色器)。但我无法掌握的是如何在不使用已弃用的 translate*、rotate* 和 scale* 函数的情况下构建包含多个对象的场景。

我过去在 OGL2 中所做的是使用 translate 和 rotate 函数在 3D 空间中“移动”,并使用 glBegin ... glEnd 在本地坐标中创建对象。在 OGL3 中,这些函数都已被弃用,据我所知,它们已被着色器取代。但是我不能为我制作的每一个对象调用一个着色器程序,可以吗?这不会影响所有其他对象吗?

我不确定我是否对我的问题进行了令人满意的解释,但它的核心是如何在 OpenGL 3.1 中使用本地坐标中定义的多个对象对场景进行编程。我发现的所有初学者教程都只使用一个对象并且没有/解决这个问题。

编辑:想象一下你想要两个旋转的立方体。手动修改每个顶点坐标会很痛苦,而且你不能简单地修改模型视图矩阵,因为那样会围绕两个静态立方体旋转相机......

【问题讨论】:

    标签: opengl


    【解决方案1】:

    让我们从基础开始。

    通常,您希望通过以下步骤来变换局部三角形顶点:

    local-space coords-> world-space coords -> view-space coords -> clip-space coords

    在标准 GL 中,前 2 个转换是通过 GL_MODELVIEW_MATRIX 完成的,第三个是通过 GL_PROJECTION_MATRIX 完成的

    当我们在homogeneous coordinates 中表示顶点时,对于我们通常想要应用的许多有趣的转换(例如平移、缩放和旋转),这些模型视图转换恰好可以表示为向量矩阵乘法.通常,顶点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 计算的内容。

    其次,这是您应用于顶点位置的方法。转换法线的数学有些不同。那是因为您希望法线在变换后保持垂直于表面(作为参考,在一般情况下,它需要乘以模型视图的反转置,但在许多情况下可以简化)

    第三,您永远不会将 4-D 坐标发送到顶点着色器。一般来说,你会通过 3-D 的。 OpenGL 会将这些 3-D 坐标(或 2-D,顺便说一句)转换为 4-D 坐标,这样顶点着色器就不必添加额外的坐标。它扩展每个顶点以添加 1 作为w 坐标。

    所以...要将所有这些重新组合在一起,对于每个对象,您需要根据要应用于对象的所有变换来计算那些神奇的 M 矩阵。在着色器内部,您必须将每个顶点位置乘以该矩阵并将其传递给顶点着色器位置输出。典型代码或多或少(这是使用旧命名法):

    mat4 MVP;
    gl_Position=MVP * gl_Vertex;
    

    * 实际矩阵可以在网络上找到,尤其是在每个函数的手册页上:rotatetranslatescaleperspectiveortho

    【讨论】:

    • 感谢您的详尽回答!我错过的一个细节是,您可以在调用 glDrawElements 之间更改 MVP 矩阵(例如,声明它是统一的)......虽然奇怪的是,从 khronos 将这些非常常见的矩阵的规范留给了程序员。希望他们能尽快找到进入 glu 或类似领域的方法......
    • 这就是中间件的用途。 GL3.2 对于快速编码的表现力较差。但无论如何,以前的版本对于实际应用程序的抽象级别是错误的。它需要一个状态管理框架。另外,假设您要保留矩阵。这意味着驱动程序必须保留所有矩阵堆栈,如何将它们仅传递给需要它的 所有 着色器(不仅仅是顶点),弄清楚你需要哪种风格 - M、MV、MVP、IT (MV),它(M)。最糟糕的部分?该应用程序是唯一可以通过一次运行许多矩阵运算来提高数学效率的应用程序。 GL 无法有效地做到这一点。
    【解决方案2】:

    这些函数显然已被弃用,但在技术上仍然可以完美运行,并且确实可以编译。所以你当然仍然可以使用 translate3f(...) 等函数。

    但是,this tutorial 很好地解释了新着色器等如何工作,以及空间中的多个对象。

    您可以创建 x 个顶点数组,并将它们绑定到 x 个 VAO 对象中,然后使用着色器等从那里渲染场景......嗯,您更容易阅读它 - 这是一个非常好的阅读掌握新概念。

    此外,所谓的 OpenGL“红皮书”有一个新版本 - The Official Guide to Learning OpenGL, Versions 3.0 and 3.1。它包括“关于 OpenGL 的弃用机制以及如何验证您的程序以适应 OpenGL 未来版本的讨论”。

    希望对你有所帮助!

    【讨论】:

    • 再次感谢您的快速回答。我已经阅读了您提到的教程,但是尽管他创建了两个三角形,但他在全局坐标中创建了它们-而不是我想要的局部坐标。问题是当您有一个更复杂的模型时,使用全局坐标可能会很麻烦,尤其是在模型移动的情况下。另外,我想从 .obj 文件加载预制对象并将其放置在 3D 空间中的某个位置。
    • @Mark 第一个链接坏了。
    猜你喜欢
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-24
    • 2016-05-10
    • 2019-03-11
    • 2017-07-04
    相关资源
    最近更新 更多