Get applied Torque from AddForceAtPosition method

Currently, there is no way to retrieve torque that is applied when using AddForceAtPosition.
I suggest that either get torque as a return value from this function, or if it goes against some programming paradigm (like having side effects and return value), then add method e.g. CalculateTorqueFromForceAtPosition.

Sure it is fairly easy to implement this and I have made an extension method that does exactly that, but since the AddForceAtPosition method implementation is hidden in .dll, I think it would be better if it was provided by Unity. Applies to 3D and 2D physics.

The methods Rigidbody.GetAccumulatedForce and Rigidbody.GetAccumulatedTorque give you the amounts of force and torque that have been applied to the Rigidbody so far in the current simulation step.

So if you only call AddForceAtPosition once, then GetAccumulatedTorque will return the torque that has been applied to the Rigidbody as result of it.

Unity uses PhysX 4 for 3D physics, and the source code is available on GitHub:

https://github.com/NVIDIAGameWorks/PhysX

The implementation of AddForceAtPosition is here:

https://github.com/NVIDIAGameWorks/PhysX/blob/4.1/physx/source/physxextensions/src/ExtRigidBodyExt.cpp#L393

Essentially, it calculates the torque (which you’ve already calculated) and then applies both the force and the torque at the center of mass of the rigidbody.

In 2D physics, Unity uses Box2D with source code also available on GitHub. Here’s the implementation of AddForceAtPosition 2D:

https://github.com/erincatto/box2d/blob/main/include/box2d/b2_body.h#L743

2 Likes

As above (great answer) but also for 2D in 2023.1+ you could directly see the change by looking at the delta of:

You could use this in your extension method to return the torque change.

2 Likes

Good point, but my case is more complicated.

As I said, it’s easy to replicate/reverse engineer/find on github, that is not an issue. Just something that in my humble opinion should/could be part of Unity physics API by default.
The argument about it being hidden in .dll - Unity can do something on top of the PhysX method and also it’s about convenience - I can’t immediately see what is going on.

Good to know, thanks, h̶o̶p̶e̶ ̶i̶t̶ ̶w̶i̶l̶l̶ ̶g̶e̶t̶ ̶a̶d̶o̶p̶t̶e̶d̶ ̶b̶y̶ ̶3̶D̶ ̶p̶h̶y̶s̶i̶c̶s̶ ̶a̶s̶ ̶t̶h̶a̶t̶ ̶i̶s̶ ̶m̶y̶ ̶m̶a̶i̶n̶ ̶c̶o̶n̶c̶e̶r̶n̶ (edit: GetAccumulatedForce/Torque is the equivalent in 3D)

I see, I understand your point. Regarding rigid body dynamics, as far as I know, Unity simply exposes the PhysX API as it is. The only situations I’m aware of where there’s significant functionality hidden behind the scenes are related to the PhysX Vehicle SDK (WheelCollider). However, that’s a very special case.

1 Like

I just now realized what were you actually saying and that I should combine these two pieces of information:

so I could make my method like this:

    public static Vector3 AddForceAtPositionGetTorque(this Rigidbody rigidBody, Vector3 force, Vector3 position,
        ForceMode mode = ForceMode.Force)
    {
        var torque = Vector3.Cross(position - rigidBody.worldCenterOfMass, force);
        //rigidBody.AddForce(force, mode);
        //rigidBody.AddTorque(torque, mode);
        var before = rigidBody.GetAccumulatedTorque().z; // Only interested in "z" others are 0
        rigidBody.AddForceAtPosition(force, position, mode); // Same as above, but try Unity's method
        var after = rigidBody.GetAccumulatedTorque().z;
        Debug.Log($"{before} | {after} | {after - before}");
        Debug.Log(torque.z);
        return torque;
    }

But the “torque” calculated from cross product is not the same as “after - before”. However the physics simulation is correct wether I use my calculated torque or use unity’s AddForceAtPosition and then return my calculated torque (and use it further). What am I doing wrong?

No, I thought I was explicit when I mentioned 2D physics. I’m not a 3D physics engineer. I’ve not dug into the 3D physics side here.

The code looks good to me. However, I’d check and debug the vector values in any case, not just the Z.

If the physics simulation is correct in both cases then the discrepancy must not be relevant. Numeric imprecisions might be kicking in that may make the numbers to look different. These might come from different ways of calculating the torque, such as using world center of mass vs. local center of mass, or if/how/where the values are transformed into local space.

2 Likes

Certainly, it’s just that GetAccumulationForce sounded like a direct 3D counterpart.

It’s a top down game with only Z rotation allowed.

The discrepancy is of relevant order of magnitude however. E.g. torque from my cross product is 11 and torque from difference is 6. But I suspect it is something like the center of mass or different coordinate system in use. I will try to play with it some more.

Even in that case, I’d monitor the 3D parameters. For example, the value of the inertia tensor may induce a rotation around a different axis even if you apply your force expecting a perfect rotation around Z.

EDIT: Even if your rigidbody constraints allow Z rotation only, since PhysX 3 (Unity 5) I’ve seen cases of these constraints being violated in apparently regular situations.

Me too. And I monitor them (and they are zero as they should be), it’s just a simplified code for the sake of this thread. I set center of mass to pivot point (Vector3.zero) and inertia tensor to (0, 0, some positive value) from a script.

Btw. those unwanted rotations even if constraints are in place were in my experience caused by default center of mass being sometimes not aligned with pivot point for whatever reason and I had to set it to Vector3.zero. I guess the auto center of mass is calculated from colliders/mesh geometry.

1 Like