OpenGL中的四元数旋转有什么问题?

OpenGL中的四元数旋转有什么问题?,opengl,rotation,quaternions,Opengl,Rotation,Quaternions,在互联网上记笔记有助于正确构造四元数类。我的问题是将它们付诸实际使用,并在原始OpenGL中使用它们进行旋转 在我的输入事件中,我有以下内容: Quaternion<float> qPrev = qRot; qRot = qRot.UnitQuaternion(); // #1. Quaternion<float> axis(5., 0., 1., 0.); qRot = qPrev*axis; qRot *= qPrev.conjugate(); //#2. qRot

在互联网上记笔记有助于正确构造四元数类。我的问题是将它们付诸实际使用,并在原始OpenGL中使用它们进行旋转

在我的输入事件中,我有以下内容:

Quaternion<float> qPrev = qRot;
qRot = qRot.UnitQuaternion(); // #1.
Quaternion<float> axis(5., 0., 1., 0.);
qRot = qPrev*axis;
qRot *= qPrev.conjugate();
//#2. qRot = qRot.UnitQuaternion();

我感谢你的帮助


编辑:非常感谢@ybungalobill的帮助

我想从我的四元数中得到的是四元数数学的一个非常具体的应用。我想要一个旋转轴,而在我的示例中,我正在创建一个具有直接值的四元数。这不是旋转矩阵的推导方式。我需要更多的步骤:

void FromAxisAngle(_Tp theta, _Tp x, _Tp y, _Tp z)
{
    //Angle should be in radians
    this->w = cos(theta/2);

    //Axes
    this->x = x * sin(theta/2);
    this->y = y * sin(theta/2);
    this->z = z * sin(theta/2);
    //Normalize
    *this = this->UnitQuaternion();
}
同样,获取旋转矩阵是一个非常具体的应用程序,需要非常具体的步骤。四元数不能做到“开箱即用”

旋转逻辑也有一些小的变化:

   Quaternion<float> qPrev = qRot;
   Quaternion<float> axis;
   axis.FromAxisAngle(-5./100, 1., 0., 0.);
   qRot = qPrev*axis;
四元数qPrev=qRot;
四元数轴;
轴从轴角度(-5./100,1,0,0.);
qRot=qPrev*轴;
现在我从旋转轴上创建了一个数学上正确的四元数。然后乘以

最后,我必须做的最后一件事是从我的四元数创建一个OpenGL可以使用的矩阵。因此,我们需要做更多的数学运算,以便将其转化为旋转物体的符号:

void GetMatrix(_Tp matrix[16])
{
   Quaternion<_Tp> temp(this->UnitQuaternion());
  _Tp qw = temp.w;
  _Tp qx = temp.x;
  _Tp qy = temp.y;
  _Tp qz = temp.z;

  matrix[0] = 1.0f - 2.0f*qy*qy - 2.0f*qz*qz;
  matrix[1] = 2.0f*qx*qy - 2.0f*qz*qw;
  matrix[2] = 2.0f*qx*qz + 2.0f*qy*qw;
  matrix[3] = 0;

  matrix[4] = 2.0f*qx*qy + 2.0f*qz*qw;
  matrix[5] = 1.0f - 2.0f*qx*qx - 2.0f*qz*qz;
  matrix[6] = 2.0f*qy*qz - 2.0f*qx*qw;
  matrix[7] = 0;

  matrix[8] = 2.0f*qx*qz - 2.0f*qy*qw;
  matrix[9] = 2.0f*qy*qz + 2.0f*qx*qw;
  matrix[10] = 1.0f - 2.0f*qx*qx - 2.0f*qy*qy;
  matrix[11] = 0;

  matrix[12] = 0;
  matrix[13] = 0;
  matrix[14] = 0;
  matrix[15] = 1;
}
void GetMatrix(_-Tp-matrix[16])
{
四元数temp(this->UnitQuaternion());
_Tp qw=温度w;
_Tp qx=温度x;
_Tp qy=温度y;
_Tp qz=温度z;
矩阵[0]=1.0f-2.0f*qy*qy-2.0f*qz*qz;
矩阵[1]=2.0f*qx*qy-2.0f*qz*qw;
矩阵[2]=2.0f*qx*qz+2.0f*qy*qw;
矩阵[3]=0;
矩阵[4]=2.0f*qx*qy+2.0f*qz*qw;
矩阵[5]=1.0f-2.0f*qx*qx-2.0f*qz*qz;
矩阵[6]=2.0f*qy*qz-2.0f*qx*qw;
矩阵[7]=0;
矩阵[8]=2.0f*qx*qz-2.0f*qy*qw;
矩阵[9]=2.0f*qy*qz+2.0f*qx*qw;
矩阵[10]=1.0f-2.0f*qx*qx-2.0f*qy*qy;
矩阵[11]=0;
矩阵[12]=0;
矩阵[13]=0;
矩阵[14]=0;
矩阵[15]=1;
}
使用
glMultMatrix
立方体旋转

这不是将四元数旋转应用于GL状态的方式。必须按照公式将其转换为矩阵,然后调用
glMultMatrix
glMultTransposeMatrix
。在这一方法之后,3号将按预期工作


将任何非零四元数从锡库转换为矩阵的代码:

template<class T>
mat<T,3,3> mat_rotation(const quat<T> &x)
{
    T s = 2/norm2(x); // cheap renormalization even of non-unit quaternions
    T wx = x.w*x.x, wy = x.w*x.y, wz = x.w*x.z;
    T xx = x.x*x.x, xy = x.x*x.y, xz = x.x*x.z;
    T yy = x.y*x.y, yz = x.y*x.z;
    T zz = x.z*x.z;

    return mat<T,3,3>(
        1 - s*(yy+zz),  s*(xy-wz),  s*(xz+wy),
        s*(xy+wz),  1 - s*(xx+zz),  s*(yz-wx),
        s*(xz-wy),  s*(yz+wx),  1 - s*(xx+yy)
    );
}
模板
材料旋转(常量数量和x)
{
ts=2/norm2(x);//非单位四元数的廉价重正化
T wx=x.w*x.x,wy=x.w*x.y,wz=x.w*x.z;
T xx=x.x*x.x,xy=x.x*x.y,xz=x.x*x.z;
T yy=x.y*x.y,yz=x.y*x.z;
T zz=x.z*x.z;
回程垫(
1-s*(yy+zz),s*(xy wz),s*(xz+wy),
s*(xy+wz),1-s*(xx+zz),s*(yz-wx),
s*(xz-wy),s*(yz+wx),1-s*(xx+yy)
);
}
这不是将四元数旋转应用于GL状态的方式。必须按照公式将其转换为矩阵,然后调用
glMultMatrix
glMultTransposeMatrix
。在这一方法之后,3号将按预期工作


将任何非零四元数从锡库转换为矩阵的代码:

template<class T>
mat<T,3,3> mat_rotation(const quat<T> &x)
{
    T s = 2/norm2(x); // cheap renormalization even of non-unit quaternions
    T wx = x.w*x.x, wy = x.w*x.y, wz = x.w*x.z;
    T xx = x.x*x.x, xy = x.x*x.y, xz = x.x*x.z;
    T yy = x.y*x.y, yz = x.y*x.z;
    T zz = x.z*x.z;

    return mat<T,3,3>(
        1 - s*(yy+zz),  s*(xy-wz),  s*(xz+wy),
        s*(xy+wz),  1 - s*(xx+zz),  s*(yz-wx),
        s*(xz-wy),  s*(yz+wx),  1 - s*(xx+yy)
    );
}
模板
材料旋转(常量数量和x)
{
ts=2/norm2(x);//非单位四元数的廉价重正化
T wx=x.w*x.x,wy=x.w*x.y,wz=x.w*x.z;
T xx=x.x*x.x,xy=x.x*x.y,xz=x.x*x.z;
T yy=x.y*x.y,yz=x.y*x.z;
T zz=x.z*x.z;
回程垫(
1-s*(yy+zz),s*(xy wz),s*(xz+wy),
s*(xy+wz),1-s*(xx+zz),s*(yz-wx),
s*(xz-wy),s*(yz+wx),1-s*(xx+yy)
);
}

我见过像您所说的那样应用矩阵的代码,但我如何避免使用生成的矩阵而改用glRotatef?@Maverick:您无法避免矩阵,因为传统的OpenGL转换最终会使用矩阵堆栈。您可以通过
normalize(x,y,z)
恢复旋转轴,通过
2*atan2(长度(x,y,z),w)
恢复角度,然后调用
glRotate
。但是下一件事是计算这个角度的正弦和余弦,然后计算出所说的矩阵。。。问题是你为什么不想用直接的方式来做呢?好吧。我对这段代码感到困惑:如果这旋转一个点并返回一个轴,为什么这不适用于glRotatef?@Maverick:你不需要它(除非你在顶点着色器中直接得到四元数进行变换——你不需要)。该代码将四元数应用于一个向量。相反,您需要的是通过矩阵乘法来表示转换。如果你做那
q.QuatRotation(v)
的代数,你会发现它正好等于
mat_rotation(q)*v
@Maverick:是的。这是正确的。换句话说:传统OpenGL的工作原理是通过
M*v
将其内部
GL\u MODELVIEW
矩阵
M
应用到每个顶点
v
。因为OpenGL不理解四元数,所以需要以矩阵向量乘法形式表示
q.quartorrotation(v)
,而
mat_rotation(q)*v
就是这样做的。你将
M=mat_rotation(q)
存储在OpenGL的状态下,然后根据需要替换不同的顶点
v
。我见过像你所说的那样应用矩阵的代码,但我如何避免使用结果矩阵而使用glRotatef呢?@Maverick:你无法避免矩阵,因为传统的OpenGL转换最终会使用矩阵堆栈。您可以通过
normalize(x,y,z)
恢复旋转轴,通过
2*atan2(长度(x,y,z),w)
恢复角度,然后调用
glRotate
。但是下一件事是计算这个角度的正弦和余弦,然后计算出所说的矩阵。。。问题是为什么你不想用简单的方式来做呢?好吧。我对这段代码感到困惑:如果这旋转一个点并返回一个轴,为什么这对glRotatef不起作用?@Maverick:you
glRotatef(qRot.x, 1., 0, 0);
glRotatef(qRot.y, 0, 1., 0);
glRotatef(qRot.z, 0, 0, 1.);
template<class T>
mat<T,3,3> mat_rotation(const quat<T> &x)
{
    T s = 2/norm2(x); // cheap renormalization even of non-unit quaternions
    T wx = x.w*x.x, wy = x.w*x.y, wz = x.w*x.z;
    T xx = x.x*x.x, xy = x.x*x.y, xz = x.x*x.z;
    T yy = x.y*x.y, yz = x.y*x.z;
    T zz = x.z*x.z;

    return mat<T,3,3>(
        1 - s*(yy+zz),  s*(xy-wz),  s*(xz+wy),
        s*(xy+wz),  1 - s*(xx+zz),  s*(yz-wx),
        s*(xz-wy),  s*(yz+wx),  1 - s*(xx+yy)
    );
}