确定基于四元数调整方向所需的角速度

时间:2015-04-07 18:53:55

标签: c++ math rotation geometry quaternions

问题:

我在3D空间中有一个存在于给定方向的对象。我需要将对象重新定向到新的方向。我目前将方向表示为四元数,尽管这不是绝对必要的。

我基本上需要确定将身体定向到所需方向所需的角速度。

我目前正在使用的内容如下所示:

Psuedocode:

// 4x4 Matrix containing rotation and translation
Matrix4 currentTransform = GetTransform();

// Grab the 3x3 matrix containing orientation only
Matrix3 currentOrientMtx = currentTransform.Get3x3();

// Build a quat based on the rotation matrix
Quaternion currentOrientation(currentOrientMtx);
currentOrientation.Normalize();

// Build a new matrix describing our desired orientation
Vector3f zAxis = desiredForward;
Vector3f yAxis = desiredUp;
Vector3f xAxis = yAxis.Cross(zAxis);
Matrix3 desiredOrientMtx(xAxis, yAxis, zAxis);

// Build a quat from our desired roation matrix
Quaternion desiredOrientation(desiredOrientMtx);
desiredOrientation.Normalize();

// Slerp from our current orientation to the new orientation based on our turn rate and time delta
Quaternion slerpedQuat = currentOrientation.Slerp(desiredOrientation, turnRate * deltaTime);

// Determine the axis and angle of rotation
Vector3f rotationAxis = slerpedQuat.GetAxis();
float rotationAngle = slerpedQuat.GetAngle();

// Determine angular displacement and angular velocity
Vector3f angularDisplacement = rotationAxis * rotationAngle;    
Vector3f angularVelocity = angularDisplacement / deltaTime;

SetAngularVelocity(angularVelocity);

这基本上只是让我的对象旋转到遗忘。我已经验证了通过轴构造的desiredOrientMtx确实是正确的最终旋转变换。我觉得我在这里错过了一些愚蠢的东西。

思想?

1 个答案:

答案 0 :(得分:0)

要计算角速度,turnRate已经提供了幅度(rads / sec),所以你真正需要的就是旋转轴。这只是GetAxis( B * Inverse(A) )给出的。相同数量的GetAngle将给出两者之间的总角度。有关详细说明,请参阅'Difference' between two quaternions

SetAngularVelocity( Normalize( GetAxis( B * Inverse(A)) ) * turnRate )

您需要在某个时刻将角速度设置为0(达到目标方向时)。一种方法是使用quaternion distance。另一种更简单的方法是检查所花费的时间。最后,您可以检查两个quats之间的角度(如上所述)并检查它是否接近于0.

float totalAngle = GetAngle( Normalize( endingPose * Inverse( startingPose ) ) );
if( fabs( totalAngle ) > 0.0001 )  // some epsilon
{
     // your setting angular velocity code here 
     SetAngularVelocity(angularVelocity);
}
else
{
     SetAngularVelocity( Vector3f(0) );
     // Maybe, if you want high accuracy, call SetTransform here too
}

但是,实际上,我不明白为什么你不只是充分利用Slerp。您不必依赖物理积分器(可能不精确)并依赖于知道何时到达目的地(这有点尴尬),您可以逐帧移动对象,因为您知道运动。

Quaternion startingPose;
Quaternion endingPose;
// As discussed earlier...
Quaternion totalAngle = Quaternion.AngleBetween( startingPose, endingPose ); 

// t is set to 0 whenever you start a new motion
t += deltaT;

float howFarIn = (turnRate * t) / totalAngle; 
SetCurrentTransform( startingPose.Slerp( endingPose, howFarIn ) );

有关此问题的讨论,请参阅Smooth rotation with quaternions