在 OpenGL 中导航超球体的表面

Posted

技术标签:

【中文标题】在 OpenGL 中导航超球体的表面【英文标题】:Navigating though the surface of a hypersphere in OpenGL 【发布时间】:2011-02-28 21:01:13 【问题描述】:

也许这适合 math.stackexchange.com,但由于我是在 OpenGL 中编程的,所以我会在这里问它。

我有一个宇宙飞船游戏的想法,其中世界被限制在 4-D 超球体(也称为 3 球体)的表面。因此,从内部看,它看起来像一个 3-D 世界,但通过向各个方向导航,我永远不会离开 3-sphere 的有限体积。

为了将 3-shpere 表示为“平面”3-D 空间,我使用了立体投影,它作为 GLSL 着色器实现起来非常简单,只需将输入向量除以 1 减去其 w 坐标即可。

为了表示对象的顶点,我使用了标准化的 4d 向量,例如 x²+y²+z²+w²=1,从而将它们保持在 3 球体内。

首先要解决的问题是旋转。但我很快发现普通的 3d 旋转矩阵足以在 3d 投影中围绕观察者旋转世界,因为它不会与 w 坐标混淆(就像围绕 z 轴旋转球体也会旋转它立体投影)。

然后我发现沿 w 轴旋转相当于在 3d 投影内平移(只是不可交换,就像在“平面”空间上的普通 3d 平移),然后我可以通过使用简单的环绕来沿轴平移轴旋转矩阵 (x', y') = (x * cos a - y * sin a, x * sin a + y * cos a),但 w 随另一个轴变化。

到目前为止,我无法根据观看者在投影中所面对的位置来确定如何向前导航。我可以应用逆变换来导出观看者在超球面坐标中面对的归一化 4-D 向量(称为 F),但我不知道如何使用 4x4 矩阵在该方向上导航(在 OpenGL 中是最佳的)。我可以考虑一个骇人听闻的解决方案:对于每个顶点 V,做 V' = normalize(d*F + V),其中 d 是向前移动的距离(在某些奇怪的单位中,我不能完全精确)。这种方式只适用于较小的 d 值,d 与角度变化之间没有直接关系。

因此问题是:如何在 4-D 超球面的表面上前进(使用 4x4 矩阵变换)?

【问题讨论】:

您能否参考一下您的 Hypersphere 的数学描述? 就像我说的,它只是 x²+y²+z²+w²=1 @ivella 刚刚出现在您的 QA 中,请参阅 How to use 4d rotors 和 Understanding 4x4 homogenous transform matrices。翻译只是将前向向量添加到位置(矩阵原点)您可以使用 mat4 和 vec4 完成所有矩阵操作...您只需使用 vec4 添加缺少的行/列操作... 【参考方案1】:

原来我前段时间在这方面写过一些论文。这个 (Interactive Visualization Methods For Four Dimensions) 最适用于您的特定问题,但引用此的其他文档也可能对您有所帮助。在那个特定的应用程序中,我旋转的是在 4D 中观察的对象,而不是查看器,但数学是等价的。

关于这个具体问题:

因此问题是:如何移动 前向(使用 4x4 矩阵变换) 在一个 4-D 的表面 超球面?

如果您在超球面的表面上四处移动,您就不会在 w 中进行平移。您实际上需要围绕单位半径的大圆在球面几何中移动。这意味着,如果您可以为您的参考系构建合适的轴,您可以spherically interpolate 在您所在的位置和您要去的位置之间。

例如,可用于此类 slerp 的一种构造是使用指向正前方的单位向量(您的视线,在 Wikipedia 等式中也称为 p_1),一个指向顶部的向量您的头部 (p_0) 和一个指向您右耳的向量(以创建右手坐标系)。

如果您随后以角速度而不是线性来跟踪球体上的速度,则只需在 Wikipedia 中插入 t(经过时间)的值即可找到您的新角位置。

请注意,该等式对顶点p 中的组件数量没有限制。球面插值适用于任何几何形状。

EDIT(回答 cmets 中的问题):

Slerp 似乎不是这里的情况, 因为我不想插入一个 随着时间的推移在 2 个向量之间旋转。 相反,在每个时间步,我想 将每个顶点移到对面 观看者的移动方向 片刻。因此,我在位置 (0, 0, 0, 1) 我想在 (sqrt(2)/2, sqrt(2)/2, 0, 0) 下一帧。

这样想:您在球体(任何维度)上的位置是一个矢量,它将您从中心移到表面。如果您以特定的角速度四处移动,那么您将处于 p0 和时间 t0,p1 在时间 t1,等等。Slerp 是一种在特定时间计算这些位置的便捷方法。

同样,您的视线是与位移矢量成直角的矢量。视线在时间 t0 为 v0,在时间 t1 为 v1,依此类推。 Slerp 再次用于计算该向量。

我怎样才能建立通讯员 变换矩阵,所以每个顶点 将乘以倒数 是吗?

使用这两个向量,orthogonalization 给你第三个,你现在有了一个新的参考框架。从您的原始参考系到这个新参考系有一个single quaternion that defines the rotation。这就是你要找的东西。

然而,在您将世界渲染到二维屏幕上之前,您首先需要将其从 4D 渲染到 3D。 OpenGL(不出所料)不直接支持这一点。

要了解原因,请查看perspective projection matrix。它假设您在 3D 空间中渲染同质点:x、y、z 在前三个分量中,w(缩放因子)在第四个分量中。 w = 0 表示一个向量,而 w = 其他任何值表示一个点。 w = 1 以外的任何值都是非归一化点。

因此,没有办法在 (0, 0, 0, 0) 的 4D 原点处渲染一个点。

从矩阵的构造中可以看出,制作 4D 到 3D 的投影矩阵并不难。首先将其应用于您的几何体集,独立于 OpenGL 的矩阵管道。然后您可以使用 OpenGL 标准矩阵将 3D 映射到屏幕上。

【讨论】:

我知道,如果我在表面上移动,我不会在 w 中平移,但是在旋转中改变 w 坐标会取代投影中的原点,对观察者来说,世界已翻译。 关于 slerp,我无法理解如何将其转换为转换矩阵。 Slerp 似乎不是这里的情况,因为我不想随着时间的推移在 2 个向量之间插入一个旋转。相反,在每个时间步长,我想将 每个 顶点移动到观察者当时正在移动的相反方向。因此,我在位置 (0, 0, 0, 1) 并且我想在 (sqrt(2)/2, sqrt(2)/2, 0, 0) 下一帧。如何构建对应的变换矩阵,让每个顶点都乘以它的逆矩阵?【参考方案2】:

您可能需要 5x5 矩阵,因为您在 4 空间上进行操作。齐次坐标的思想是通过应用线性算子引入一个额外的维度来表示加法运算。

我真的很喜欢你的想法,但只是出于好奇:为什么不简单地定义一个循环 3 空间,即在给定值处包装坐标。使用几何着色器,您可以复制那些环绕的图元顶点(您必须剪切,并将剪切的顶点与引入的辅助顶点一起移动到空间的另一端)。这会产生一种镜厅效应,所以你也必须引入某种地平线。

【讨论】:

效果不一样。使用循环环绕的 3-D 空间似乎沿着一个轴看你会看到你自己的背在地平线上,并且取决于你走的角度,你不会在一次往返后到达相同的位置。 3 球体的效果是,好吧,我需要对其进行编码才能知道... @Ivella,实际上,循环坐标会产生类似于您正在寻找的效果,如果不完全一样的话。在任何维度球体上导航的主要特征之一是,无论您转向哪种方式,您始终可以以相同的距离返回起点。在循环坐标系中,对角线方向将比直轴方向更长。 我不需要 5x5 矩阵来进行旋转,4x4 就足够了,就像 3x3 矩阵足以进行 3D 旋转一样。我无法在 4D 欧几里得空间中平移,因为那会使我脱离超球面,所以我不需要 5x5 矩阵。【参考方案3】:

我确实在 math.stackexchange.com 上问过同样的问题,因为这个问题与数学太相关,我可能会在那里得到更好的答案。如果您对我实际使用的原始答案感兴趣,请查看here。

在 4D 中,没有一个向量垂直于任何旋转,实际上是一个垂直向量的整个平面,这让我感到困惑。

另外,在 OpenGL 中,我很快发现我可以简化给定解决方案的计算,因为我总是可以假设我在 4D 投影原点 (0,0,0,-1),总是面向 (0 ,0,-1,0),然后沿 z 和 w 平移一个给定的角度,并将其与前一帧中已经累积的 GL_MODELVIEW_MATRIX 相乘。所以我做了MODELVIEW <= M x MODELVIEW 而不是MODELVIEW <= MODELVIEW x M 如果我简单地打电话给glMultMatrix(M)

【讨论】:

以上是关于在 OpenGL 中导航超球体的表面的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenGL 中将纹理映射到球体时出现接缝问题

我有一个 OpenGL 镶嵌球体,我想在其中切一个圆柱形孔

如何在OpenGL中做“AND”模具?

在 OpenGL 4.0 中绘制球体

PyQtGraph & OpenGL:如何在两个坐标之间创建一个球体?

OpenGL/C++ 3D 球体