[英]Rotation of object around World Axis OpenGL
I'm trying to make a controllable ball in OpenGL. 我正在尝试在OpenGL中制作一个可控的球。 I'm using my own matrix class to transform the object matrix, but I can't seem to get the Rotation right. 我正在使用自己的矩阵类来转换对象矩阵,但似乎无法正确实现“旋转”。 I always end up with the ball rotating around the local axis. 我总是以球绕局部轴旋转而告终。 This is how it looks right now https://gfycat.com/LongKindBassethound . 这就是现在的样子https://gfycat.com/LongKindBassethound 。 The long line are the local axis. 长线是局部轴。
So when the ball moves forward the next side movement will be wrong. 因此,当球向前移动时,下一个侧向移动将是错误的。 Theres a function in the matrix class that allows rotation around any axis: 矩阵类中有一个函数可以绕任何轴旋转:
Matrix& Matrix::rotationAxis(const Vector& Axis, float Angle) {
const float Si = sin(Angle);
const float Co = cos(Angle);
const float OMCo = 1 - Co;
Vector Ax = Axis;
Ax.normalize();
m00= (Ax.X * Ax.X) * OMCo + Co;
m01= (Ax.X * Ax.Y) * OMCo - (Ax.Z * Si);
m02= (Ax.X * Ax.Z) * OMCo + (Ax.Y * Si);
m03= 0;
m10= (Ax.Y * Ax.X) * OMCo + (Ax.Z * Si);
m11= (Ax.Y * Ax.Y) * OMCo + Co;
m12= (Ax.Y * Ax.Z) * OMCo - (Ax.X * Si);
m13= 0;
m20= (Ax.Z * Ax.X) * OMCo - (Ax.Y * Si);
m21= (Ax.Z * Ax.Y) * OMCo + (Ax.X * Si);
m22= (Ax.Z * Ax.Z) * OMCo + Co;
m23= 0;
m30= 0;
m31= 0;
m32= 0;
m33= 1;
return *this;
}
I think with this I can take the world direction vectors and transform them to the local space of the object and then rotate around the result. 我认为,我可以采用世界方向矢量并将其转换为对象的局部空间,然后围绕结果旋转。 I don't really know how to do that though (matrix of the ball * world vector? That doesn't work). 我真的不知道该怎么做(球的矩阵*世界向量?那是行不通的)。 I would really like to avoid quaternions, but if I can't do that I would appreciate suggestions in that direction too. 我真的很想避免四元数,但是如果我不能这样做,我也很乐意朝这个方向提出建议。
EDIT: More Info 编辑:更多信息
The transforamtion Code. 转换代码。 As you can see I tried different methods that all do the same... So no surprise there that it doesnt work. 如您所见,我尝试了不同的方法,所有这些方法都执行相同的操作...因此,这并不起作用并不奇怪。
Matrix transM, rotX, rotZ;
rotationX = straight;
rotationZ = side;
if (velocity != Vector(0, 0, 0)) {
velocity.X = -0.0005 * DeltaTime;
velocity.X = clamp(velocity.X, 0, FLT_MAX);
velocity.Z = -0.0005 * DeltaTime;
velocity.Z = clamp(velocity.Z, 0, FLT_MAX);
}
velocity.X += speed * -side * DeltaTime;
velocity.Z += speed * straight * DeltaTime;
transM.translation(velocity.X, 0, velocity.Z);
if (velocity.Z != 0 || velocity.X != 0) {
//http://mathworld.wolfram.com/EulerAngles.html
//http://gamedev.stackexchange.com/questions/67199/how-to-rotate-an-object-around-world-aligned-axes
Vector localAxisX = m_Ball * Vector(1, 0, 0);
Vector localAxisZ = m_Ball * Vector(0, 0, 1);
rotX.rotationAxis(Vector(1, 0, 0), 0.5* M_PI * straight * DeltaTime);
rotZ.rotationAxis(Vector(0, 0, 1), 0.5* M_PI * side * DeltaTime);
//rotX.rotationX(0.5* M_PI * straight * DeltaTime * 3);
//rotZ.rotationZ(0.5* M_PI * side * DeltaTime * 3);
//Matrix fullRotation.rotationYawPitchRoll(Vector(0, 0.5* M_PI * straight * DeltaTime, 0.5* M_PI * side * DeltaTime));
m_Ball = transM * m_Ball * (rotX*rotZ);
}
else {
m_Ball = transM * m_Ball;
}
Draw code with my previous attempt trying to use glRotatef (obviously commented out right now) 我以前尝试使用glRotatef的尝试绘制代码(现在已明显注释掉)
void Ball::draw(float DeltaTime) {
glPushMatrix();
glMultMatrixf(m_Ball);
if(rotationX)
glRotatef(0.5* M_PI * rotationX * DeltaTime, 1.0, 0.0, 0.0);
if(rotationZ)
glRotatef(0.5* M_PI * rotationZ * DeltaTime, 0.0, 0.0, 1.0);
g_Model_ball.drawTriangles();
glPopMatrix();
drawAxis();
}
I highly suggest using quaternions to easily handle compound rotations and avoid gimbal lock. 我强烈建议使用四元数来轻松处理复合旋转并避免云台锁定。
https://en.wikipedia.org/wiki/Gimbal_lock https://zh.wikipedia.org/wiki/云台锁定
Ok with regards to your comments and video, You want to rotate around the ball's center. 关于您的评论和视频,您想绕球的中心旋转。 It seems you accumulate your rotations in m_Ball
but do a weird transM
multiplication. 看来您在m_Ball
累积了旋转,但是做了一个怪异的transM
乘法。 Also you are probably accumulating translations in transM
. 另外,您可能正在transM
积累翻译。
Try not to mix your translations and rotations and avoid accumulating them in your m_Ball
. 尽量不要混合使用平移和旋转,并避免将它们累积在m_Ball
。 You can do something like this. 你可以做这样的事情。
//transformation matrix
transM.translation(velocity.X, 0, velocity.Z);
//accumulate translations in m_BallT
m_BallT = transM * m_BallT;
//final Rotation
Matrix rotation = rotX * rotZ;
//accumulate rotations in m_BallR
m_BallR = rotation * m_BallR;
//now compute your final transformation matrix from accumulated rotations and translation
m_Ball = m_BallT * m_BallR;
note how m_BallR
is just rotations accumulated. 请注意m_BallR
只是如何累积旋转。 Post multiplication will ensure new rotation
is applied after accumulated rotations in m_BallR
. 乘法后将确保在m_BallR
累积旋转后应用新的rotation
。 Finally translate to the final position accumulated in m_BallT
. 最后转换为m_BallT
累积的最终位置。 Your ball will rotate about its center and move according to m_BallT
. 您的球将绕其中心旋转并根据m_BallT
移动。
You could also simply replace the transformation component on your m_BallR
to avoid extra matrix multiplications. 您也可以简单地替换m_BallR
上的转换组件,以避免额外的矩阵乘法。
Vector newPos(m_Ball.translation().X + velocity.X, terrainNoise.GetHeight(m_Ball.translation().X, m_Ball.translation().Z) + 0.5, m_Ball.translation().Z + velocity.Z);
rotX.rotationAxis(Vector(1, 0, 0), 0.5* M_PI * straight * DeltaTime * abs(velocity.Z) * 100);
rotZ.rotationAxis(Vector(0, 0, 1), 0.5* M_PI * side * DeltaTime * abs(velocity.X) * 100);
m_Rotation = (rotX*rotZ);
m_Ball = (m_Ball.invert() * m_Rotation).invert();
m_Ball.m03 = newPos.X;
m_Ball.m13 = newPos.Y;
m_Ball.m23 = newPos.Z;
This is the solution I came up with after reading this link provided by @Spektre. 这是我想出了阅读后的溶液这个由@Spektre提供的链接。 Basically you just invert the ModelMatrix of the ball to get it into world position, do your rotation and then transform it back into local space. 基本上,您只需要反转球的ModelMatrix即可将其置于世界位置,进行旋转,然后将其转换回局部空间。
You have to set the newPos Vector before you rotate, otherwise it would affect future transformations. 旋转之前必须设置newPos Vector,否则它将影响以后的转换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.