When setting rigidbody.angularVelocity, it is applied in world space. That is, regardless of the object’s orientation, if I set rigidbody.angularVelocity to 0,0,1 it rotates on the global z axis. This is expected behavior.
The documentation says that rigidbody rotation constraints are in local space, i.e. relative to that object’s transform. This seems to be true most of the time, but surprisingly appears to switch coordinate systems and block angularVelocity setting in world space.
Here are some tests done under 5.6.0p4
Example A:
-
Place a rigidbody cube at default rotation of 0,0,0 (local transform matches world coordinates)
-
Set the angular velocity to 0,0,1 and observe it spinning on world z. This is also on the rigidbody’s local Z.
-
Constrain Z rotation on rigidbody. Observe it stop spinning. This is expected behavior.
-
Unconstrain Z rotation.
Example B
-
Place a rigidbody rotated to 0,90,0 (local forward points to world right)
-
Set the angular velocity to 0,0,1 and observe it spinning on world z, just as before. This is a rotation on the rigidbody’s local X.
-
Constrain X rotation on the rigidbody. Observe it stop spinning. This is expected behavior.
-
Unconstrain X rotation.
Example C
- Place a rigidbody rotated to 0,90,0 (local forward points to world right)
- Set the angular velocity to 0,0,1 again. Cube spins.
- Constrain Z rotation on rigidbody. Observe it continue to spin on world z because the local z doesn’t need to rotate to achieve this.
- With the Z rotation constrained, set the angular velocity again to 0,0,1. This is expected to be a redundant assignment with no effect, but it stops the rotation. Why?
What is going on in example C? Hard to imagine that something this fundamental could have been around so long if it’s not intended behavior, but it definitely is unexpected and weird from my POV. Am I missing something?
If you’d like more context: I set angularVelocity directly (every frame) to manage rotation of a rigidbody character controller with a PID. The game is psuedo 2d, so I’m hoping to rely on rigidbody constraints to some degree. AddTorque correctly navigates the constraints, but it’s harder to manage overshoots / oscillations.
Here’s a script to help test the examples. Note that it sets the angular velocity every frame so you’ll want to set applyAngularVelocity back to false before step C3 (or else it’ll trigger step C4 prematurely).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PhysicsTest : MonoBehaviour {
public bool applyAngularVelocity = false;
public Vector3 angularVelocity = Vector3.zero;
public bool reset;
Rigidbody _rigidbody;
private void Start()
{
_rigidbody = GetComponent<Rigidbody>();
}
private void Update()
{
if (applyAngularVelocity)
_rigidbody.angularVelocity = angularVelocity;
if (reset)
{
angularVelocity = Vector3.zero;
transform.localRotation = Quaternion.identity;
_rigidbody.angularVelocity = angularVelocity;
reset = false;
}
}
}