我在 Opengl 中显示字符,我让它们绕着四元数的轴旋转,我想要实现的是让它们绕着自己的轴旋转,但是当使用四元数时,如果我根据一个轴旋转一个对象,其他轴则不会没有考虑到这个旋转将围绕一个固定的世界轴旋转。 给定四元数 Qaccumulative(前旋转)和 3 个角度 AngleX、AngleY 和 AngleZ。 首先,我认为欧拉的旋转是值得尝试的事情,我尝试了几种技术:
Quaternion rot1;
Quaternion rot2;
Quaternion rot3;
Vector3 axis ;
float angle;
QAccumulative.getAxisAngle(&axis, &angle);
// first try : around fix axes
cout << "axis : " << axis << endl;
rot1.FromAxis(Vector3(1.0,0.0,0.0),angleX);
rot2.FromAxis(Vector3(0.0,1.0,0.0),angleY);
rot3.FromAxis(Vector3(0.0,0.0,1.0),angleZ);
QAccumulative = QAccumulative * rot1;
QAccumulative = QAccumulative * rot2;
QAccumulative = QAccumulative * rot3;
/*
// second try, around current modified axes
rot1.FromAxis(Vector3(axis.x,0.0,0.0),angleX);
rot2.FromAxis(Vector3(0.0,axis.y,0.0),angleY);
rot3.FromAxis(Vector3(0.0,0.0,axis.z),angleZ);
QAccumulative = QAccumulative * rot1;
QAccumulative = QAccumulative * rot2;
QAccumulative = QAccumulative * rot3;
*/
/*
// third try with Euler rotation
Quaternion rotation;
rotation.FromEuler(10*angleX,10*angleY,10*angleZ);
QAccumulative = QAccumulative * rotation;
*/
QAccumulative.normalise();
到目前为止,它们都没有工作...我不认为我的旋转实现是问题,但如果有人这样做,我会发布代码。欧拉不是我想的那样吗?我应该使用什么轮换来实现我的目标?
编辑:我试过这个,帖子建议:
rotate(float angleX,float angleY,float angleZ) {
Vector3 axis = Vector3(angleX,angleY,angleZ);
Vector3 worldAxis = QAccumulative * axis;
Quaternion worldRotation( worldAxis.x,worldAxis.y,worldAxis.z, 10 );
QAccumulative = worldRotation * QAccumulative;
QAccumulative.normalise();
角色仍然围绕固定轴旋转。
编辑: 我应用了一个帖子给出的伪代码并且它有效:
rotate(float angleX,float angleY,float angleZ) {
Vector3 axis = Vector3(angleX,angleY,angleZ);
Vector3 worldAxis = QAccumulative * axis;
Quaternion worldRotationx( 1.0,0,0, angleZ );
Quaternion worldRotationy( 0,1.0,0, angleX);
Quaternion worldRotationz( 0,0,1.0, -angleY );
QAccumulative = worldRotationx * worldRotationy * worldRotationz * QAccumulative;
QAccumulative.normalise();
最佳答案
我的第一个建议是不要使用欧拉角定义四元数旋转:
这里有一些链接比我能更好地解释它:
http://bitsquid.blogspot.ca/2013/03/what-is-gimbal-lock-and-why-do-we-still.html
https://mathoverflow.net/questions/95902/the-gimbal-lock-shows-up-in-my-quaternions
http://answers.unity3d.com/questions/573035/avoiding-gimbal-lock.html
我建议将您的旋转定义为单个轴和角度,并按照此编写您的类接口(interface),这里有一些建议:
Vector3 operator* ( const Vector3& vec ) const; // rotate a vector
Quaternion operator* ( const Quaternion& quat ) const; // concatenate
void set( const Vector3& axis, float angle ); // set quaternion
void getAxisAngle( Vector3* axis, float* angle ); // extract axis and angle
至于使用四元数应用局部轴旋转,您可以简单地将局部轴转换到世界空间并以这种方式应用转换。
我假设您将字符变换存储为旋转四元数、平移向量和缩放向量/标量。在这种情况下,您只需将角色旋转四元数应用到局部轴以将其带入世界空间,然后使用该世界空间轴像往常一样构建和应用旋转。
您将角色的当前旋转存储为四元数:
Quaternion characterQuaternion;
然后您有了要应用的局部旋转:
Vector3 localAxis;
float angle;
您需要将局部轴转换为世界空间,然后从中构建一个四元数并将其应用于您的角色四元数:
Vector3 worldAxis = characterQuaternion * localAxis; // transform local axis to world coordinate system
Quaternion worldRotation( worldAxis, angle ); // build quaternion
characterQuaternion = worldRotation * characterQuaternion; // apply the rotation
例如,如果您想对角色应用 45 个单位角度(度数或弧度,取决于您的旋转方法)的“滚动”旋转:
localAxis = Vector3(1,0,0);
angle = 45;
关于opengl - 四元数旋转,试图围绕他的轴旋转一个对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24681490/