From 76c54d58819ba9a1f6e020d0aaf8c092ad8c0fd8 Mon Sep 17 00:00:00 2001 From: "nicogo.eth" Date: Wed, 18 Dec 2024 19:19:04 +0100 Subject: [PATCH 1/4] Bepu docs update : constraints & some additional informations --- en/manual/physics/characters.md | 126 ++++++++++++++++++++++++++++++ en/manual/physics/constraints.md | 55 +++++++++++++ en/manual/physics/rigid-bodies.md | 2 + 3 files changed, 183 insertions(+) diff --git a/en/manual/physics/characters.md b/en/manual/physics/characters.md index 68499505..eb8e5e65 100644 --- a/en/manual/physics/characters.md +++ b/en/manual/physics/characters.md @@ -53,6 +53,132 @@ public class MyCharacterController : CharacterComponent } ``` +## Simple Character controller + +```cs +using Stride.BepuPhysics; +using Stride.Core; +using Stride.Core.Mathematics; +using Stride.Engine; +using Stride.Engine.FlexibleProcessing; +using Stride.Games; +using Stride.Input; +using System.Collections.Generic; + +namespace MyGameUsingBepuPhysics +{ + public class CharacterControllerComponent : CharacterComponent, IComponent + { + public Entity? CameraPivot { get; set; } + public float MinCameraAngle { get; set; } = -90; + public float MaxCameraAngle { get; set; } = 90; + + private Vector3 _cameraAngle; + private UpdateCaller _processor = null!; + + private void Update() + { + if (_processor.Inputs.IsKeyPressed(Keys.Tab)) + { + _processor.Game.IsMouseVisible = !_processor.Game.IsMouseVisible; + if (_processor.Game.IsMouseVisible) + _processor.Inputs.UnlockMousePosition(); + else + _processor.Inputs.LockMousePosition(true); + } + + Move(); + Rotate(); + if (_processor.Inputs.IsKeyPressed(Keys.Space)) + TryJump(); + } + + public override void SimulationUpdate(BepuSimulation simulation, float simTimeStep) + { + Orientation = Quaternion.RotationY(_cameraAngle.Y); // Do it before physics tick to ensure it is interpolated properly + base.SimulationUpdate(simulation, simTimeStep); + } + + private void Move() + { + // Keyboard movement + var moveDirection = Vector2.Zero; + if (_processor.Inputs.IsKeyDown(Keys.W) || _processor.Inputs.IsKeyDown(Keys.Z)) + moveDirection.Y += 1; + if (_processor.Inputs.IsKeyDown(Keys.S)) + moveDirection.Y -= 1; + if (_processor.Inputs.IsKeyDown(Keys.A) || _processor.Inputs.IsKeyDown(Keys.Q)) + moveDirection.X -= 1; + if (_processor.Inputs.IsKeyDown(Keys.D)) + moveDirection.X += 1; + + var velocity = new Vector3(moveDirection.X, 0, -moveDirection.Y); + velocity.Normalize(); + + velocity = Vector3.Transform(velocity, Entity.Transform.Rotation); + + if (_processor.Inputs.IsKeyDown(Keys.LeftShift)) + velocity *= 2f; + + Move(velocity); + } + + private void Rotate() + { + var delta = _processor.Inputs.Mouse.Delta; + + _cameraAngle.X -= delta.Y; + _cameraAngle.Y -= delta.X; + _cameraAngle.X = MathUtil.Clamp(_cameraAngle.X, MinCameraAngle, MaxCameraAngle); + + Entity.Transform.Rotation = Quaternion.RotationY(_cameraAngle.Y); + if (CameraPivot != null) + { + CameraPivot.Transform.Rotation = Quaternion.RotationX(_cameraAngle.X); + } + } + + private class UpdateCaller : IComponent.IProcessor, IUpdateProcessor + { + private List Components = new(); + + public InputManager Inputs; + public IGame Game; + + public int Order { get; } + + public void SystemAdded(IServiceRegistry registryParam) + { + Inputs = registryParam.GetService(); + Game = registryParam.GetService(); + Inputs.LockMousePosition(true); + Game.IsMouseVisible = false; + } + public void SystemRemoved() { } + + public void OnComponentAdded(CharacterControllerComponent item) + { + Components.Add(item); + item._processor = this; + } + + public void OnComponentRemoved(CharacterControllerComponent item) + { + Components.Remove(item); + item._processor = null!; + } + + public void Update(GameTime gameTime) + { + foreach (var comp in Components) + comp.Update(); + } + } + } +} + +``` + ## See also * [Statics](static-colliders.md) diff --git a/en/manual/physics/constraints.md b/en/manual/physics/constraints.md index 2da46ccb..d4791672 100644 --- a/en/manual/physics/constraints.md +++ b/en/manual/physics/constraints.md @@ -12,6 +12,61 @@ Constraints can either link two collidables together. They allow for interaction and dependency between bodies. +## Constraints list + +Below is a table organizing the constraints by a logical order (from simpler and more common to more complex or specialized). Each row lists the constraint name (with a general known mechanical analogy in parentheses if applicable), the available variants, the number of bodies involved, and a brief description. Variants such as “Servo”, “Motor”, “Limit”, or “GearMotor” typically indicate different modes of controlling or restricting the motion allowed by the constraint: + +- **Limit**: Restricts motion or angle within certain bounds. +- **Motor**: Applies a driving force or velocity to move bodies towards a target. +- **Servo**: Attempts to maintain or reach a specific position, angle, or distance using feedback control. +- **GearMotor**: Couples angular motion between axes, acting like a geared connection. + +**Table of Constraints** + +| Constraint Name (General Name) | Variants | Bodies | Description | +|-----------------------------------------------------------|-----------------|--------|----------------------------------------------------------------------------------------------------------| +| WeldConstraintComponent (Weld Joint) | - | 2 | Fixes two bodies together with no relative movement allowed. | +| BallSocketConstraintComponent (Ball-and-Socket Joint) | Motor, Servo | 2 | Allows free rotation in all directions around a shared pivot point (like a human shoulder joint). | +| HingeConstraintComponent (Hinge Joint) | - | 2 | Permits rotation about a single axis, like a door hinge. | +| AngularHingeConstraintComponent (Hinge Joint) | - | 2 | A specialized angular hinge, controlling relative rotation similarly to a standard hinge joint. | +| AngularSwivelHingeConstraintComponent (Universal Joint) | - | 2 | Allows rotation around two perpendicular axes, like a universal joint. | +| SwivelHingeConstraintComponent (Universal Joint) | - | 2 | Another form of a universal-type joint, enabling swiveling motion around multiple axes. | +| AngularConstraintComponent (Generic Angular Constraint) | Motor, Servo | 2 | A general rotational constraint that can control or limit how two bodies rotate relative to each other. | +| AngularAxisMotorConstraintComponent / AngularAxisGearMotorConstraintComponent (Rotational Axis Drive) | GearMotor, Motor | 2 | Controls rotation about a specific axis between two bodies, possibly with gearing effects. | +| TwistLimitConstraintComponent (Twist Joint) | - | 2 | Limits rotational "twist" around an axis, preventing excessive rotation like a torsion stop. | +| TwistMotorConstraintComponent (Twist Joint) | Motor | 2 | Drives relative rotation about a single axis, applying torque to achieve a target angle or velocity. | +| TwistServoConstraintComponent (Twist Joint) | Servo | 2 | Attempts to maintain a specific twist angle through servo-like feedback control. | +| SwingLimitConstraintComponent (Swing Joint) | - | 2 | Restricts "swing" motion around one or more axes, controlling how far the joint can deviate. | +| DistanceLimitConstraintComponent (Distance Joint) | - | 2 | Enforces an upper or lower bound on the distance between two points on different bodies. | +| DistanceServoConstraintComponent (Distance Joint) | Servo | 2 | Attempts to maintain or reach a specific distance between two points on different bodies. | +| DistanceConstraintComponent (Distance Joint) | Limit, Servo | 2 | Maintains or controls the exact distance between two anchor points, allowing limit or servo behavior. | +| CenterDistanceConstraintComponent (Distance Joint) | Limit | 2 | Similar to a distance joint, focusing on the distance between bodies’ centers or defined points. | +| LinearAxisLimitConstraintComponent (Prismatic Joint) | - | 2 | Restricts movement along a single linear axis, preventing motion beyond certain limits. | +| LinearAxisMotorConstraintComponent (Prismatic Joint) | Motor | 2 | Drives one body relative to another along a single axis, acting like a linear actuator. | +| LinearAxisServoConstraintComponent (Prismatic Joint) | Servo | 2 | Tries to maintain or achieve a specific position along a linear axis, using servo control. | +| PointOnLineServoConstraintComponent (Line Constraint) | Servo | 2 | Keeps a point on one body constrained to move along a line defined by another body, controlled by a servo. | +| OneBodyAngularMotorConstraintComponent (Single Body Angular Drive) | Motor | 1 | Applies torque directly to one body’s rotation, acting like a motor attached directly to that body. | +| OneBodyAngularServoConstraintComponent (Single Body Angular Drive) | Servo | 1 | Attempts to maintain a certain angular orientation of a single body using servo-like control. | +| OneBodyLinearMotorConstraintComponent (Single Body Linear Drive) | Motor | 1 | Moves a single body along a direction, as if a motor is pushing it along that axis. | +| OneBodyLinearServoConstraintComponent (Single Body Linear Drive) | Servo | 1 | Tries to maintain a single body’s position along a certain axis, servo-style. | +| AreaConstraintComponent (Area Preservation) | - | 3 | Maintains the area defined by three bodies, preventing them from collapsing inward or stretching out. | +| VolumeConstraintComponent (Volume Preservation) | - | 4 | Preserves the volume defined by four bodies, ensuring they form a stable, space-filling tetrahedron. | + +--- + +## Explanation of Constraints Variants + +- **Servo**: In servo mode, the constraint attempts to achieve or maintain a target position, angle, or distance, using feedback control. It adjusts forces or torques to reach and hold the desired setpoint. + +- **Motor**: A motor variant applies forces or torques to drive the connected bodies towards a given velocity or to overcome resistance, simulating an engine or actuator. + +- **Limit**: When a constraint is in a limit mode, it restricts movement or rotation within predetermined bounds, stopping the bodies from exceeding these limits. + +- **GearMotor**: Gear motor variants couple angular velocities or angles together, simulating gears. This ensures one body’s motion is directly related to another’s, as if connected by gears. + +These variants allow the same basic constraint type to be used for different behaviors—ranging from passively limiting motion to actively driving it toward a controlled target state. + + ## Performance And Stability The following are relevant excerpts from [Bepu's documentation](https://github.com/bepu/bepuphysics2/blob/master/Documentation/PerformanceTips.md) diff --git a/en/manual/physics/rigid-bodies.md b/en/manual/physics/rigid-bodies.md index 80062228..9276811b 100644 --- a/en/manual/physics/rigid-bodies.md +++ b/en/manual/physics/rigid-bodies.md @@ -4,6 +4,8 @@ Designer **Body** move based on physical forces applied to them, such as gravity and collisions. Typical (rigid)bodies are boxes, balls, furniture, and so on — objects that can be pushed, pulled, and knocked around, and also have effects on other bodies they collide with. +Any body can be **Kinematic**, an object that is not affected by physics forces like gravity or collisions but can interact with dynamic objects through user-defined motion +See [Kinematic Bodies](kinematic-rigid-bodies.md) for more informations. ![Static and rigidbody colliders](media/rigid-bodies-static-and-rigid-body-colliders.png) From 3c606e4e955ef1c840b6f5f94db59df37fc584ba Mon Sep 17 00:00:00 2001 From: "nicogo.eth" Date: Wed, 18 Dec 2024 19:54:39 +0100 Subject: [PATCH 2/4] Add stability tips --- en/manual/physics/constraints.md | 30 ++++++++++++++++++++++-------- en/manual/physics/simulation.md | 18 ++++++++++++++++-- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/en/manual/physics/constraints.md b/en/manual/physics/constraints.md index d4791672..a8005f14 100644 --- a/en/manual/physics/constraints.md +++ b/en/manual/physics/constraints.md @@ -67,18 +67,32 @@ Below is a table organizing the constraints by a logical order (from simpler and These variants allow the same basic constraint type to be used for different behaviors—ranging from passively limiting motion to actively driving it toward a controlled target state. -## Performance And Stability +## Performance and Stability -The following are relevant excerpts from [Bepu's documentation](https://github.com/bepu/bepuphysics2/blob/master/Documentation/PerformanceTips.md) +The following are relevant excerpts from [Bepu's documentation StabilityTips](https://github.com/bepu/bepuphysics2/blob/master/Documentation/StabilityTips.md) and [Substepping](https://github.com/bepu/bepuphysics2/blob/master/Documentation/Substepping.md) -Try using the minimum number of solver iterations sufficient to retain stability. The cost of the solver stage is linear with the number of iterations, and some simulations can get by with very few. +Constraints can introduce complexity into physics simulations, sometimes causing instability, jitter, or excessive oscillation. Common sources of instability include incomplete force propagation across complex constraint networks (leading to jitter, especially in tall stacks) and overly stiff constraints pushing beyond what the solver can handle at a given frequency. -For some simulations with very complex constraint configurations, there may be no practical number of solver iterations that can stabilize the simulation. In these cases, you may need to instead use substepping or a shorter time step duration for the entire simulation. More frequent solver execution can massively improve simulation quality, allowing you to drop velocity iteration counts massively (even to just 1 per substep). See the Substepping documentation for more details. +### Improving Stability +- **Increase Solver Iterations**: If objects bounce or jitter (especially in complex stacks or with high mass-ratio configurations), increasing `Simulation.Solver.IterationCount` can help the solver better converge. +- **Reduce Constraint Stiffness**: Constraints with very high frequencies relative to the simulation timestep can cause instability. Try setting constraint frequencies to no more than about half the simulation rate. +- **Avoid Extreme Mass Ratios**: Heavy objects relying on very light supports cause convergence issues. Wherever possible, reduce mass ratios or add support structures. +- **Use Substepping**: For difficult simulations (e.g., high stiffness or large mass ratios), consider solver substepping. Substepping effectively increases the solver update rate within each main timestep, improving stability without always needing high iteration counts. -> [!WARNING] -> Probably need to adapt and extend some parts of the above to our implementation, not sure how relevant everything is. Take stuff from https://github.com/bepu/bepuphysics2/blob/master/Documentation/StabilityTips.md and https://github.com/bepu/bepuphysics2/blob/master/Documentation/Substepping.md -> - Eideren +### Using Substepping +- **Configuration**: Specify a `SolveDescription` with `SubstepCount > 1` when creating the simulation. For example, `SubstepCount = 4` at 60Hz results in a 240Hz effective solver rate. +- **Benefits**: Substepping can handle stiffer constraints and more extreme mass ratios, often reducing the total iteration count needed. +- **Trade-Offs**: Substepping doesn’t re-run full collision detection at each substep—only the solver. While cheaper, this can lead to slightly outdated contacts and minor artifacts. Mitigate by adjusting damping, sleeping thresholds, or turning substepping off if needed. + +### General Tips +1. Start simple: a few solver iterations, no substepping. +2. If instability persists, add more solver iterations or start using substepping. +3. Keep constraints and mass distributions realistic and not too extreme. +4. Fine-tune damping, contact configurations, or substep counts if subtle jitter remains. + +Balancing solver iterations, constraint stiffness, mass ratios, and substepping can greatly improve both performance and stability in complex, constraint-driven simulations. ## See also -* [Colliders](colliders.md) \ No newline at end of file +* [Colliders](colliders.md) +* [simulation](simulation.md) \ No newline at end of file diff --git a/en/manual/physics/simulation.md b/en/manual/physics/simulation.md index 18633df6..db52e7b1 100644 --- a/en/manual/physics/simulation.md +++ b/en/manual/physics/simulation.md @@ -29,8 +29,22 @@ There are multiple ways to retrieve a reference to this `BepuSimulation` from in The following are relevant excerpts from [Bepu's documentation](https://github.com/bepu/bepuphysics2/blob/master/Documentation/PerformanceTips.md) -If physics causes your game to hang for a while when simulating for the first time, it may be related to just-in-time compilation. If it becomes a problem, consider running a small simulation that hits all the relevant codepaths (a bunch of objects colliding with constraints applied) behind a loading screen. Using an ahead-of-time compilation toolchain would also work. +### General +- **JIT Compilation Spikes**: Large spikes in physics step time after launch may be due to JIT compilation. Consider running a small simulation behind a loading screen to prime all relevant code paths. AOT compilation can also help. +- **Thread Oversubscription**: If recurring spikes occur (especially in the solver), the operating system may be oversubscribing threads. Too many threads vying for CPU time can stall physics. In such cases, reduce the number of threads used by the simulation or by other parts of the engine. + +### Shape Optimization +- **Use Simple Shapes**: Spheres and capsules are fastest, then boxes and triangles, followed by cylinders and convex hulls. +- **Keep Hulls Small**: If using convex hulls, minimize vertex count. Complexity directly affects collision cost. +- **Limit Concave and Mesh Shapes**: Use compounds of simpler shapes instead of concave meshes whenever possible. If absolutely necessary, keep the triangle count low and shapes uniform in size. +- **Reuse Shapes**: Avoid creating many duplicate, large shapes (like complex hulls or meshes). Reusing shapes reduces memory bandwidth and cache issues. +- **Type Consistency**: Using similar shape types can yield small SIMD efficiency gains in the narrow phase. + +### Solver Optimization +- **Minimize Iterations**: Use the smallest number of solver iterations that keep the simulation stable. The solver cost grows linearly with iteration count. +- **Substepping**: For complex or stiff constraint configurations, using solver substeps can dramatically improve stability. With substeps, you can often reduce the number of velocity iterations. Consider using substepping if no reasonable iteration count alone stabilizes the simulation. See the [Substepping documentation](Constraints.md) for more details. ## See also * [Colliders](colliders.md) -* [Collider shapes](collider-shapes.md) \ No newline at end of file +* [Collider shapes](collider-shapes.md) +* [Constraints](Constraints.md) \ No newline at end of file From 75ceccd17ea6727ed11f9dae112c93a8ecb2764a Mon Sep 17 00:00:00 2001 From: "nicogo.eth" Date: Wed, 18 Dec 2024 20:08:57 +0100 Subject: [PATCH 3/4] add FAQ --- en/manual/physics/faq.md | 12 ++++++++++++ en/manual/physics/index.md | 1 + 2 files changed, 13 insertions(+) create mode 100644 en/manual/physics/faq.md diff --git a/en/manual/physics/faq.md b/en/manual/physics/faq.md new file mode 100644 index 00000000..75476426 --- /dev/null +++ b/en/manual/physics/faq.md @@ -0,0 +1,12 @@ +# FAQ + +**Q: My objects stop moving or become “stuck” after waiting still for a while.** +A: This is usually due to the physics engine putting bodies to sleep to save on computation. To prevent your object from sleeping, you can: +- Set `BodyActivityDescription.SleepThreshold = -1` for the object’s body, which disables sleeping. +- Or explicitly wake the object each frame by setting `body.Awake = true` in your update loop. + +**Q: Objects pass through each other at high speeds.** +A: This can be caused by insufficient time resolution or Mesh colliders. Consider enabling Continuous Collision Detection (CCD), reducing the timestep duration, or increasing solver substeps to ensure the solver checks for collisions more frequently. Also use primitives shapes + +**Q: How do I deal with high mass ratios that cause instability?** +A: Very heavy objects supported by very light ones can cause instability. If you can’t adjust masses, try adding additional support structures, increasing solver iterations, enabling substepping, or introducing damping. Lowering constraint stiffness can also help achieve stability without requiring a large number of solver iterations. diff --git a/en/manual/physics/index.md b/en/manual/physics/index.md index e86a133b..1a0eee3c 100644 --- a/en/manual/physics/index.md +++ b/en/manual/physics/index.md @@ -22,6 +22,7 @@ This section explains how physics components work, how to add them to your proje * [Constraints](constraints.md): Join physics objects together, constrain them around points * [Physics Queries](raycasting.md): Operations to find objects in the scene * [Physics Update](physics-update.md): Updating logic alongside physics +* [FAQ](faq.md): Frequently asked questions ### Tutorials From e6ea46c153326a2ad7bd7fe82d17200cf3b85339 Mon Sep 17 00:00:00 2001 From: "nicogo.eth" Date: Fri, 20 Dec 2024 18:16:05 +0100 Subject: [PATCH 4/4] add FAQ to toc --- en/manual/toc.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/en/manual/toc.yml b/en/manual/toc.yml index a1ef808a..a5a885c5 100644 --- a/en/manual/toc.yml +++ b/en/manual/toc.yml @@ -456,7 +456,8 @@ items: href: physics/script-a-trigger.md - name: Physics jitter href: physics/fix-physics-jitter.md - + - name: FAQ + href: physics/faq.md - name: Physics Bullet href: physics-bullet/index.md items: