Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bepu docs update : constraints & some additional informations #374

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions en/manual/physics/characters.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<CharacterControllerComponent.UpdateCaller, CharacterControllerComponent>
{
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<UpdateCaller, CharacterControllerComponent>.IProcessor, IUpdateProcessor
{
private List<CharacterControllerComponent> Components = new();

public InputManager Inputs;
public IGame Game;

public int Order { get; }

public void SystemAdded(IServiceRegistry registryParam)
{
Inputs = registryParam.GetService<InputManager>();
Game = registryParam.GetService<IGame>();
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)
Expand Down
85 changes: 77 additions & 8 deletions en/manual/physics/constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,87 @@

Constraints can either link two collidables together. They allow for interaction and dependency between bodies.

## Performance And Stability
## Constraints list

The following are relevant excerpts from [Bepu's documentation](https://github.com/bepu/bepuphysics2/blob/master/Documentation/PerformanceTips.md)
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:

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.
- **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.

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.
**Table of Constraints**

> [!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
| 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 StabilityTips](https://github.com/bepu/bepuphysics2/blob/master/Documentation/StabilityTips.md) and [Substepping](https://github.com/bepu/bepuphysics2/blob/master/Documentation/Substepping.md)

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.

### 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.

### 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)
* [Colliders](colliders.md)
* [simulation](simulation.md)
12 changes: 12 additions & 0 deletions en/manual/physics/faq.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions en/manual/physics/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New pages should also be added to the toc.yml file :P

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


### Tutorials

Expand Down
2 changes: 2 additions & 0 deletions en/manual/physics/rigid-bodies.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<span class="badge text-bg-success">Designer</span>

**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)

Expand Down
Loading