四元数旋转不起作用
我刚刚开始使用四元数,但在使用四元数让简单的 FPS 相机正常工作时遇到了一些烦人的困难。
基本上,每当我尝试移动鼠标时,我在屏幕上绘制的三角形都会变得疯狂,并且在屏幕上移动和移动的速度比我看到的要快。移动键(wsad)按预期工作,直到我移动鼠标,然后一切都变得一团糟。我认为问题出在轮换上,但过去几天我一直在思考这个问题,但没有结果。
以下是有关正在发生的情况的视频: 四元数测试视频
- 要查看鼠标输入,请从头开始观看。
- 要查看键盘输入(前进、后退等),请跳至 0:51 秒。
仅供参考,以下是我正在使用的 3 个主要类:
Quaternion.h
CameraSceneNode.h
CameraSceneNode.cpp
最相关的部分是 tick()
(在其中更新旋转四元数)和 render()
(在其中渲染“相机”,其中包括旋转和平移场景)。
这是 tick()
方法:
void CameraSceneNode::tick(float32 time) {
// movement direction
if (movement_[MOVE_DIR_FORWARD] == 1)
pos_ += rotation_ * vmath::Vector3f(0, 0, -moveSpeed_ * time);
if (movement_[MOVE_DIR_BACKWARD] == 1)
pos_ += rotation_ * vmath::Vector3f(0, 0, moveSpeed_ * time);
if (movement_[MOVE_DIR_LEFT] == 1)
pos_ += rotation_ * vmath::Vector3f(-moveSpeed_ * time, 0, 0);
if (movement_[MOVE_DIR_RIGHT] == 1)
pos_ += rotation_ * vmath::Vector3f(moveSpeed_ * time, 0, 0);
// rotation
if (xRot_ != 0) {
Quaternion quatRotation = Quaternion();
quatRotation.buildFromAxisAngle(1, 0, 0, (xRot_ * time * rotSpeed_) * math::DEGTORAD);
//quatRotation.normalize();
rotation_ = rotation_ * quatRotation;
xRot_ = 0;
rotation_.normalize();
}
if (yRot_ != 0) {
Quaternion quatRotation = Quaternion();
quatRotation.buildFromAxisAngle(0, 1, 0, (yRot_ * time * rotSpeed_) * math::DEGTORAD);
//quatRotation.normalize();
rotation_ = quatRotation * rotation_;
yRot_ = 0;
rotation_.normalize();
}
}
这是 render()
方法:
void CameraSceneNode::render() {
if (isActive()) {
float32 matrix[16];
rotation_.fillMatrix(matrix);
glMultMatrixf(&matrix[0]);
//glRotatef(rotYTest, 0, 1, 0);
//glRotatef(rotXTest, 1, 0, 0);
glTranslatef(-pos_.x, -pos_.y, -pos_.z);
}
}
另外,在我在相机上调用 render()
之前,我运行这段代码:
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
在主游戏循环的每一帧中都会调用 tick(..)
和 render()
。 CameraSceneNode
类中有一些函数接受移动方向和相机旋转的更改(即更改 movement_
缓冲区或 xRot_
和 yRot_
) 。
如果这还不够,我很抱歉。一些函数(例如 fillMatrix(..)
)是在我上面引用的 3 个 .h/.cpp 文件中定义的。我已经多次检查了四元数类,在我看来它是正确的。但话又说回来,我使用的所有代码对我来说都是正确的,所以谁知道呢:S
我对此完全束手无策。如果有人能解释为什么这不起作用,我将不胜感激!
干杯
贾勒特
I'm just starting to work with Quaternions, but I'm having some annoying difficulties getting a simple FPS camera to work properly using Quaternions.
Basically, whenever I try to move the mouse, a triangle I draw on the screen goes crazy and moves off and on the screen faster than I can see. The movement keys (wsad) are working as expected, UNTIL I move the mouse, and then it gets all messed up. I think the problem is with the rotation, but I've been pouring over this issue for the past couple of days to no avail.
Here's a video of what's going on: Quaternion Test Video
- To see mouse input, watch from the beginning.
- To see keyboard input (go forward, backward, etc) skip to 0:51 seconds.
Just for reference, here are the 3 main classes I'm using:
Quaternion.h
CameraSceneNode.h
CameraSceneNode.cpp
The most relevant sections are tick()
(where I update the rotation Quaternion), and render()
(where I render the 'camera', which consists of rotating and translating the scene).
Here is the tick()
method:
void CameraSceneNode::tick(float32 time) {
// movement direction
if (movement_[MOVE_DIR_FORWARD] == 1)
pos_ += rotation_ * vmath::Vector3f(0, 0, -moveSpeed_ * time);
if (movement_[MOVE_DIR_BACKWARD] == 1)
pos_ += rotation_ * vmath::Vector3f(0, 0, moveSpeed_ * time);
if (movement_[MOVE_DIR_LEFT] == 1)
pos_ += rotation_ * vmath::Vector3f(-moveSpeed_ * time, 0, 0);
if (movement_[MOVE_DIR_RIGHT] == 1)
pos_ += rotation_ * vmath::Vector3f(moveSpeed_ * time, 0, 0);
// rotation
if (xRot_ != 0) {
Quaternion quatRotation = Quaternion();
quatRotation.buildFromAxisAngle(1, 0, 0, (xRot_ * time * rotSpeed_) * math::DEGTORAD);
//quatRotation.normalize();
rotation_ = rotation_ * quatRotation;
xRot_ = 0;
rotation_.normalize();
}
if (yRot_ != 0) {
Quaternion quatRotation = Quaternion();
quatRotation.buildFromAxisAngle(0, 1, 0, (yRot_ * time * rotSpeed_) * math::DEGTORAD);
//quatRotation.normalize();
rotation_ = quatRotation * rotation_;
yRot_ = 0;
rotation_.normalize();
}
}
and here is the render()
method:
void CameraSceneNode::render() {
if (isActive()) {
float32 matrix[16];
rotation_.fillMatrix(matrix);
glMultMatrixf(&matrix[0]);
//glRotatef(rotYTest, 0, 1, 0);
//glRotatef(rotXTest, 1, 0, 0);
glTranslatef(-pos_.x, -pos_.y, -pos_.z);
}
}
Also, before I call render()
on the camera, I run this bit of code:
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
Both tick(..)
and render()
are called every frame from my main game loop. There are functions in the CameraSceneNode
class that accept changes in movement direction and camera rotation (i.e. that change the movement_
buffer or xRot_
and yRot_
) .
I'm sorry if this isn't enough information. Some of the functions (like fillMatrix(..)
) are defined in those 3 .h/.cpp files I referenced above. I've checked over the Quaternion class several times, and it looks to me like it's correct. But then again, all the code I'm using looks correct to me, so who knows :S
I'm totally at my wits end with this. If anyone can shed some light on why this is not working, I would greatly appreciate it!!
Cheers
Jarrett
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从表面上看,您在每个刻度上逐渐累积旋转(rotation_ = quatRotation *rotation_;),这首先是有意义的,因为您所做的只是稍微调整旋转,因此应该安全地附加另一个与已有的旋转一两度,对吧?
然而,每次旋转(通过您正在做的事情),您实际上每次都会稍微改变旋转轴,这就是您看到这种不稳定行为的原因。
我的建议是跟踪整体 X/Y 旋转,随着鼠标移动而递增或递减,然后每次直接计算旋转而不是累积旋转。因此,如果您在 X 方向旋转 1 度 15 次,则当前代码本质上是“在 X 方向旋转 1 度,在 X 方向添加旋转 1 度,等等”。我的建议是跟踪单个旋转因子 X,并在其变化时直接设置旋转“旋转 13 度、旋转 14 度、旋转 15 度等”。
从您的视频来看,旋转似乎也太大了,因此您可能希望将最终使用的旋转缩放 10 或 50(或其他)。
我可能偏离了,但我在 3D 编码冒险中遇到过类似的事情,这是我最好的建议。如果这不是问题,因为您正在处理相机旋转,您可能需要使用矩阵逆。更糟的是,查看模型视图矩阵的某些旋转,看看它是否符合您的预期(虽然很痛苦,但也是一次有价值的调试练习)。
From the looks of it, you're progressively accumulating your rotation every tick (rotation_ = quatRotation * rotation_;), which makes sense at first because all you're doing is adjusting the rotation slightly and so it should be safe to tack on another degree or two of rotation to what's already there, right?
However, each time you rotate (by what you're doing), you're actually slightly changing the axis of rotation each time, which is why you see this erratic behaviour.
What I would suggest is to keep track of the overall X/Y rotations, incrementing or decrementing as the mouse moves, and then computing the rotation directly each time instead of accumulating rotations. So if you rotated in X by 1 degree 15 times, your current code essentially says "rotate 1 degree in X, add a rotate 1 degree in X, etc, etc". What I'm suggesting is to keep track of a single rotation factor X, and as it changes set the rotation directly "rotate 13 degrees, rotate 14 degrees, rotate 15 degrees, etc".
From your video it also looks like the rotations are too large, so you may wish to scale the final rotations used by a factor of 10 or 50 (or whatever).
I could be way off, but I've run into similar things in my 3D coding adventures and this is my best suggestion. If that's not the issue, since you're dealing with a camera rotation, you may need to use the matrix inverse. Worse comes to worse, look at the modelview matrix for certain rotations and see if it matches what you expect (a pain, but also a valuable debugging exercise).