static void CreateAndRunSimulation(BufferPool bufferPool) { //TODO: As more features get added, you'll probably want to revisit this and lengthen the per-execution duration. var simulation = Simulation.Create(bufferPool, new TestCallbacks()); var sphere = new Sphere(0.5f); var shapeIndex = simulation.Shapes.Add(sphere); var bodyBuilder = new RegularGridWithKinematicBaseBuilder(new Vector3(1), new Vector3(), 1, shapeIndex); var constraintBuilder = new BallSocketConstraintBuilder(); const int width = 3; const int height = 3; const int length = 3; SimulationSetup.BuildLattice(bodyBuilder, constraintBuilder, width, height, length, simulation, out var bodyHandles, out var constraintHandles); simulation.PoseIntegrator.Gravity = new Vector3(0, -10, 0); simulation.Bodies.ActiveSet.Velocities[width].Linear = new Vector3(0.1f, 0, 0.1f); for (int i = 0; i < 16; ++i) { simulation.Timestep(1 / 60f); } simulation.Dispose(); }
public static RigidPose[] ExecuteSimulation(int frameCount, BufferPool bufferPool, IThreadDispatcher threadDispatcher) { var simulation = Simulation.Create(bufferPool, new TestCallbacks()); var shape = new Sphere(0.5f); var shapeIndex = simulation.Shapes.Add(shape); const int width = 8; const int height = 8; const int length = 8; SimulationSetup.BuildLattice( new RegularGridWithKinematicBaseBuilder(new Vector3(1.2f, 1.05f, 1.2f), new Vector3(1, 1, 1), 1f / (shape.Radius * shape.Radius * 2 / 3), shapeIndex), new ConstraintlessLatticeBuilder(), width, height, length, simulation, out var bodyHandles, out var constraintHandles); simulation.PoseIntegrator.Gravity = new Vector3(0, -10, 0); simulation.Deterministic = true; //All bodies are definitely active, so we can pull directly from the active set. ref var velocity = ref simulation.Bodies.ActiveSet.Velocities[simulation.Bodies.HandleToLocation[bodyHandles[width]].Index];
public static void Test() { //const int bodyCount = 8; //SimulationSetup.BuildStackOfBodiesOnGround(bodyCount, false, true, out var bodies, out var solver, out var graph, out var bodyHandles, out var constraintHandles); SimulationSetup.BuildLattice( new RegularGridWithKinematicBaseBuilder(new Vector3(1), new Vector3()), new ContactManifoldConstraintBuilder(), 32, 32, 32, out var simulation, out var bodyHandles, out var constraintHandles); SimulationScrambling.ScrambleBodies(simulation); SimulationScrambling.ScrambleConstraints(simulation.Solver); SimulationScrambling.ScrambleBodyConstraintLists(simulation); SimulationScrambling.AddRemoveChurn <Contact4>(simulation, 100000, bodyHandles, constraintHandles); var threadDispatcher = new SimpleThreadDispatcher(8); //var threadDispatcher = new NotQuiteAThreadDispatcher(8); simulation.ConstraintLayoutOptimizer.OptimizationFraction = 0.01f; int constraintOptimizationIterations = 8192; simulation.ConstraintLayoutOptimizer.Update(simulation.BufferPool, threadDispatcher);//prejit var timer = Stopwatch.StartNew(); for (int i = 0; i < constraintOptimizationIterations; ++i) { simulation.ConstraintLayoutOptimizer.Update(simulation.BufferPool, threadDispatcher); } timer.Stop(); Console.WriteLine($"Finished constraint optimizations, time (ms): {timer.Elapsed.TotalMilliseconds}" + $", per iteration (us): {timer.Elapsed.TotalSeconds * 1e6 / constraintOptimizationIterations}"); //threadDispatcher.Dispose(); simulation.BufferPool.Clear(); }
public static void Test() { const int width = 32; const int height = 32; const int length = 32; SimulationSetup.BuildLattice( new RegularGridWithKinematicBaseBuilder(new Vector3(1), new Vector3()), new BallSocketConstraintBuilder(), width, height, length, out var simulation, out var bodyHandles, out var constraintHandles); var threadDispatcher = new SimpleThreadDispatcher(8); const float inverseDt = 60f; const float dt = 1 / inverseDt; const int iterationCount = 8; const int frameCount = 128; simulation.Solver.IterationCount = iterationCount; simulation.PoseIntegrator.Gravity = new Vector3(0, -10, 0); var samples = new SimulationTimeSamples(frameCount); for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { var energyBefore = TestHelpers.GetBodyEnergyHeuristic(simulation.Bodies); //simulation.Timestep(dt); simulation.Timestep(dt, threadDispatcher); samples.RecordFrame(simulation); var energyAfter = TestHelpers.GetBodyEnergyHeuristic(simulation.Bodies); int sampledBodyIndex = width; var samplePose = simulation.Bodies.ActiveSet.Poses[sampledBodyIndex]; var sampleVelocity = simulation.Bodies.ActiveSet.Velocities[sampledBodyIndex]; //for (int i =0; i < simulation.Bodies.BodyCount; ++i) //{ // simulation.Bodies.GetPose(simulation.Bodies.IndexToHandle[i], out var pose); // simulation.Bodies.GetVelocity(simulation.Bodies.IndexToHandle[i], out var velocity); // Console.WriteLine($"Sample {i} position: {pose.Position}, velocity: {velocity.Linear}"); //} Console.WriteLine($"Sample {sampledBodyIndex} position: {samplePose.Position}, velocity: {sampleVelocity.Linear}"); Console.WriteLine($"Body energy {frameIndex}: {energyAfter}, delta: {energyAfter - energyBefore}"); } var multiplier = 1e3 / frameCount; Console.WriteLine($"Simulation time (ms): {multiplier * samples.Simulation.ComputeStats().Total}"); Console.WriteLine($"Body opt time (ms): {multiplier * samples.BodyOptimizer.ComputeStats().Total}"); Console.WriteLine($"Constraint opt time (ms): {multiplier * samples.ConstraintOptimizer.ComputeStats().Total}"); Console.WriteLine($"Batch compress time (ms): {multiplier * samples.BatchCompressor.ComputeStats().Total}"); Console.WriteLine($"Pose integrate time (ms): {multiplier * samples.PoseIntegrator.ComputeStats().Total}"); Console.WriteLine($"Solve time (ms): {multiplier * samples.Solver.ComputeStats().Total}"); threadDispatcher.Dispose(); simulation.BufferPool.Clear(); }
public static SimulationTimeSamples Solve <TBodyBuilder, TConstraintBuilder, TConstraint>(TBodyBuilder bodyBuilder, TConstraintBuilder constraintBuilder, int width, int height, int length, int frameCount, int threadCount, IThreadDispatcher initializationThreadPool, IThreadDispatcher threadDispatcher) where TBodyBuilder : IBodyBuilder where TConstraintBuilder : IConstraintBuilder where TConstraint : IConstraintDescription <TConstraint> { //const int bodyCount = 8; //SimulationSetup.BuildStackOfBodiesOnGround(bodyCount, false, true, out var bodies, out var solver, out var graph, out var bodyHandles, out var constraintHandles); GC.Collect(3, GCCollectionMode.Forced, true); SimulationSetup.BuildLattice( bodyBuilder, constraintBuilder, width, height, length, out var simulation, out var bodyHandles, out var constraintHandles); SimulationScrambling.ScrambleBodies(simulation); SimulationScrambling.ScrambleConstraints(simulation.Solver); SimulationScrambling.ScrambleBodyConstraintLists(simulation); SimulationScrambling.AddRemoveChurn <TConstraint>(simulation, bodyHandles.Length * 2, bodyHandles, constraintHandles); const int batchCompressionIterations = 1000; simulation.SolverBatchCompressor.TargetCandidateFraction = .005f; simulation.SolverBatchCompressor.MaximumCompressionFraction = 0.0005f; for (int i = 0; i < batchCompressionIterations; ++i) { simulation.SolverBatchCompressor.Compress(simulation.BufferPool, initializationThreadPool); } //Attempt cache optimization. int bodyOptimizationIterations = bodyHandles.Length / 4; simulation.BodyLayoutOptimizer.OptimizationFraction = 0.005f; for (int i = 0; i < bodyOptimizationIterations; ++i) { simulation.BodyLayoutOptimizer.IncrementalOptimize(simulation.BufferPool, initializationThreadPool); } simulation.ConstraintLayoutOptimizer.OptimizationFraction = 0.044f; int constraintOptimizationIterations = 1024; for (int i = 0; i < constraintOptimizationIterations; ++i) { simulation.ConstraintLayoutOptimizer.Update(simulation.BufferPool, initializationThreadPool); } var simulationTimeSamples = new SimulationTimeSamples(frameCount); const float dt = 1 / 60f; const int iterationCount = 8; simulation.Solver.IterationCount = iterationCount; for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { CacheBlaster.Blast(); simulation.Timestep(dt, threadDispatcher); simulationTimeSamples.RecordFrame(simulation); } simulation.Dispose(); simulation.BufferPool.Clear(); return(simulationTimeSamples); }
public unsafe override void Initialize(ContentArchive content, Camera camera) { camera.Position = new Vector3(-20f, 13, -20f); camera.Yaw = MathHelper.Pi * 3f / 4; camera.Pitch = MathHelper.Pi * 0.1f; Simulation = Simulation.Create(BufferPool, new TestCallbacks()); var shape = new Sphere(0.5f); shape.ComputeInertia(1, out var sphereInertia); var shapeIndex = Simulation.Shapes.Add(shape); const int width = 16; const int height = 16; const int length = 16; var latticeSpacing = 1.1f; var latticeOffset = -0.5f * width * latticeSpacing; SimulationSetup.BuildLattice( new RegularGridBuilder(new Vector3(latticeSpacing, 1.1f, latticeSpacing), new Vector3(latticeOffset, 3, latticeOffset), sphereInertia, shapeIndex), new BallSocketConstraintBuilder(), width, height, length, Simulation, out var bodyHandles, out var constraintHandles); Simulation.PoseIntegrator.Gravity = new Vector3(0, -10, 0); Simulation.Deterministic = false; var staticShape = new Sphere(4); var staticShapeIndex = Simulation.Shapes.Add(staticShape); const int staticGridWidthInSpheres = 100; const float staticSpacing = 6; for (int i = 0; i < staticGridWidthInSpheres; ++i) { for (int j = 0; j < staticGridWidthInSpheres; ++j) { var staticDescription = new StaticDescription { Collidable = new CollidableDescription { Continuity = new ContinuousDetectionSettings { Mode = ContinuousDetectionMode.Discrete }, Shape = staticShapeIndex, SpeculativeMargin = 0.1f }, Pose = new RigidPose { Position = new Vector3( -staticGridWidthInSpheres * staticSpacing * 0.5f + i * staticSpacing, -4, -staticGridWidthInSpheres * staticSpacing * 0.5f + j * staticSpacing), Orientation = BepuUtilities.Quaternion.Identity } }; Simulation.Statics.Add(staticDescription); } } //ref var velocity = ref Simulation.Bodies.Velocities[Simulation.Bodies.HandleToIndex[bodyHandles[width]]]; //velocity.Linear = new Vector3(0.1f, 0, 0.1f); //velocity.Angular = new Vector3(); //Simulation.Solver.IterationCount = 100; }