Bepu2 multiple objects sleeping at the same time.

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
Darkon76
Posts: 23
Joined: Mon Mar 27, 2017 12:33 pm

Bepu2 multiple objects sleeping at the same time.

Post by Darkon76 »

Hello currently I'm testing the latest version of bepu 2, my test consist of creating a big floor, and ring of stacked cubes (4k in total). After doing a simulation.Timestep I update the position of the internal transform. The problem is that the fps is constant and all the objects sleep at the same time creating a spike of 1.2seconds. Using bepu1 the objects slowly sleep lowering fps reliable.

I use the following code

Code: Select all

        protected internal override void Step()
        {
            Simulation.Timestep(dt, ThreadDispatcher);
            Bepu2ComponentHelper.UpdatePositions();
        }

        internal static void UpdatePositions()
        {
            for (var i = 0; i < Simulation.Bodies.Sets.Length; ++i)
            {
                ref var set = ref Simulation.Bodies.Sets[i];
                if (!set.Allocated)
                {
                    continue;
                }

                for (var bodyIndex = 0; bodyIndex < set.Count; ++bodyIndex)
                {
                    UpdatePose(i, bodyIndex);
                }
            }
        } 

        static void UpdatePose(int setIndex, int indexInSet)
        {
            ref var set = ref Simulation.Bodies.Sets[setIndex];
            var handle = set.IndexToHandle[indexInSet];

            if (setIndex == 0)
            {
                if (set.Activity [indexInSet].SleepCandidate)
                {
                    return;
                }

                if (IndexComponent.TryGetValue(handle, out var component))
                {
                    component.PositionChanged();
                }
            }
           
        }

  public void PositionChanged()
        {
            _preventPositionUpdate = true;
            transform.SetPositionOrientation(_bodyReference.Pose.Position.ToSdk(), _bodyReference.Pose.Orientation.ToSdk());
            _preventPositionUpdate = false;
        }
IndexComponent is a dictionary with the indexhandle and a component helper that updates the position and rotation of the internal transform, used for the renderer.


Is there a list of objects or index that where moved, or an event that an object was moved by the physics?
Also the user can manually move objects, which is the best way to wake up a sleeping object?
Darkon76
Posts: 23
Joined: Mon Mar 27, 2017 12:33 pm

Re: Bepu2 multiple objects sleeping at the same time.

Post by Darkon76 »

Update, I created the test as a bepu demo, the spike is still there, the test is pressing Z 4 times.

Code: Select all

using System;
using System.Numerics;
using BepuPhysics;
using BepuPhysics.Collidables;
using BepuUtilities;
using DemoContentLoader;
using DemoRenderer;
using DemoUtilities;
using Quaternion = BepuUtilities.Quaternion;

namespace Demos.Demos
{
    public class DropCircleTest : Demo
    {
        public override void Initialize(ContentArchive content, Camera camera)
        {
            camera.Position = new Vector3(-30, 8, -60);
            camera.Yaw = MathHelper.Pi * 3f / 4;
            camera.Pitch = 0;

            Simulation = Simulation.Create(BufferPool, new DefaultNarrowPhaseCallbacks(),
                new DefaultPoseIntegratorCallbacks(true /*new Vector3(0, -10, 0)*/));
            var boxShape = new Box(1, 1, 1);
            boxShape.ComputeInertia(1, out _boxInertia);
            _boxIndex = Simulation.Shapes.Add(boxShape);




            var staticShape = new Box(200, 1, 200);
            var staticShapeIndex = Simulation.Shapes.Add(staticShape);

            var staticDescription = new StaticDescription
            {
                Collidable = new CollidableDescription
                {
                    Continuity = new ContinuousDetectionSettings {Mode = ContinuousDetectionMode.Discrete},
                    Shape = staticShapeIndex,
                    SpeculativeMargin = 0.1f
                },
                Pose = new RigidPose
                {
                    Position = new Vector3(1, -0.5f, 1),
                    Orientation = Quaternion.Identity
                }
            };
            Simulation.Statics.Add(staticDescription);

        }

        private TypedIndex _boxIndex;
        private BodyInertia _boxInertia;

        private void CreateCircleCube(int sampleCount, float radius, int floorCount)
        {
            var wpCnt = sampleCount;
            var increment = MathHelper.Pi * 2 / wpCnt;

            var tempPos = Vector3.Zero;
            var offset = new Vector3(0, 0, 5);
            for (var j = 0; j < floorCount; j++)
            {
                for (float i = 0; i < MathHelper.Pi * 2 - increment / 2; i += increment)
                {
                    tempPos = new Vector3((float) Math.Sin(i) * radius, j * 2, (float) Math.Cos(i) * radius);

                    var bodyDescription = new BodyDescription
                    {
                        //Make the uppermost block kinematic to hold up the rest of the chain.
                        LocalInertia = _boxInertia,
                        Pose = new RigidPose
                        {
                            Position = tempPos,
                            Orientation = Quaternion.Identity
                        },
                        Activity = new BodyActivityDescription
                        {
                            MinimumTimestepCountUnderThreshold = 32,
                            SleepThreshold = .01f
                        },
                        Collidable = new CollidableDescription {Shape = _boxIndex, SpeculativeMargin = .1f},
                    };
                    Simulation.Bodies.Add(bodyDescription);
                }
            }
        }


        public override void Update(Window window, Camera camera, Input input, float dt)
        {
            if (input.WasPushed(OpenTK.Input.Key.Z))
            {
                CreateCircleCube(25, 16, 11);
                CreateCircleCube(25, 14, 10);
                CreateCircleCube(25, 12, 10);
                CreateCircleCube(25, 10, 9);
            }
            base.Update(window, camera, input, dt);
        }
    }
}
Gif of the profiler

https://imgur.com/a/Xukbntk

Looking at the profiler the fps is stable even that most of the cubes are sleeping, shouldn't the fps increase?


(I forgot to change to release that is why the spike in my side was of 1 sec(checking the bepu demo numbers I need to optimize a lot at my side)).
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Bepu2 multiple objects sleeping at the same time.

Post by Norbo »

Is there a list of objects or index that where moved, or an event that an object was moved by the physics?
Not exactly, but the Simulation.Bodies.ActiveSet (which is an alias for Simulation.Bodies.Sets[0]) contains every body which is awake, which is a reasonable proxy for 'stuff that moved'. As you've already done, you can further filter on whether it is a sleep candidate.
Also the user can manually move objects, which is the best way to wake up a sleeping object?
The Simulation.Awakener is the direct way. It has a few options, including AwakenBody. The AwakenSets function lets you activate one or more sets at the same time, optionally with multithreading.
Update, I created the test as a bepu demo, the spike is still there, the test is pressing Z 4 times.
In v2, sleeping is a much more aggressive optimization. The objects are moved into completely different data structures. This means having tens of thousands of sleeping objects is typically just fine (and will become even faster once I get around to finishing up some things in the broad phase). The downside is that moving objects into and out of sleeping is more expensive.

For simulation consistency, interacting objects (those which are connected by any form of constraint) must be activated or deactivated together. So, sleeping or waking piles of thousands of objects requires moving thousands objects around in memory at once. If you set up a simulation with separated piles, the spike would become trivial. (Except for the first time- the first time a codepath is hit, it has to be compiled by the JIT and that can be noticeable.)

The tradeoff was made under the assumption that games usually have many smaller groups of objects, rather than single enormous piles.

There are some plans to improve this in the future. I may also eventually make deactivation more aggressively asynchronous, but that comes with a great deal of complexity and wouldn't help activation.
Looking at the profiler the fps is stable even that most of the cubes are sleeping, shouldn't the fps increase?
If you mean the rendered FPS, only if the CPU was bottlenecking frame delivery. The demos don't bother trying to render faster than the display refresh rate. As the graph shows, the time spent in physics does indeed decrease significantly, so you could update more frequently if you wanted.
Darkon76
Posts: 23
Joined: Mon Mar 27, 2017 12:33 pm

Re: Bepu2 multiple objects sleeping at the same time.

Post by Darkon76 »

Thanks for the reply,
So to make it faster I only update the position of the objects at Simulation.Bodies.Sets[0] that aren't sleep candidates.
If you mean the rendered FPS, only if the CPU was bottlenecking frame delivery. The demos don't bother trying to render faster than the display refresh rate. As the graph shows, the time spent in physics does indeed decrease significantly, so you could update more frequently if you wanted.
Looking at the profiler it takes the same time to process 1k objects, than 500 active objects and 500 sleep objects. I expected when the objects went to sleep I get better performance. But with better knowledge of the library it is an expected behavior, because all the objects of the set are processed and when the set is fully sleep it is moved to a different set. Or something like that.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Bepu2 multiple objects sleeping at the same time.

Post by Norbo »

Looking at the profiler it takes the same time to process 1k objects, than 500 active objects and 500 sleep objects. I expected when the objects went to sleep I get better performance. But with better knowledge of the library it is an expected behavior, because all the objects of the set are processed and when the set is fully sleep it is moved to a different set. Or something like that.
The actual time it takes to complete a call to Simulation.Timestep() should decrease when objects enter a sleep state. As the graph in the gif you posted shows, it drops from ~6ms per timestep to 0.4ms or so with some noise (which is about as low as it'll go with multithreading- there's some constant overhead associated with thread wrangling even in an empty simulation).
Post Reply