# How to calculate a rigidbody's mass-normalized energy for sleepThreshold?

Discussion in 'Physics' started by Ludiq, Mar 18, 2015.

1. ### Ludiq

Joined:
Mar 6, 2015
Posts:
618
I'm using different gravities per area for my game and therefore I need to apply a gravitational force at each fixedUpdate. However, this won't let the rigidbodies sleep. I could manually make them sleep when they are below the sleep threshold (Physics.sleepThreshold), but I don't know how to calculate it for each object.

The documentation vaguely says "The mass-normalized energy threshold, below which objects start going to sleep." How is the mass-normalized energy calculated for a given rigidbody?

2. ### Partel-Lang

Joined:
Jan 2, 2013
Posts:
1,968
Kinetic energy is calculated by
Code (CSharp):
1. float E = rigidbody.mass * Mathf.Pow(rigidbody.velocity.magnitude, 2) * 0.5f;
mass-normalized probably means mass is just ignored, so that leaves us with:

Code (CSharp):
1. float E = Mathf.Pow(rigidbody.velocity.magnitude, 2) * 0.5f;
You should probably add to the result the rotational kinetic energy, which can be calculated the same way:

Code (CSharp):
1. E += Mathf.Pow(rigidbody.angularVelocity.magnitude, 2) * 0.5f;

3. ### Ludiq

Joined:
Mar 6, 2015
Posts:
618
I used these calculations, then compared it to the treshold (E < Physics.SleepTreshhold), but it seems that this triggers much more easily than Unity's default sleep. I also tried checking if that condition was maintained over 2 frames, and it's still triggering more easily. Any idea why?

4. ### Razieln64

Joined:
May 3, 2008
Posts:
129
Thanks for the info.

To speed up computations don't compute the power of 2.

You can write it as :

Code (csharp):
1. float E = rigidbody.velocity.sqrMagnitude * 0.5f
2. E += rigidbody.angularVelocity.sqrMagnitude * 0.5f;
Same thing with the angular velocity.

FlightOfOne and SparrowsNest like this.
5. ### Ludiq

Joined:
Mar 6, 2015
Posts:
618
Any update on this? Maybe from someone in the Unity physics team?

6. ### Abhinav91

Joined:
Oct 21, 2013
Posts:
67
Bumping this thread. I'm trying to understand this as well.
The Physics Manager documentation says "The mass-normalized kinetic energy threshold below which a non-kinematic Rigidbody may go to sleep. Rigidbodies whose kinetic energy divided by their mass is below this threshold will be candidates for sleeping."

I tried searching 'Mass-normalized Kinetic Energy' on Google because I don't know what 'Mass-normalized' means. Couldn't find anything. Then, according to the second sentence, I calculated the Kinetic Energy and divided it by the mass of the Rigidbody, and then compared that with the sleepThreshold, but the Rigidbody didn't go to sleep when the result went below the sleepThreshold value.

Last edited: Jan 24, 2016
7. ### Ludiq

Joined:
Mar 6, 2015
Posts:
618
You do have to call Sleep() in that if condition.

8. ### Abhinav91

Joined:
Oct 21, 2013
Posts:
67
I'm not setting the Rigidbody to sleep manually based on an IF condition. I'm letting the Physics engine handle that.
All I'm doing is calculating the Kinetic Energy and the (Kinetic Energy / Rigidbody Mass), and then seeing if either of these values match the sleepThreshold value when the Rigidbody is set to sleep.
I'm trying to understand exactly how the sleepThreshold is calculated.

Ludiq likes this.

Joined:
Oct 21, 2013
Posts:
67
*bump*

10. ### IronLionZion

Joined:
Dec 15, 2015
Posts:
74
I also would like to know the answer to this.

11. ### Abhinav91

Joined:
Oct 21, 2013
Posts:
67
Haha wow man! This thread is more than 1 year old. Has no one been able to find an answer to this yet? On my side, no luck so far.
Can any of the Unity Devs help us with this?

12. ### Partel-Lang

Joined:
Jan 2, 2013
Posts:
1,968
OK, decided to give it another try..

So according to the docs, sleep threshold is "The mass-normalized kinetic energy threshold below which a non-kinematic Rigidbody may go to sleep. Rigidbodies whose kinetic energy divided by their mass is below this threshold will be candidates for sleeping."

I found this paper for calculating the kinetic energy of a 3D rigid-body and arrived to this solution:

Code (CSharp):
1. /// <summary>
2.     /// Gets the mass normalized kinetic energy of a Rigidbody.
3.     /// </summary>
4.     public static float GetMassNormalizedKineticEnergy(Rigidbody r) {
5.         // Linear energy
6.         float E = 0.5f * r.mass * Mathf.Pow(r.velocity.magnitude, 2f);
7.
8.         // Angular energy
9.         E += 0.5f * r.inertiaTensor.x * Mathf.Pow(r.angularVelocity.x, 2f);
10.         E += 0.5f * r.inertiaTensor.y * Mathf.Pow(r.angularVelocity.y, 2f);
11.         E += 0.5f * r.inertiaTensor.z * Mathf.Pow(r.angularVelocity.z, 2f);
12.
13.         // Mass-normalized
14.         return E /= r.mass;
15.     }
Running it in a test got me thinking that the kinetic energy is not the only thing used for determining whether to sleep or not. Also the sleep threshold description seems to hint that ("may go to sleep"). So I figured there might be a timer involved so objects wouldn't go to sleep immediately after settling down or before being accelerated by gravitation. There are probably also collision events used to wake up the Rigidbody.
Anyway, I arrived to the script below. That is not a perfect match, but its usable at least I guess. Cant really debug it further without looking at the engine.

Code (CSharp):
1. using UnityEngine;
2. using System.Collections;
3.
4. public class KineticEnergyTest : MonoBehaviour {
5.
6.     private Rigidbody r;
7.     private float sleepTimer;
8.
9.     void Start() {
10.         r = GetComponent<Rigidbody>();
11.     }
12.
13.     void FixedUpdate() {
14.         // Calculate the mass-normalized kinetic energy
15.         float E = GetMassNormalizedKineticEnergy(r);
16.
17.         // Should the Rigidbody sleep according to our calculations?
18.         bool isSleeping = E < Physics.sleepThreshold;
19.
20.         // ...if so, run a timer...
21.         if (isSleeping) sleepTimer += Time.deltaTime;
22.         else sleepTimer = 0f;
23.
24.         // If timer has expired, consider it sleeping
25.         bool isSleepingFinally = sleepTimer >= 0.25f;
26.
27.         // Debugging
28.         bool isTrue = r.IsSleeping() == isSleepingFinally;
29.         if (!isTrue) Debug.Log("ERROR! Calculated sleeping " + isSleepingFinally + "; Rigidbody.IsSleeping(): " + r.IsSleeping() + "; Timer: " + sleepTimer);
30.     }
31.
32.     /// <summary>
33.     /// Gets the mass normalized kinetic energy of a Rigidbody.
34.     /// </summary>
35.     public static float GetMassNormalizedKineticEnergy(Rigidbody r) {
36.         // Linear energy
37.         float E = 0.5f * r.mass * Mathf.Pow(r.velocity.magnitude, 2f);
38.
39.         // Angular energy
40.         E += 0.5f * r.inertiaTensor.x * Mathf.Pow(r.angularVelocity.x, 2f);
41.         E += 0.5f * r.inertiaTensor.y * Mathf.Pow(r.angularVelocity.y, 2f);
42.         E += 0.5f * r.inertiaTensor.z * Mathf.Pow(r.angularVelocity.z, 2f);
43.
44.         // Mass-normalized
45.         return E /= r.mass;
46.     }
47.
48.     // Wake up if something collided with us.
49.     void OnCollisionEnter() {
50.         sleepTimer = 0f;
51.     }
52.
53.     // Wake up for example when ground has been pulled away from beneath us.
54.     void OnCollisionExit() {
55.         sleepTimer = 0f;
56.     }
57. }
Just make a scene with a Rigidbody and something for it to fall on and add the script to the Rigidbody.
The "ERROR" messages you'll get are the frames in which my calculations don't match with Rigidbody.IsSleeping();

Cheers,
Pärtel

shough and ilmario like this.
13. ### shough

Joined:
Sep 13, 2017
Posts:
5
@Partel-Lang Wow that is fantastic! Especially the GetMassNormalizedKineticEnergy. I think there is a scale of 1000x on the sleep threshold, i.e. a PhysX sleep threshold of 3 will stop when your kinetic energy value is 0.003.

14. ### shough

Joined:
Sep 13, 2017
Posts:
5
Here's a script that seems to work well for rolling ball sleep thresholding, it has a couple of modifications: 1) Taking the 1000x scale thing into account. 2) Checking if E is non-zero, in which case it won't force sleeping. This is needed because otherwise you can't start a sleeping object with ApplyForce.

Code (CSharp):
1. using System.Collections;
2. using System.Collections.Generic;
3. using UnityEngine;
4.
5. public class PlayerMotorST : MonoBehaviour {
6.
7.     Rigidbody rb;
8.
9.     const float CUSTOM_SLEEP_THRESHOLD = 5f / 1000f;
10.     float sleepTimer = 0f;
11.
12.     void Start () {
13.         rb = GetComponent<Rigidbody> ();
14.     }
15.
16.     void FixedUpdate () {
17.         // Calculate the mass-normalized kinetic energy
18.         float E = GetMassNormalizedKineticEnergy(rb);
19.
20.         // Should the Rigidbody sleep according to our calculations?
21.         bool shouldSleep = E < CUSTOM_SLEEP_THRESHOLD;
22.
23.         // Check if it is zeroed out
24.         bool isSleeping = shouldSleep && (E > 0.00001f);
25.
26.         Debug.Log ("E"+E);
27.         Debug.Log ("Should Sleep?" + shouldSleep);
28.         Debug.Log ("Is sleeping?" + isSleeping);
29.
31.         // ...if so, run a timer...
32.         if (isSleeping) sleepTimer += Time.deltaTime;
33.         else sleepTimer = 0f;
34.
35.         // If timer has expired, consider it sleeping
36.         bool isSleepingFinally = sleepTimer >= 0.25f;
37.
38.         //Execute
39.         if (isSleepingFinally)
40.             rb.Sleep ();
41.     }
42.
43.     float GetMassNormalizedKineticEnergy(Rigidbody r) {
44.         // Linear energy
45.         float E = 0.5f * r.mass * Mathf.Pow(r.velocity.magnitude, 2f);
46.
47.         // Angular energy
48.         E += 0.5f * r.inertiaTensor.x * Mathf.Pow(r.angularVelocity.x, 2f);
49.         E += 0.5f * r.inertiaTensor.y * Mathf.Pow(r.angularVelocity.y, 2f);
50.         E += 0.5f * r.inertiaTensor.z * Mathf.Pow(r.angularVelocity.z, 2f);
51.
52.         // Mass-normalized
53.         return E /= r.mass;
54.     }
55.
56.     // Wake up if something collided with us.
57.     void OnCollisionEnter() {
58.         sleepTimer = 0f;
59.     }
60.
61.     // Wake up for example when ground has been pulled away from beneath us.
62.     void OnCollisionExit() {
63.         sleepTimer = 0f;
64.     }
65.
66.
67. }
68.
Edit: Btw, the reason I looked into this is a problem where rolling balls freeze on inclines with the default Unity sleep threshold. They freeze at the peak of their movement when gravity is still acting. But the timer is a very nice fix for this, you could also use some kind of incline sensing if you really need to fine tune it.

Edit 2: Revisiting this post realizing I'm a moron. You can simply send a WakeUp call.

Last edited: Jan 1, 2019