【问题标题】:Confused about OpenGL transformations对OpenGL转换感到困惑
【发布时间】:2012-11-04 20:48:07
【问题描述】:

在opengl中有一个原点为(0,0,0)的世界坐标系。

让我感到困惑的是,所有的转换,如 glTranslate、glRotate 等都是做什么的?他们移动吗 世界坐标中的物体,还是它们移动相机?如您所知,相同的运动可以通过移动物体或相机来实现。

我猜是glTranslate,glRotate,改变物体,gluLookAt改变相机?

【问题讨论】:

  • 为什么要猜?阅读文档。
  • 顺便说一句,OpenGL 并不特定于 C++(甚至 C),所以我删除了 C++ 标签。

标签: opengl


【解决方案1】:

在opengl中有一个原点为(0,0,0)的世界坐标系。

嗯,技术上没有。

让我困惑的是 glTranslate、glRotate 等所有转换都做了什么?它们是在世界坐标中移动对象,还是移动相机?

两者都没有。 OpenGL 不知道对象,OpenGL 不知道相机,OpenGL 不知道世界。 OpenGL 关心的只是图元、点、线或三角形、每个顶点的属性、标准化设备坐标 (NDC) 和 NDC 映射到的视口。

当您告诉 OpenGL 绘制图元时,每个顶点都会根据其属性进行处理。位置是属性之一,通常是在局部“对象”坐标系中具有 1 到 4 个标量元素的向量。手头的任务是以某种方式将局部顶点位置属性转换为视口上的位置。在现代 OpenGL 中,这发生在一个小程序中,在 GPU 上运行,称为 顶点着色器。顶点着色器可以以任意方式处理位置。但通常的方法是应用一些非奇异的线性变换。

这样的变换可以用同质变换矩阵来表示。对于 3 维向量,4 个元素的向量中的齐次表示,其中第 4 个元素为 1。

在计算机图形学中,三重转换管道已成为一种标准的做事方式。首先将对象局部坐标转换为相对于虚拟“眼睛”的坐标,从而进入眼睛空间。在 OpenGL 中,这种转换曾经被称为 modelview 转换。对于眼睛空间中的顶点位置,可以进行多种计算,例如照明可以以广义方式表示,因此这些计算发生在眼睛空间中。接下来,眼睛空间坐标被转换为所谓的剪辑空间。这种变换将眼睛空间中的一些体积映射到具有特定边界的特定体积,几何图形被裁剪到该特定体积。由于这种转换有效地应用了投影,因此在 OpenGL 中这曾经被称为 projection 转换。

在剪辑空间之后,位置被它们的同质分量“归一化”,产生归一化的设备坐标,然后简单地映射到视口。

总结一下:

一个顶点位置由局部变换到裁剪空间

vpos_eye  = MV · vpos_local
eyespace_calculations(vpos_eye);
vpos_clip =  P · vpos_eye

·: inner product column on row vector

然后到达NDC

vpos_ndc = vpos_clip / vpos_clip.w

最后到视口(NDC 坐标在 [-1, 1] 范围内)

vpos_viewport = (vpos_ndc + (1,1,1,1)) * (viewport.width, viewport.height) / 2 + (viewport.x, viewport.y)

*: vector component wise multiplication

OpenGL 函数 glRotate、glTranslate、glScale、glMatrixMode 仅操作变换矩阵。 OpenGL曾经有四个变换矩阵:

  • 模型视图
  • 投影
  • 质地
  • 颜色

可以使用 glMatrixMode 设置矩阵操作函数作用于哪一个。每个矩阵操作函数通过乘以它们在选择矩阵顶部描述的变换矩阵来组成一个新矩阵,从而替换它。 glLoadIdentity 函数将当前矩阵替换为恒等式,glLoadMatrix 将其替换为用户定义的矩阵,glMultMatrix 在其上乘以用户定义的矩阵。


那么模型视图矩阵如何模拟对象放置和相机。好吧,正如你已经说过的

如您所知,相同的运动可以通过移动物体或相机来实现。

您无法真正区分它们。通常的方法是将对象局部到眼睛的转换分为两个步骤:

  • 对象到世界 - OpenGL 称之为“模型转换”
  • 世界观 - OpenGL 将此称为“视图变换”

它们一起形成模型视图,在 modelview 矩阵描述的固定函数 OpenGL 中。现在因为转换的顺序是

  1. 本地到世界,M模型矩阵vpos_world = M · vpos_local
  2. 世界观,V查看矩阵vpos_eye = V · vpos_world

我们可以替换为

vpos_eye = V · ( M · vpos_local ) = V · M · vpos_local

V · M替换为ModelView矩阵=: MV

vpos_eye = MV · vpos_local

因此,您可以看到复合矩阵 M 的 V 和 M 仅取决于您乘以模型视图矩阵的操作顺序,以及您决定在哪一步“从这里将其称为模型变换开”。

即紧接着

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

视图已定义。但在某些时候,您将开始应用模型转换,之后的一切都是模型。


请注意,在现代 OpenGL 中,所有矩阵操作函数都已被删除。 OpenGL 的矩阵堆栈从来都不是完整的功能,也没有真正的应用程序真正使用过它。大多数程序只是glLoadMatrix-ed 自己计算的矩阵,并没有打扰 OpenGL 内置的矩阵操作例程。

自从引入着色器后,整个 OpenGL 矩阵堆栈就变得难以使用,说得好听点。

结论:如果您打算以现代方式使用 OpenGL,请不要打扰内置函数。但请记住我写的内容,因为您的着色器所做的将与 OpenGL 的固定函数管道所做的非常相似。

【讨论】:

    【解决方案2】:

    OpenGL是一个低级API,在“场景”中没有“物体”和“相机”这样的高级概念,所以只有两种矩阵模式:MODELVIEW(“相机”的乘积)矩阵由“对象”变换)和 PROJECTION(从世界空间到后透视空间的投影变换)。

    “模型”和“视图”(对象和相机)矩阵之间的区别取决于您。 glRotate/glTranslate 函数只是将当前选择的矩阵乘以给定的矩阵(甚至不区分 ModelView 和 Projection)。

    【讨论】:

      【解决方案3】:

      这些函数乘以(转换)glMatrixMode() 设置的当前矩阵,因此它取决于您正在处理的矩阵。 OpenGL有4种不同类型的矩阵; GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE 和 GL_COLOR,这些函数中的任何一个都可以更改这些矩阵中的任何一个。因此,基本上,您不会转换对象,而只是操纵不同的矩阵来“伪造”这种效果。

      请注意,glulookat() 只是一个方便的函数,相当于平移后跟一些旋转,没有什么特别之处。

      【讨论】:

        【解决方案4】:

        所有的变换都是对对象的变换。甚至 gluLookAt 也只是一种变换对象,就好像相机就在你告诉它的位置一样。从技术上讲,它们是顶点上的变换,但这只是语义。

        【讨论】:

          【解决方案5】:

          没错,glTranslate、glRotate 在渲染前改变物体坐标,gluLookAt 改变相机坐标。

          【讨论】:

            猜你喜欢
            • 2021-11-28
            • 1970-01-01
            • 1970-01-01
            • 2018-08-30
            • 2016-05-27
            • 2017-09-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多