Exemple #1
0
        protected Simulation(BufferPool bufferPool, SimulationAllocationSizes initialAllocationSizes)
        {
            BufferPool = bufferPool;
            Shapes     = new Shapes(bufferPool, initialAllocationSizes.ShapesPerType);
            BroadPhase = new BroadPhase(bufferPool, initialAllocationSizes.Bodies, initialAllocationSizes.Bodies + initialAllocationSizes.Statics);
            Bodies     = new Bodies(bufferPool, Shapes, BroadPhase,
                                    initialAllocationSizes.Bodies,
                                    initialAllocationSizes.Islands,
                                    initialAllocationSizes.ConstraintCountPerBodyEstimate);
            Statics = new Statics(bufferPool, Shapes, Bodies, BroadPhase, initialAllocationSizes.Statics);

            Solver = new Solver(Bodies, BufferPool, 8,
                                initialCapacity: initialAllocationSizes.Constraints,
                                initialIslandCapacity: initialAllocationSizes.Islands,
                                minimumCapacityPerTypeBatch: initialAllocationSizes.ConstraintsPerTypeBatch);
            constraintRemover = new ConstraintRemover(BufferPool, Bodies, Solver);
            Sleeper           = new IslandSleeper(Bodies, Solver, BroadPhase, constraintRemover, BufferPool);
            Awakener          = new IslandAwakener(Bodies, Statics, Solver, BroadPhase, Sleeper, bufferPool);
            Statics.awakener  = Awakener;
            Solver.awakener   = Awakener;
            Bodies.Initialize(Solver, Awakener);
            PoseIntegrator            = new PoseIntegrator(Bodies, Shapes, BroadPhase);
            SolverBatchCompressor     = new BatchCompressor(Solver, Bodies);
            BodyLayoutOptimizer       = new BodyLayoutOptimizer(Bodies, BroadPhase, Solver, bufferPool);
            ConstraintLayoutOptimizer = new ConstraintLayoutOptimizer(Bodies, Solver);
        }
Exemple #2
0
        public Simulation(BufferPool bufferPool, SimulationAllocationSizes initialAllocationSizes, int solverIterationCount, int solverFallbackBatchThreshold, ITimestepper timestepper)
        {
            BufferPool = bufferPool;
            Shapes     = new Shapes(bufferPool, initialAllocationSizes.ShapesPerType);
            BroadPhase = new BroadPhase(bufferPool, initialAllocationSizes.Bodies, initialAllocationSizes.Bodies + initialAllocationSizes.Statics);
            Bodies     = new Bodies(bufferPool, Shapes, BroadPhase,
                                    initialAllocationSizes.Bodies,
                                    initialAllocationSizes.Islands,
                                    initialAllocationSizes.ConstraintCountPerBodyEstimate);
            Statics = new Statics(bufferPool, Shapes, Bodies, BroadPhase, initialAllocationSizes.Statics);

            Solver = new Solver(Bodies, BufferPool, solverIterationCount, solverFallbackBatchThreshold,
                                initialCapacity: initialAllocationSizes.Constraints,
                                initialIslandCapacity: initialAllocationSizes.Islands,
                                minimumCapacityPerTypeBatch: initialAllocationSizes.ConstraintsPerTypeBatch);
            constraintRemover = new ConstraintRemover(BufferPool, Bodies, Solver);
            Sleeper           = new IslandSleeper(Bodies, Solver, BroadPhase, constraintRemover, BufferPool);
            Awakener          = new IslandAwakener(Bodies, Statics, Solver, BroadPhase, Sleeper, bufferPool);
            Statics.awakener  = Awakener;
            Solver.awakener   = Awakener;
            Bodies.Initialize(Solver, Awakener);
            SolverBatchCompressor     = new BatchCompressor(Solver, Bodies);
            BodyLayoutOptimizer       = new BodyLayoutOptimizer(Bodies, BroadPhase, Solver, bufferPool);
            ConstraintLayoutOptimizer = new ConstraintLayoutOptimizer(Bodies, Solver);
            Timestepper = timestepper;
        }
Exemple #3
0
 /// <summary>
 /// Clears the simulation of every object and returns all pooled memory to the buffer pool. Leaves the simulation in an unusable state.
 /// </summary>
 public void Dispose()
 {
     Clear();
     Activator.Dispose();
     Deactivator.Dispose();
     Solver.Dispose();
     BroadPhase.Dispose();
     NarrowPhase.Dispose();
     Bodies.Dispose();
     Statics.Dispose();
     BodyLayoutOptimizer.Dispose(BufferPool);
     Shapes.Dispose();
 }
Exemple #4
0
 /// <summary>
 /// Increases the allocation size of any buffers too small to hold the allocation target, and decreases the allocation size of any buffers that are unnecessarily large.
 /// </summary>
 /// <remarks>
 /// <para>
 /// The final size of the allocated buffers are constrained by the allocator. It is not guaranteed to be exactly equal to the target, but it is guaranteed to be at least as large.
 /// </para>
 /// <para>
 /// This is primarily a convenience function. Everything it does internally can be done externally.
 /// For example, if only type batches need to be resized, the solver's own functions can be used directly.
 /// </para>
 /// </remarks>
 /// <param name="allocationTarget">Allocation sizes to guarantee sufficient size for.</param>
 public void Resize(SimulationAllocationSizes allocationTarget)
 {
     Solver.ResizeSolverCapacities(allocationTarget.Bodies, allocationTarget.Constraints);
     Solver.MinimumCapacityPerTypeBatch = allocationTarget.ConstraintsPerTypeBatch;
     Solver.ResizeTypeBatchCapacities();
     //Note that the bodies set has to come before the body layout optimizer; the body layout optimizer's sizes are dependent upon the bodies set.
     Bodies.Resize(allocationTarget.Bodies);
     Bodies.MinimumConstraintCapacityPerBody = allocationTarget.ConstraintCountPerBodyEstimate;
     Bodies.ResizeConstraintListCapacities();
     BodyLayoutOptimizer.ResizeForBodiesCapacity(BufferPool);
     Statics.Resize(allocationTarget.Statics);
     Shapes.ResizeBatches(allocationTarget.ShapesPerType);
     BroadPhase.Resize(allocationTarget.Bodies, allocationTarget.Bodies + allocationTarget.Statics);
 }
Exemple #5
0
        //TODO: I wonder if people will abuse the dt-as-parameter to the point where we should make it a field instead, like it effectively was in v1.
        /// <summary>
        /// Performs one timestep of the given length.
        /// </summary>
        /// <remarks>
        /// Be wary of variable timesteps. They can harm stability. Whenever possible, keep the timestep the same across multiple frames unless you have a specific reason not to.
        /// </remarks>
        /// <param name="dt">Duration of the time step in time.</param>
        public void Timestep(float dt, IThreadDispatcher threadDispatcher = null)
        {
            ProfilerClear();
            ProfilerStart(this);
            //Note that the first behavior-affecting stage is actually the pose integrator. This is a shift from v1, where collision detection went first.
            //This is a tradeoff:
            //1) Any externally set velocities will be integrated without input from the solver. The v1-style external velocity control won't work as well-
            //the user would instead have to change velocities after the pose integrator runs. This isn't perfect either, since the pose integrator is also responsible
            //for updating the bounding boxes used for collision detection.
            //2) By bundling bounding box calculation with pose integration, you avoid redundant pose and velocity memory accesses.
            //3) Generated contact positions are in sync with the integrated poses.
            //That's often helpful for gameplay purposes- you don't have to reinterpret contact data when creating graphical effects or positioning sound sources.

            //TODO: This is something that is possibly worth exposing as one of the generic type parameters. Users could just choose the order arbitrarily.
            //Or, since you're talking about something that happens once per frame instead of once per collision pair, just provide a simple callback.
            //(Or maybe an enum even?)
            //#1 is a difficult problem, though. There is no fully 'correct' place to change velocities. We might just have to bite the bullet and create a
            //inertia tensor/bounding box update separate from pose integration. If the cache gets evicted in between (virtually guaranteed unless no stages run),
            //this basically means an extra 100-200 microseconds per frame on a processor with ~20GBps bandwidth simulating 32768 bodies.

            //Note that the reason why the pose integrator comes first instead of, say, the solver, is that the solver relies on world space inertias calculated by the pose integration.
            //If the pose integrator doesn't run first, we either need
            //1) complicated on demand updates of world inertia when objects are added or local inertias are changed or
            //2) local->world inertia calculation before the solver.

            ProfilerStart(PoseIntegrator);
            PoseIntegrator.Update(dt, BufferPool, threadDispatcher);
            ProfilerEnd(PoseIntegrator);

            ProfilerStart(BroadPhase);
            BroadPhase.Update(threadDispatcher);
            ProfilerEnd(BroadPhase);

            ProfilerStart(BroadPhaseOverlapFinder);
            BroadPhaseOverlapFinder.DispatchOverlaps(threadDispatcher);
            ProfilerEnd(BroadPhaseOverlapFinder);

            ProfilerStart(NarrowPhase);
            NarrowPhase.Flush(threadDispatcher, threadDispatcher != null && Deterministic);
            ProfilerEnd(NarrowPhase);

            ProfilerStart(Solver);
            if (threadDispatcher == null)
            {
                Solver.Update(dt);
            }
            else
            {
                Solver.MultithreadedUpdate(threadDispatcher, BufferPool, dt);
            }
            ProfilerEnd(Solver);

            //Note that constraint optimization should be performed after body optimization, since body optimization moves the bodies- and so affects the optimal constraint position.
            //TODO: The order of these optimizer stages is performance relevant, even though they don't have any effect on correctness.
            //You may want to try them in different locations to see how they impact cache residency.
            ProfilerStart(BodyLayoutOptimizer);
            if (threadDispatcher == null)
            {
                BodyLayoutOptimizer.IncrementalOptimize();
            }
            else
            {
                BodyLayoutOptimizer.IncrementalOptimize(BufferPool, threadDispatcher);
            }
            ProfilerEnd(BodyLayoutOptimizer);

            ProfilerStart(ConstraintLayoutOptimizer);
            ConstraintLayoutOptimizer.Update(BufferPool, threadDispatcher);
            ProfilerEnd(ConstraintLayoutOptimizer);

            ProfilerStart(SolverBatchCompressor);
            SolverBatchCompressor.Compress(BufferPool, threadDispatcher, threadDispatcher != null && Deterministic);
            ProfilerEnd(SolverBatchCompressor);

            ProfilerEnd(this);
        }