问题:
我在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确实是正确的最终旋转变换。我觉得我在这里错过了一些愚蠢的东西。
思想?
答案 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。