I have a space based lunar module game and I want to display the rotation rate of each axis in the HUD.
I'm not very good with vector math and I tried using the rigidbody.angular velocity but that is aligned with the world axis I quickly found out.
So I tried using the localEulerAngles and testing the difference between them every second.
Like this:
void FixedUpdate()
{
if (Time.time >= nextSample)
{
pitchDiff = Mathf.Abs(Lunar.transform.localEulerAngles.x - lastPitchAngle);
yawDiff = Mathf.Abs(Lunar.transform.localEulerAngles.y - lastYawAngle);
rollDiff = Mathf.Abs(Lunar.transform.localEulerAngles.z - lastRollAngle);
lastPitchAngle = Lunar.transform.localEulerAngles.x;
lastYawAngle = Lunar.transform.localEulerAngles.y;
lastRollAngle = Lunar.transform.localEulerAngles.z;
nextSample = Time.time + sampleRate;
}
}
This 'sort of' works but I get bad results when the angle passes to and from 360 to 1 within a second.
I also noticed that it gets less accurate the faster the object spins.
This does seem like a rather crappy approach or I just need to find a better way to derive the angle difference every second.
I essentially want they 'local' angular velocity of each axis.
Try using DeltaAngle. This gives you the minimum difference between two angles
pitchDiff = Mathf.DeltaAngle(Lunar.transform.localEulerAngles.x, lastPitchAngle);
I ended up using the Angle class on the Unify Wiki which has a Difference function.
void FixedUpdate()
{
// This code relys on the Angle class which is a Boo script in the standard assets/scripts folder
Angle cx = new Angle(Lunar.transform.localEulerAngles.x, AngleMode.Degree);
Angle cy = new Angle(Lunar.transform.localEulerAngles.y, AngleMode.Degree);
Angle cz = new Angle(Lunar.transform.localEulerAngles.z, AngleMode.Degree);
if (Time.time >= nextSample)
{
Angle lx = new Angle(lastPitchAngle, AngleMode.Degree); // Pitch
pitchRate = (float)(cx.Difference(lx)).Deg;
Angle ly = new Angle(lastYawAngle, AngleMode.Degree); // Yaw
yawRate = (float)(cy.Difference(ly)).Deg;
Angle lz = new Angle(lastRollAngle, AngleMode.Degree); //Roll
rollRate = (float)(cz.Difference(lz)).Deg;
// update last angle values for next sample
lastPitchAngle = Lunar.transform.localEulerAngles.x;
lastYawAngle = Lunar.transform.localEulerAngles.y;
lastRollAngle = Lunar.transform.localEulerAngles.z;
nextSample = Time.time + sampleRate;
}
}
So here's the current 'realtime' solution, I ended up making my own Angle Difference function and got rid of the Angle class as it was written in Boo and was introducing some weird floating point error.
float AngleDifference(float angA, float angB)
{
float diff = Mathf.Abs(angA - angB);
if (diff > 180) diff = 360 - diff;
return diff;
}
void FixedUpdate() // used to calculate roll rates and add rotation stabilisation when rotation rate is very low.
{
float frameDivider = 1 / Time.deltaTime;
pitchRate = AngleDifference(Lunar.transform.localEulerAngles.x, lastPitchAngle) * frameDivider;
yawRate = AngleDifference(Lunar.transform.localEulerAngles.y, lastYawAngle) * frameDivider;
rollRate = AngleDifference(Lunar.transform.localEulerAngles.z, lastRollAngle) * frameDivider;
// update last angle values for next sample
lastPitchAngle = Lunar.transform.localEulerAngles.x;
lastYawAngle = Lunar.transform.localEulerAngles.y;
lastRollAngle = Lunar.transform.localEulerAngles.z;
}
There is a problem still though, Yaw and Roll work perfectly when rotating on a single axis but if I rotate only around the X axis (Pitch) as the angle approaches 90 degrees forward or backward, Yaw and Roll start to show a change in their value, this is because the Euler angles are also World Axis aligned. I tested this by rolling 90 degrees to the side then applying a pitch rotation which caused the Yaw value to change.
So it looks like I am going to have to use some sort of more complex vector derived solution...
Hi,
just found your question. Maybe my reply helps others.
Transform _transform;
Rigidbody _rigidbody;
float degreePerSecondY;
Vector3 cachedAngularVelocity;
void Awake() {
_transform = transform; // Transform into cache
_rigidbody = rigidbody; // Rigidbody into cache
}
void FixedUpdate() {
cachedAngularVelocity = _transform.InverseTransformDirection(_rigidbody.angularVelocity);
degreePerSecondY = cachedAngularVelocity.y/Time.fixedDeltaTime;
}