- Home /
Get Rigidbodies to Sleep Faster
I'm colorizing all the rigidbodies that are awake in my scene so it's easier to tell when they go to sleep, and currently, they're taking too long. I can afford to be extremely lenient with accuracy, so I don't mind if they stop simulating before fully settled.
Unfortunately, no amount of tweaking Sleep Velocity and Sleep Angular Velocity seems to work. I've incrementally cranked them up to 10000 from the default 0.14, and also tested 0.014 just to make sure I didn't misunderstand how those values are supposed to work.
I've also verified that the active rigidbodies are indeed getting set with the right sleep velocities.
As a final note, they seem to be deactivating in large groups/piles, which makes sense that the simulation would be recursive. I'd still like the piles to deactivate faster though.
Untested idea: Why not put them to sleep yourself. Add this line in Update() or FixedUpdate() on a script attached to these objects:
if (rigidbody.velocity.magnitude < someValue && rigidbody.angularVelocity.magnitude < someOtherValue)
rigidbody.Sleep();
Note angularVelocity is in radians.
To help them stay asleep, make sure that Sleep Angular Velocity and Sleep Velocity is set above the values you use in the 'if'. Plus you could set the rigidbody.velocity and rigidbody.angularVeloicty to Vector3.zero.
Hey, thanks man. Ironically, I just finished doing that, heh! Had to include a $$anonymous$$imum alive time too, otherwise they'd instantly go to sleep once activated. Also of note, for anyone else trying this, the docs say Vector3.sqr$$anonymous$$agnitude is faster than Vector3.magnitude because it avoids the expensive sqrt step, but still works perfectly fine for this application if you adjust the target velocity to compensate.
So, admittedly, it's working exactly how I'd LI$$anonymous$$E it to work through the built-in sleep functionality, but now I worry about doubled efforts, since I assume the internal sleep velocity calculations are still running... correct me if I'm wrong.
Also, I'd imagine the internal sleep checking to be more efficient than what I just whipped up, but that's also just a guess.
So yeah, this is definitely an option, but I wonder if I could squeeze more performance out of just wrangling the existing sleep functionality?
Try checking if the rigidbody.velocity is greater or equal to $$anonymous$$ / max on any / all axes. Here's an example that will kind of exaggerate what I'm saying here, just to show you how it will work, you can adjust things to be a bit closer to "settled" for more realistic results. This will catch the negative Y axis of a falling rigidbody cube.
//Example.cs
using UnityEngine;
using System.Collections;
public class Example : $$anonymous$$onoBehaviour
{
Color sleepColor;
Color awakeColor;
float $$anonymous$$Y;
Vector3 cur;
void Awake()
{
sleepColor = Color.red;
awakeColor = Color.green;
$$anonymous$$Y = -10f;
}
void Update()
{
cur = rigidbody.velocity;
if(cur.y <= $$anonymous$$Y)
{
renderer.material.color = sleepColor;
rigidbody.Sleep();
}
if(rigidbody.IsSleeping())
renderer.material.color = sleepColor;
else
renderer.material.color = awakeColor;
}
}
Answer by calbar · Sep 02, 2013 at 02:10 AM
Whelp, I was hoping to leverage the built-in sleep functionality, but I guess the manual approach is more flexible and easier to control.
This is my test for if the rigidbody is ready to go to sleep, as mentioned in my reply to robertbu:
if (grounded && aliveTime >= minimumAliveTime && rigidbody.velocity.sqrMagnitude < sleepVelocity)
3 important notes:
If you don't test whether the rigidbody is grounded (that is, colliding with something else) it's very common for a rigidbody flying near-vertical to freeze in mid-air, where velocity can come very close to 0 at the peak of its arc.
If you want a rigidbody to instantiate without an initial velocity (i.e. to let gravity naturally pull it down) you'll need to impose a minimum alive time before testing its velocity, otherwise it'll instantly go to sleep before it ever picks up enough speed to exceed the sleep threshold.
Use velocity.sqrMagnitude because it avoids the expensive sqrt step of velocity.magnitude, but still works perfectly fine for this situation if you adjust the sleep velocity.
To test whether it's grounded, just use the OnCollision methods Unity provides:
void OnCollisionEnter () { grounded = true; }
void OnCollisionStay () { grounded = true; }
void OnCollisionExit () { grounded = false; }
There's a chance with the above code that a rigidbody could hit a ceiling and freeze from satisfying the OnCollision state and velocity being less than the sleep threshold if it hits head-on. You might have to get a little fancier with your tests if this is a possibility in your game.
Doing the alive time is pretty straightforward:
public void Activate () { if (!rigidbody) { aliveTime = 0f; } }
void FixedUpdate () { if (rigidbody) { aliveTime += Time.deltaTime; } }
I've found a minimum alive time of 1 second and a sleep velocity of 0.1 work well for aggressively putting rigidbodies to sleep without sacrificing a lot of quality.
Your answer
Follow this Question
Related Questions
Why are my Rigidbodies not sleeping? 0 Answers
How do I change force of gravity for a single object? 4 Answers
Deactivate Rigibodies 1 Answer
Go to sleep. 0 Answers