Calculating the rotational acceleration from torque

I’m trying to write a function that takes a Vector3 of torque and calculates the resulting radial acceleration in radians per second per second. I understand that I’ll need to use the rigidbody.inertiaTensor and rigidbody.inertiaTensorRotation to do this, but I don’t know how they work. Does anybody know how to do this? I would like it to be as accurate as possible. I imagine the signature of the function would be something like the below.

public static Vector3 TorqueToAcceleration(Vector3 torque, Vector3 inertialTensor, Quaternion inertialTensorRotation, float rigidbodyMass) {
	// Magic happens here
}

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

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.xB.x, A.yB.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.

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. 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.

The same thing seems to apply for “VelocityChange”. VelocityChange and Acceleration both ignore the tensor but still divide by the mass.