根据四元数确定调整方向所需的 angular 速度

Determining angular velocity required to adjust orientation based on Quaternions

问题:

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

我基本上需要确定将 body 定向到所需方向所需的 angular 速度。

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

伪代码:

// 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);

这基本上只会让我的 object 旋转到被遗忘的地步。我已经验证了我通过轴构建的 desiredOrientMtx 确实是正确的最终旋转变换。我觉得我在这里遗漏了一些愚蠢的东西。

想法?

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

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

您需要在某个时刻(当您到达目标方向时)将 angular 速度设置为 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