public unsafe override void Initialize(ContentArchive content, Camera camera) { camera.Position = new Vector3(0, 40, 200); camera.Yaw = 0; camera.Pitch = 0; //This type of position-based bounciness requires feedback from position error to drive the corrective impulses that make stuff bounce. //The briefer a collision is, the more damped the bounce becomes relative to the physical ideal. //To counteract this, a substepping timestepper is used. In the demos, we update the simulation at 60hz, so a substep count of 4 means the solver and integrator will run at 240hz. //That allows higher stiffnesses to be used since collisions last longer relative to the solver timestep duration. //(Note that substepping tends to be an extremely strong simulation stabilizer, so you can usually get away with lower solver iteration counts for better performance.) var collidableMaterials = new CollidableProperty <SimpleMaterial>(); Simulation = Simulation.Create(BufferPool, new BounceCallbacks() { CollidableMaterials = collidableMaterials }, new DemoPoseIntegratorCallbacks(new Vector3(0, -10, 0)), new SubsteppingTimestepper(4), solverIterationCount: 2); var shape = new Sphere(1); shape.ComputeInertia(1, out var inertia); var ballDescription = BodyDescription.CreateDynamic(RigidPose.Identity, inertia, new CollidableDescription(Simulation.Shapes.Add(shape), 20f), new BodyActivityDescription(1e-2f)); for (int i = 0; i < 100; ++i) { for (int j = 0; j < 100; ++j) { //We'll drop balls in a grid. From left to right, we increase stiffness, and from back to front (relative to the camera), we'll increase damping. //Note that higher frequency values tend to result in smaller bounces even at 0 damping. This is not physically realistic; it's a byproduct of the solver timestep being too long to properly handle extremely brief contacts. //(Try increasing the substep count above to higher values and watch how the bounce gets closer and closer to equal height across frequency values.) ballDescription.Pose.Position = new Vector3(i * 3 - 99f * 3f / 2f, 100, j * 3 - 230); collidableMaterials.Allocate(Simulation.Bodies.Add(ballDescription)) = new SimpleMaterial { FrictionCoefficient = 1, MaximumRecoveryVelocity = float.MaxValue, SpringSettings = new SpringSettings(5 + 0.25f * i, j * j / 10000f) }; } } collidableMaterials.Allocate(Simulation.Statics.Add(new StaticDescription(new Vector3(0, -15f, 0), new CollidableDescription(Simulation.Shapes.Add(new Box(2500, 30, 2500)), 0.1f)))) = new SimpleMaterial { FrictionCoefficient = 1, MaximumRecoveryVelocity = 2, SpringSettings = new SpringSettings(30, 1) }; }
public PhyObject Create(ObjectState state) { PhyObject phy = null; if (state.uID == null || objects.ContainsKey(state.uID)) { state.uID = PhyObject.createUID(); } if (state is BoxState) { if (state.isMesh) { phy = CreateMesh((BoxState)state); } else { phy = CreateBox((BoxState)state); } } if (state is SphereState) { phy = CreateSphere((SphereState)state); } if (phy.material == default(SimpleMaterial)) { collidableMaterials.Allocate(phy.bodyHandle) = new SimpleMaterial { FrictionCoefficient = .1f, MaximumRecoveryVelocity = float.MaxValue, SpringSettings = new SpringSettings(1f, 1.5f) }; } if (!objects.ContainsKey(state.uID)) { objects.Add(state.uID, phy); } else { QuixConsole.WriteLine("Objects already had that key"); } return(phy); }