【发布时间】:2025-12-26 12:00:11
【问题描述】:
我正在处理fork of Pleasant3D。
当旋转正在显示的对象时,即使该点不在视图的中心(例如,因为用户已平移以移动视图中的对象),该对象也始终相对于自身围绕同一点旋转。
我想更改此设置,以便视图始终围绕视图中心的点旋转对象,因为它向用户显示,而不是对象的中心。
这是当前围绕其中心旋转对象的代码的核心(略微简化)(来自here):
glLoadIdentity();
// midPlatform is the offset to reach the "middle" of the object (or more specifically the platform on which the object sits) in the x/y dimension.
// This the point around which the view is currently rotated.
Vector3 *midPlatform = [self.currentMachine calcMidBuildPlatform];
glTranslatef((GLfloat)cameraTranslateX - midPlatform.x,
(GLfloat)cameraTranslateY - midPlatform.y,
(GLfloat)cameraOffset);
// trackBallRotation and worldRotation come from trackball.h/c which appears to be
// from an Apple OpenGL sample.
if (trackBallRotation[0] != 0.0f) {
glRotatef (trackBallRotation[0], trackBallRotation[1], trackBallRotation[2], trackBallRotation[3]);
}
// accumlated world rotation via trackball
glRotatef (worldRotation[0], worldRotation[1], worldRotation[2], worldRotation[3]);
glTranslatef(midPlatform.x, midPlatform.y, 0.);
// Now draw object...
我需要以什么顺序应用什么转换才能获得我想要的效果?
到目前为止我尝试过的一些方法
据我了解,这就是当前代码的作用:
“如果对一个顶点应用多个变换,OpenGL 会以相反的顺序执行矩阵乘法”(来自here)。这意味着要应用的第一个转换实际上是上面代码中的最后一个。它将视图的中心 (0,0) 移动到对象的中心。
这个点然后用作接下来的两个变换(旋转)的旋转中心。
最后,midPlatform 平移反向完成,将中心移回原始位置,并应用用户完成的 XY 平移(平移)。在这里,“相机”也从对象移到正确的位置(由 cameraOffset 指示)。
这看起来很简单。所以我需要改变的不是将视图的中心转换为对象的中心 (midPlatform),而是需要将其转换为用户看到的当前视图中心,对吧?
不幸的是,这就是转换开始以有趣的方式相互影响的地方,我遇到了麻烦。
我尝试将代码更改为:
glLoadIdentity();
glTranslatef(0,
0,
(GLfloat)cameraOffset);
if (trackBallRotation[0] != 0.0f) {
glRotatef (trackBallRotation[0], trackBallRotation[1], trackBallRotation[2], trackBallRotation[3]);
}
// accumlated world rotation via trackball
glRotatef (worldRotation[0], worldRotation[1], worldRotation[2], worldRotation[3]);
glTranslatef(cameraTranslateX, cameraTranslateY, 0.);
换句话说,我将视图的中心平移到前一个中心,围绕该中心旋转,然后应用相机偏移将相机移到正确的位置。这使得旋转完全按照我想要的方式运行,但它引入了一个新问题。现在用户所做的任何平移都是相对于对象的。例如,如果旋转对象以使相机沿 X 轴末端观察,如果用户从左向右平移,则对象似乎是在离用户更近/更远,而不是向左或向右移动。
我想我可以理解为什么是(在旋转之前应用 XY 相机平移),并且我认为我需要做的是想办法在旋转之后从旋转之前取消平移(以避免奇怪的平移效果),然后进行另一次平移,相对于观察者(眼睛坐标空间)而不是对象(对象坐标空间)进行平移,但我不确定该怎么做。
我在 OpenGL 常见问题解答 (http://www.opengl.org/resources/faq/technical/transformations.htm) 中找到了我认为的一些线索,例如:
9.070 如何围绕固定坐标系而不是对象的局部坐标系变换对象?
如果您围绕其 Y 轴旋转一个对象,您会发现 X 轴和 Z 轴随着该对象旋转。围绕这些轴之一的后续旋转将围绕新转换的轴而不是原始轴旋转。通常需要在固定坐标系而不是对象的局部坐标系中执行变换。
问题的根本原因是 OpenGL 矩阵运算后乘到矩阵堆栈上,从而导致在对象空间中发生变换。要影响屏幕空间转换,您需要进行预乘。 OpenGL没有提供矩阵乘法顺序的模式切换,所以需要手动预乘。应用程序可以通过在每一帧之后检索当前矩阵来实现这一点。应用程序在单位矩阵之上为下一帧乘以新的变换,并使用 glMultMatrix() 将累积的当前变换(从最后一帧)乘以这些变换。
您需要注意,每帧检索一次 ModelView 矩阵可能会对应用程序的性能产生不利影响。但是,您需要对该操作进行基准测试,因为性能会因一种实现而异。
和
9.120 如何找到仅由 ModelView 矩阵变换的顶点坐标?
获取顶点的眼睛坐标空间值通常很有用(即模型视图矩阵转换的对象空间顶点)。您可以通过检索当前的 ModelView 矩阵并执行简单的向量/矩阵乘法来获得它。
但我不确定如何在我的情况下应用这些。
【问题讨论】:
-
呃.... 已弃用的功能和固定功能管道。你只求麻烦……
-
我愿意考虑从头开始重写这个逻辑,如果我可能能够正确地做到这一点并且不会在项目的这一部分上花费过多的时间(特别是如果我现在可以只换掉转换逻辑并保持绘图逻辑不变)。请记住,这是我第一次涉足 OpenGL,是否有关于如何在不使用“[d] 弃用功能和固定功能管道”的情况下正确执行此操作的好教程? (如果它解释了固定功能管道是什么以及为什么它是一件坏事,则可以加分。)
-
(老实说,我更喜欢基于现有代码的解决方案和正确方法的教程。)
标签: objective-c opengl