如何将本地对象坐标转换为世界坐标?

11

我需要一种简单的方法将我的对象坐标转换为世界坐标,以便我可以在该坐标系中定位它们并进行碰撞检测?


我建议阅读关于线性代数或矩阵代数的内容,以及一本有关图形学的书籍。 - Thomas Matthews
2个回答

30
首先,一些背景知识。在3D图形中,需要考虑几个向量空间:
  • 模型空间 - 通常是您指定给OpenGL的坐标
  • 世界空间 - 坐标是相对于世界中某个中心点指定的。
  • 视图空间 - 坐标是相对于相机指定的。
  • 投影空间 - 屏幕上的所有内容都适合每个维度上的区间[-1, +1]
坐标是通过齐次方式指定的,因此每个向量都具有分量(x,y,z,w),其中w是一个缩放因子。您可以将三维空间中的坐标获取为(x/w, y/w, z/w)。缩放因子对于某些转换(如透视投影)是必需的,在非齐次坐标中无法实现。
需要使用4x4矩阵将坐标从一个向量空间转换到另一个向量空间。您可能会有三个不同的矩阵:
  • 模型矩阵(模型到世界)
  • 视图矩阵(世界到视图)
  • 投影矩阵(视图到投影空间)
您可以使用以下公式将坐标C投影到屏幕上:
C' = P * V * M * C

OpenGL内部维护两个矩阵:modelview(模型和视图相乘)和投影。还有一个我们不需要担心的纹理矩阵。当你调用glMatrixMode时,你在这些矩阵之间切换。你可以使用glLoadIdentity将当前矩阵替换为单位矩阵。你可以使用像glTranslatefglRotatefgluProjection这样的函数对当前矩阵应用变换。每个这样的函数只是创建一个实现特定变换的4x4矩阵,然后将当前矩阵乘以它。你可以在OpenGL 2.1参考页面中查看变换矩阵。


现在是实际答案。你需要为场景中的每个对象维护一个4x4模型矩阵。模型矩阵将包含所有所需的变换,以将模型坐标转换为世界坐标。例如,每次调用glTranslate时,你都会更新你的模型矩阵:

T  = [ 1 0 0 x ]
     [ 0 1 0 y ]
     [ 0 0 1 z ]
     [ 0 0 0 1 ]
M' = M * T

然后,您可以使用模型矩阵将坐标转换到世界空间(首先确保它们是齐次坐标;如果不是,请设置w = 1):

V' = V * M

由于您正在同时维护这些转换,因此您实际上不再需要维护OpenGL模型视图矩阵。您可以将您的模型矩阵作为uniform传递给着色器。您可以以类似的方式维护自己的视图和投影矩阵。这在最近的OpenGL版本中是必需的;所有矩阵处理函数都已过时。


@Shazad,添加了一些背景信息和更详细的解释。希望有所帮助。 - Jay Conrod
@Jay:首先你说 C' = P * V * M * C,但是在最后你又说 V' = M * V。我有点困惑,因为一次是 V * M,一次是 M * V。矩阵乘法不满足交换律,所以 A * B != B * A。你的答案中可能有一个顺序是错误的吗?也许我的数学有问题,如果是这样,请随时纠正我。 - Mecki
@Mecki,是的,看起来像是笔误。谢谢你指出来。现在已经修正了。 - Jay Conrod
1
杰伊,我的点赞将你带到了神奇的一万大关,恭喜啊! - johnbakers

6
您可以使用虚拟相机视图矩阵的逆矩阵(V-1)乘以物体的模型视图矩阵(V*M)来获得世界坐标。
在gluLookAt()函数后,您可以使用以下代码获取V:
glGetFloatv(GL_MODELVIEW_MATRIX, camViewMatrix)
然后反转矩阵并存储它(用于后面的矩阵乘法)。
在绘制物体之前,您可以使用相同的GL函数获取V*M,即在所有glTranslatef()、glRotatef()和glScale()命令之后:
glGetFloatv(GL_MODELVIEW_MATRIX, objectsModelViewMatrix); V-1 * ( V * M ) == M 然后将两个矩阵相乘,结果矩阵包含位置,m12 = x,m13 = y和m14 = z。
更多详细信息和C代码请参见: https://sourceforge.net/p/openantz/wiki/Local_to_World_Coordinates/

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