Comments and answers for "Calculating the rotational acceleration from torque"
http://answers.unity.com/questions/821833/calculating-the-rotational-acceleration-from-torqu.html
The latest comments and answers for the question "Calculating the rotational acceleration from torque"Answer by Bunny83
http://answers.unity.com/answers/1084009/view.html
*Converted the comment into an answer.*
@Nimred
Yes, it seems you're right ^^. I just copied his comment into the question but hadn't a closer look at what he has done there. Your code looks right to me.
Vector3.Scale just does a component wise multiplication. So Vector3.Scale(A,B) == new Vector3(A.x*B.x, A.y*B.y, A.z*B.z); So one vector scales the other component wise.
Unfortunately there's no component wise reciprocal operator or method. However we could simply write one ^^:
public static class Vector3Extension
{
public static Vector3 Reciprocal(this Vector3 v)
{
return new Vector3(1f/v.x, 1f/v.y, 1f/v.z);
}
}
With that helper method I've created this method which seems to be correct:
public static Vector3 ApplyTensor(Rigidbody rb, Vector3 worldAcceleration)
{
var q = rb.transform.rotation * rb.inertiaTensorRotation;
var qi = Quaternion.Inverse(q);
var acc = qi * worldAcceleration;
acc = Vector3.Scale(acc, rb.inertiaTensor.Reciprocal());
return q * acc;
}
I've created a test scene where i added two identical rigidbodies. In FixedUpdate i used
R1.AddTorque(torque,ForceMode.Force);
acc = ApplyTensor(R2, torque);
R2.AddTorque(acc, ForceMode.Acceleration);
And the result is identical. Even when i select both objects, the inspector shows all rotation values as identical. I also tested with a rotated tensor.
***edit***
The following is actually wrong ^^. I was under the impression that the inertia tensor just contains the "mass distribution" for a given collider setup and the mass would be somehow included in the actual calculation when a force is "converted" to the angular acceleration. However it turns out that it's not possible to linearly "scale" the inertia tensor by the actual mass.
So what Unity / Physx does is to calculate the inertia tensor based on the given mass and collider setup. The tensor already contains the mass. So the above method is actually correct.
<strike>It seems that the "acceleration" mode for torque is internally also dividing the acceleration by the rigidbodies mass. That actually must be a bug in Unity. See [ForceMode][1]. The acceleration is not dependent on the mass, only forces are. So usually to get the real "acceleration" you would need to divide by the mass as well.</strike>
<strike>The same thing seems to apply for "VelocityChange". VelocityChange and Acceleration both ignore the tensor but still divide by the mass.</strike>
[1]: http://docs.unity3d.com/ScriptReference/ForceMode.htmlSun, 18 Oct 2015 14:32:44 GMTBunny83Comment by Nimred on Nimred's comment
http://answers.unity.com/comments/1083876/view.html
Thanks, but now I have to wonder why there's a $$anonymous$$athf.Abs :) Angular acceleration should be a Vector3 representing the axis of rotation, multiplied by an amount of rotation around that axis... So the values shouldn't always be positive.
On the other hand, I tried to invert the answer from [this question][1], which solves how to find the (world space) angular acceleration from torque:
Quaternion tensorRotationWS = rigidbody.transform.rotation * rigidbody.inertiaTensorRotation;
Vector3 torque = tensorRotationWS * Vector3.Scale(rigidbody.inertiaTensor, Quaternion.Inverse(tensorRotationWS ) * angularAcceleration );
I don't completely understand it, so I don't really know if it's correct - but it works ingame. Converted to relative torque, with a world-space angular acceleration input, it should be this:
Quaternion tensorRotationWS = rigidbody.transform.rotation * rigidbody.inertiaTensorRotation;
Quaternion tensorRotationLS = rigidbody.inertiaTensorRotation;
Vector3 relativeTorque = tensorRotationLS * Vector3.Scale(rigidbody.inertiaTensor, Quaternion.Inverse(tensorRotationWS) * angularAcceleration);
Once inverted to convert relative torque to angular acceleration, I get this:
Quaternion tensorRotationLS = rigidBody.inertiaTensorRotation;
Vector3 tensorLocalTorque= Quaternion.Inverse(tensorRotationLS) * relativeTorque;
Vector3 tensorLocalAcceleration;
tensorLocalAcceleration.x = tensorLocalTorque.x / rigidbody.inertiaTensor.x;
tensorLocalAcceleration.y = tensorLocalTorque.y / rigidbody.inertiaTensor.y;
tensorLocalAcceleration.z = tensorLocalTorque.z / rigidbody.inertiaTensor.z;
Vector3 angularAccelerationLS = tensorRotationLS * tensorLocalAcceleration;
Vector3 angularAccelerationWS = transform.rotation * angularAccelerationLS;
Unfortunately since this is based on a formula I don't fully understand, I can't be 100% sure that it's right. The inversion itself is consistent, so that when I convert an acceleration to torque and back again I get the same acceleration; and it also works properly with my spaceship ingame. But I can't explain the differences with your formula...
[1]: http://answers.unity3d.com/questions/48836/deter$$anonymous$$ing-the-torque-needed-to-rotate-an-object.htmlSun, 18 Oct 2015 11:18:27 GMTNimredComment by Bunny83 on Bunny83's comment
http://answers.unity.com/comments/1083742/view.html
I copied your "corrected" code into your answer. There's no point in keeping a wrong answer ^^.Sun, 18 Oct 2015 01:56:15 GMTBunny83Comment by PeterReeves on PeterReeves's comment
http://answers.unity.com/comments/1083724/view.html
The * 50.0f was there since the default physics timestep is a 50th of a second.
I've updated the code by the way (the original I posted turns out to be not quite correct):
public static Vector3 TorqueToAcceleration(Vector3 relativeTorque, Vector3 inertialTensor, Quaternion inertialTensorRotation) {
inertialTensor = inertialTensorRotation * inertialTensor;
float x = $$anonymous$$athf.Abs(relativeTorque.x / inertialTensor.x);
float y = $$anonymous$$athf.Abs(relativeTorque.y / inertialTensor.y);
float z = $$anonymous$$athf.Abs(relativeTorque.z / inertialTensor.z);
return new Vector3(x, y, z);
}Sun, 18 Oct 2015 00:28:15 GMTPeterReevesComment by Nimred on Nimred's answer
http://answers.unity.com/comments/1083532/view.html
Nice, I was looking for this... but why * 50.0f? It seems a bit magical...Sat, 17 Oct 2015 16:25:44 GMTNimredAnswer by PeterReeves
http://answers.unity.com/answers/824541/view.html
Well, I manged to find an answer.
Thanks to help from a friend, the vector seems to contain an object's resistance to being rotated on each axis, and the quaternion only changes if you have a shape that is not symmetrical.
// copied from comment below
public static Vector3 TorqueToAcceleration(Vector3 relativeTorque, Vector3 inertialTensor, Quaternion inertialTensorRotation) {
inertialTensor = inertialTensorRotation * inertialTensor;
float x = Mathf.Abs(relativeTorque.x / inertialTensor.x);
float y = Mathf.Abs(relativeTorque.y / inertialTensor.y);
float z = Mathf.Abs(relativeTorque.z / inertialTensor.z);
return new Vector3(x, y, z);
}Wed, 05 Nov 2014 10:38:50 GMTPeterReeves