Search Unity

Question Rigidbody wakes up when setting its velocity to zero

Discussion in 'Physics' started by arkano22, Feb 5, 2021.

  1. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,929
    Hi there,

    Talking about the built-in physics engine here (not ECS physics or Havok) in Unity 2019.3: Setting a rigidbody's linear/angular velocities to a value that's below their respective sleep thresholds seems to wake them up.

    This code:

    Code (CSharp):
    1. rigidbody.velocity += Vector3.zero;
    Keeps the rigidbody ever awake, and this behavior seems extremely surprising to me. Why? Shouldn't a rigidbody check if it's velocity is above the sleeping threshold at the end of a step, and if so wake up? Why wake it up automatically when setting its velocity to *any* value?

    One could argue that since FixedUpdate() is called before the physics update, waking the rigidbody up immediately so it can be simulated in the same frame it woke up (instead of taking a one-frame delay) is a good idea, and rightly so. But why not checking its velocity before waking it up?

    Can anyone share some insight about this? Is this a bug or a feature(tm)?
     
    Last edited: Feb 5, 2021
  2. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,929
    Moreover, PhysX's documentation explicitly states that setting the velocity of a rigidbody won't wake it up unless the velocity is larger than zero:

    https://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/guide/Manual/RigidBodyDynamics.html
    Which makes a ton of sense. I'm inclined to think this is a bug in Unity. Thoughts?
     
  3. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    596
    Taking a look right now. I can reproduce it, and seemingly nothing actually wakes the body explicitly, but it's clearly awake after the velocity assignment. We use autowake = true, but unless zero is not quite equal to zero somewhere down the pipes it shouldn't matter should it.
     
  4. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,929
    Hi Yant,

    Thanks a lot for taking a look! I'd assume you guys mostly wrap around PhysX with minimal/no additional changes to the actual physics simulation itself, so a floating point comparison issue somewhere makes sense.

    Haven't tested this with raw PhysX, might be a good idea to do so in order to prune potential culprits.
     
  5. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    596
    Looks this is the behaviour of PhysX.

    When you call that Rigidbody.velocity accessor, it actually goes directly here: https://github.com/NVIDIAGameWorks/...hysx/source/physx/src/NpRigidDynamic.cpp#L238

    Notice that wakeUpInternalNoKinematicTest function. Check its implementation here: https://github.com/NVIDIAGameWorks/...hysx/source/physx/src/NpRigidDynamic.cpp#L532

    Practically, when entering that function forceWakeUp = false (because velocity == 0), and autoWake = true. With these parameters, it will naturally proceed to body.wakeUpInternal(wakeCounter) which just writes to the buffer any IsSleeping reads from. WakeCounter is 0 initially (because of sleeping), and it will be reset to ~0.4 (the default wake counter).
     
    arkano22 likes this.
  6. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,929
    So when using autoWake, the rigidbody is always waken up upon setting its velocity. From wakeUpInternalNoKinematicTest:

    Code (csharp):
    1. bool needsWakingUp = body.isSleeping() && (autowake || forceWakeUp);
    And forceWakeUp equals !velocity.isZero() when called from setVelocity. Turns out this is documented otherwise:

    https://docs.nvidia.com/gameworks/c...hysx/apireference/files/classPxRigidBody.html

    Notice the ...and the velocity is non-zero part.

    This is easy to workaround in Unity, by checking if the velocity is below a threshold before setting it. However it's not very elegant or performant when done repeatedly with many rigidbodies, imho.

    Edited out, later re-added: Don't know the reasons behind always using autoWake, but could make sense to add an extra parameter to rigidbody.AddForce and rigidbody.AddTorque() to mimic PhysX's functions signature. That way the user could control this behavior.
     
    Last edited: Feb 5, 2021
  7. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    596
    Your suggestion about exposing a set of additional methods that expose autoWake make sense, we should take a look at that eventually. Thanks for your feedback.
     
    arkano22 likes this.