0
\$\begingroup\$

I am attempting to calculate an angular velocity that will get me from the current gameObject.transform.rotation to a given Quaternion rotation using angular velocity. I've tried several methods but all of them seem to cause oscillation (maybe due to the gimbal nature of Vector3 for angular velocity).

Here are the pieces of code that I have tried:

Quaternion rotationDelta = Quaternion.Inverse(gameObject.transform.rotation) * remoteRotation;
return (rotationDelta.eulerAngles / PlayerMovement.BROADCAST_INTERVAL);

Another attempt using toAngleAxis:

rotationDelta.ToAngleAxis(out angleInDegrees, out rotationAxis);
Vector3 angularDisplacement = rotationAxis * angleInDegrees * Mathf.Deg2Rad;
return angularDisplacement / PlayerMovement.BROADCAST_INTERVAL;

Using Eulers:

 Vector3 difference = new Vector3(Mathf.DeltaAngle(gameObject.transform.rotation.eulerAngles.x, remoteRotation.eulerAngles.x),
                                  Mathf.DeltaAngle(gameObject.transform.rotation.eulerAngles.y, remoteRotation.eulerAngles.y),
                                  Mathf.DeltaAngle(gameObject.transform.rotation.eulerAngles.z, remoteRotation.eulerAngles.z));

 Vector3 differenceInRadians = new Vector3(difference.x * Mathf.Deg2Rad,
                                           difference.y * Mathf.Deg2Rad,
                                           difference.z * Mathf.Deg2Rad);

 return differenceInRadians / PlayerMovement.BROADCAST_INTERVAL;
\$\endgroup\$
1
\$\begingroup\$

"maybe due to the gimbal nature of Vector3 for angular velocity" ...using Vector3 for angular velocity does not entail gimbals, but converting it to Euler angles does.

Angular velocity is not an Euler angle where each axis is a rotation rate about that axis. It's a vector pointing in the direction of the axis of rotation, with length proportional to the speed of rotation.

Treating it this way, we can get much more stable and intuitive results:

// Rotations stack right to left,
// so first we undo our rotation, then apply the target.
var delta = remote.rotation * Quaternion.Inverse(body.rotation);

float angle; Vector3 axis;
delta.ToAngleAxis(out angle, out axis);        

// We get an infinite axis in the event that our rotation is already aligned.
if (float.IsInfinity(axis.x))
    return;

if (angle > 180f)
    angle -= 360f;

// Here I drop down to 0.9f times the desired movement,
// since we'd rather undershoot and ease into the correct angle
// than overshoot and oscillate around it in the event of errors.
Vector3 angular = (0.9f * Mathf.Deg2Rad * angle / interval) * axis.normalized;

body.angularVelocity = angular;
\$\endgroup\$
  • \$\begingroup\$ This is amazing - I've been stuck on this for awhile so thanks a ton. One more question, if you don't mind, it looks to work very well on most objects but when done with a large object(with a lot of child game objects) it has a slight stutter to it. I tried always setting the velocity to the remote velocity (totally smooth when I do that) and use this method as a correction (amplifies the jitter) \$\endgroup\$ – Dave C Aug 20 '17 at 20:54
  • \$\begingroup\$ I don't have any insights about that at present, unfortunately. I'd recommend asking about that in a new question. \$\endgroup\$ – DMGregory Aug 20 '17 at 20:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.