Skip to content

Commit

Permalink
refine docs
Browse files Browse the repository at this point in the history
  • Loading branch information
notgiven688 committed Oct 27, 2024
1 parent 71c094d commit c8760b8
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 47 deletions.
2 changes: 1 addition & 1 deletion docs/docs/01_quickstart/01-render-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
sidebar_position: 2
---

# Setting Up a Render Loop
# Render Loop

The first thing we need to do is to familiarize ourselves a bit with Raylib_cs. Replace the content of `Program.cs` with the following code:

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/01_quickstart/02-hello-world.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,4 @@ CloseWindow();

Running your program, you should now see a few boxes dynamically falling onto the ground.

![plane](./img/raylibjitter.gif)
![plane](./img/raylibjitter.gif)
16 changes: 8 additions & 8 deletions docs/docs/02_documentation/01world.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Jitter World

An instance of the Jitter `World` class houses all entities in the physics simulation and provides the `World.Step` method to advance the simulation by a single time step.
An instance of the Jitter `World` class contains all entities in the physics simulation and provides the `World.Step` method to advance the simulation by a single time step.

## Creating the World

Expand Down Expand Up @@ -31,7 +31,7 @@ $$$
\left(\mathrm{BodyCount}+\mathrm{ContactCount}+\mathrm{ConstraintCount}+\mathrm{SmallConstraintCount}\right)\times{}\mathrm{IntPtr.Size}
$$$

For a typical 64-bit system the example above allocated arrays with a total size of about 1.5 MB.
For a typical 64-bit system the example above allocates arrays with a total size of about $1.5\,\mathrm{MB}$.
:::

## World.Step
Expand All @@ -55,9 +55,9 @@ Therefore, it is reasonable to use metric units (kg, m, s) when conceptualizing
:::

The smaller the time step size, the more stable the simulation.
Timesteps larger then $$$1/60\,\mathrm{s}$$$ are not adviced.
Timesteps larger then $\mathrm{dt}=1/60\,\mathrm{s}$ are not adviced.
It is also recommend to use fixed time steps.
Typical code accumulates delta times and calls world.Step only at fixed time intervals, as shown in the following example.
Typical code accumulates delta times and calls `world.Step` only at fixed time intervals, as shown in the following example.

```cs
private float accumulatedTime = 0.0f;
Expand Down Expand Up @@ -113,10 +113,10 @@ The number of iterations can be raised to improve simulation quality (`world.Sol
world.SolverIterations = (solver: 6, relaxation: 4);
```

Jitter solves physical contacts (and constraints) on the velocity level ("solver iterations").
Jitter solves physical contacts (and constraints) on the velocity level ('solver iterations').
Jitter also adds velocities to rigid bodies to resolve unphysical interpenetrations of bodies.
These additional velocities add unwanted energy to the system which can be removed by an additional relaxation phase after integrating the new positions from these velocities.
The number of iterations in the relaxation phase ("relaxation iterations") is specified here as well.
The number of iterations in the relaxation phase ('relaxation iterations') is specified here as well.
The runtime for solving contacts and constraints scales linearly with the number of iterations.

## Substep Count
Expand All @@ -137,7 +137,7 @@ Substepping is excellent for enhancing the overall quality of constraints, stabi

## Auxiliary Contacts

Jitter employs a technique termed "auxiliary contacts", where additional contacts are generated for the general case where two flat surfaces of shapes are in contact.
Jitter employs a technique termed 'auxiliary contacts', where additional contacts are generated for the general case where two flat surfaces of shapes are in contact.
These additional contacts are calculated within one frame, generating the full contact manifold in a 'single pass' and preventing jitter commonly encountered with incrementally constructed collision manifolds.
The `world.EnableAuxiliaryContactPoints` property can be used to enable or disable the usage of auxiliary contact point generation.

Expand All @@ -150,7 +150,7 @@ world.RigidBodies
```

where `RigidBodies` is of type `ReadOnlyActiveList<RigidBody>`.
The bodies are in no particular order and maybe reordered within the data structure during calls to `world.Step`.
The bodies are in no particular order and maybe reordered during calls to `world.Step`.

## Raw Data

Expand Down
18 changes: 14 additions & 4 deletions docs/docs/02_documentation/02bodies.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ Setting `setMassProperties: false` in `body.AddShape(...)` prevents Jitter from
***In Jitter the position of the rigid body has to align with the center of mass.**
So in the local reference frame of the body, the center of mass is $(0, 0, 0)$. Shapes or combinations of shapes must be translated accordingly.*

### Debugging shapes

The `RigidBody` class offers the `body.DebugDraw(IDebugDrawer drawer)` method which creates a triangle hull for each shape added to the body and calls the `drawer.DrawTriangle` method in the provided `IDebugDrawer` implementation.
The coordinates of the triangles are in world space and can be drawn to debug the collision shape of the rigid body.

:::warning body.DebugDraw performance
Every call to `body.DebugDraw` the triangle hulls are generated on the fly.
Since this is a slow operation the method should only be called for debugging purposes.
:::

## Gravity

The gravity for the world can be set using `world.Gravity`.
Expand All @@ -58,7 +68,7 @@ The property `body.AffectedByGravity` can be used to disable gravity for individ
## Damping

Jitter uses a very simple damping system to slow rigid bodies down.
This improves simulation stability and also resembles mechanical systems "losing" energy in the real world.
This improves simulation stability and also resembles mechanical systems 'losing' energy in the real world.
In Jitter there is a linear and an angular damping factor for each body which can be set using `body.Damping`.
With each `world.Step`, Jitter multiplies the angular and linear velocity of each rigid body by $$1-\gamma$$, where $$\gamma$$ is the damping factor.
For performance reasons there is no time dependency for the damping system.
Expand All @@ -67,7 +77,7 @@ As a result, bodies in a simulation with smaller timesteps experience greater da
## Speculative contacts

Speculative contacts can be utilized to prevent fast and small objects from tunneling through thin objects.
An object moving quickly enough might "miss" a collision since the distance traveled between two frames exceeds the thickness of another object.
An object moving quickly enough might 'miss' a collision since the distance traveled between two frames exceeds the thickness of another object.
Speculative contacts can be enabled on a per-body basis using `body.EnableSpeculativeContacts`.
The `world.SpeculativeRelaxationFactor` and `world.SpeculativeVelocityThreshold` can be adjusted to fine-tune speculative contacts for specific use cases.
However, it should be noted that an accurate simulation of fast-moving objects is only possible using smaller time steps.
Expand All @@ -81,8 +91,8 @@ For a collision of two bodies with different coefficients the maximum value of e
## Collide events

An instance of `RigidBody` provides two events: `BeginCollide` and `EndCollide`.
These events are triggered whenever an arbiter (Contact) is created which involves the rigid body.
By default arbiters are created between colliding shapes.
These events are triggered whenever an arbiter (Contact) is created or removed which involves the rigid body.
By default, arbiters are created between colliding shapes.
For example, the `BeginCollide` event can be used to modify the coefficient of friction of a contact:

```cs
Expand Down
13 changes: 6 additions & 7 deletions docs/docs/02_documentation/03shapes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ They also implement the `IDynamicTreeEntry` interface and can therefore be added
When a shape is added to a rigid body this is done automatically (`world.DynamicTree`).

:::info Concave Shapes

A concave shape can be represented by combining multiple convex shapes on a single rigid body.
Third-party libraries for "convex decomposition" can be used to generate convex hulls from arbitrary meshes.

Third-party libraries for 'convex decomposition' can be used to generate convex hulls from arbitrary meshes.
:::

## Default types
Expand Down Expand Up @@ -48,7 +46,8 @@ The triangles provided *must* form a convex hull.
The validity of the convex shape is not checked.
Invalid shapes can lead to glitched
collisions and/or non-terminating algorithms during collision detection.
The triangles are used to construct an internal acceleration structure that speeds up collision detection for this shape through hill-climbing.
The triangles are used to construct an internal acceleration structure that speeds up collision detection for this shape through hill-climbing.

The `convexHullShape.Clone()` method can be used to clone the shape:
The internal data structure is then used for both shapes.

Expand All @@ -71,7 +70,7 @@ For example, passing the 8 vertices of a cube to the constructor generates a cub

### TransformedShape

The `TransformedShape` can wrap and transform other shape.
The `TransformedShape` takes another shape as input and transforms it.

```cs
public TransformedShape(RigidBodyShape shape, in JVector translation, in JMatrix transform)
Expand All @@ -92,7 +91,7 @@ public TriangleShape(TriangleMesh mesh, int index)

A `TriangleMesh.Triangle` stores information about neighbour triangles.
This information is used in the `TriangleEdgeCollisionFilter` (enabled by default) to resolve collision artifacts that occur when shapes slide over the edges between connected triangles.
These edges are often referred to as "internal edges" and can cause major problems when adding level geometry to a game.
These edges are often referred to as 'internal edges' and can cause major problems when adding level geometry to a game.

### FatTriangleShape

Expand All @@ -107,7 +106,7 @@ The vertices of the `SoftBodyShape` are represented by rigid bodies.
The shapes (triangle and tetrahedron) are dynamically defined by the position of the vertices.
A `SoftBodyShape` is not added to a body.

## Custom Shapes
## Custom shapes

Custom shapes can easily be implemented in Jitter.
A shape is defined by its support function - which can be looked up or derived.
Expand Down
49 changes: 26 additions & 23 deletions docs/docs/02_documentation/05dynamictree.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
# Dynamic Tree
# Dynamic tree

The dynamic tree in Jitter holds instances which implement the `IDynamicTreeProxy` interface.
The main task of the tree is to efficiently determine if a proxy’s axis-aligned bounding box is
overlapping with the axis-aligned bounding box of any other proxy in the world.
In a naive implementation this requires $\mathcal{O}\left(n\right)$ operations (checking for an overlap with every of the $n-1$ entities). The tree
structure does accelerate this to $\mathcal{O}\left(\mathrm{log}(n)\right)$. Since proxies are dynamic and can move, the tree must be continuously updated. To less frequency trigger
updates, entities are enclosed within slightly larger bounding boxes than their actual size. This bounding box extension is defined
by the `Velocity` property of the `IDynamicTreeProxy` interface.
The main task of the tree is to efficiently determine if a proxy’s axis-aligned bounding box is overlapping with the axis-aligned bounding box of any other proxy in the world.
In a naive implementation this requires $\mathcal{O}\left(n\right)$ operations (checking for an overlap with every of the $n-1$ entities).
The tree structure does accelerate this to $\mathcal{O}\left(\mathrm{log}(n)\right)$. Since proxies are dynamic and can move, the tree must be continuously updated.
To less frequently trigger updates, entities are enclosed within slightly larger bounding boxes than their actual size.
This bounding box extension is defined by the `Velocity` property of the `IDynamicTreeProxy` interface.

![img alt](./img/dynamictree.png)

## Adding Proxies
## Adding proxies

Jitter automatically registers all shapes added to a rigid body (`body.AddShape`) with the `world.DynamicTree`. However, users are free
to add own implementations of `IDynamicTreeProxy` to the world's tree, using `tree.AddProxy`. In this case the user has to implement a `BroadPhaseFilter` and
register it (using `world.BroadPhaseFilter`) to handle any collisions with the custom proxy, otherwise an `InvalidCollisionTypeException` is thrown.
Jitter automatically registers all shapes added to a rigid body (`body.AddShape`) with the `world.DynamicTree`.
However, users are free to add own implementations of `IDynamicTreeProxy` to the world's tree, using `tree.AddProxy`.
In this case the user has to implement a `BroadPhaseFilter` and register it (using `world.BroadPhaseFilter`) to handle any collisions with the custom proxy, otherwise an `InvalidCollisionTypeException` is thrown.

## Potential pairs

The tree implementation in Jitter needs to be updated using `tree.Update(bool multiThread)`. This is done automatically for the dynamic tree owned by the world class (`world.DynamicTree`). This update process generates information about pairs of proxies which either start overlapping, or start to separate. This "events" are used to
update the `tree.PotentialPairs` hash set, which holds all overlapping pairs. Inactive
pairs of bodies can be pruned from the hashset by calling `tree.TrimInactivePairs` (also done automatically for the dynamic tree owned by the world class).
The tree implementation in Jitter needs to be updated using `tree.Update(bool multiThread)`.
This is done automatically for the dynamic tree owned by the world class (`world.DynamicTree`).
This update process generates information about pairs of proxies which either start overlapping, or start to separate.
This 'events' are used to update the `tree.PotentialPairs` hash set, which holds all overlapping pairs.
Inactive pairs of bodies can be pruned from the hashset by calling `tree.TrimInactivePairs` (also done automatically for the dynamic tree owned by the world class).
The Jitter `world` class internally uses the potential pairs to gather more detailed collision information of the pairs and also to generate collision response.

## Querying the tree
Expand All @@ -37,8 +38,7 @@ as well as all proxies which overlap with a ray
public void Query<T>(T hits, JVector rayOrigin, JVector rayDirection) where T : ICollection<IDynamicTreeProxy>
```

Custom queries can easily be implemented. An implementation which queries all proxies which have an overlap with a
single point could be implemented like this:
Custom queries can easily be implemented. An implementation which queries all proxies which have an overlap with a single point can be implemented like this:

```cs
var stack = new Stack<int>();
Expand All @@ -52,7 +52,7 @@ while (stack.TryPop(out int id))
{
if (node.IsLeaf)
{
Console.WriteLine($"{node.Proxy} contains {point}.");
Console.WriteLine($'{node.Proxy} contains {point}.');
}
else
{
Expand All @@ -65,18 +65,21 @@ while (stack.TryPop(out int id))

## Ray casting

All proxies in the tree which implement the `IRayCastable` interface can be raycasted. This includes all shapes:
All proxies in the tree which implement the `IRayCastable` interface can be raycasted.
This includes all shapes:

```cs
public bool RayCast(JVector origin, JVector direction, float maxLambda, RayCastFilterPre? pre, RayCastFilterPost? post,
out IDynamicTreeProxy? shape, out JVector normal, out float lambda)
public bool RayCast(JVector origin, JVector direction, RayCastFilterPre? pre, RayCastFilterPost? post,
out IDynamicTreeProxy? proxy, out JVector normal, out float lambda)
```

The pre- and post-filters can be used to discard hits during the ray cast. Jitter shoots a ray from the origin into the specified direction. The function
returns `true` if a hit was found. It also reports the point of collision which is given by
The pre- and post-filters can be used to discard hits during the ray cast.
Jitter shoots a ray from the origin into the specified direction.
The function returns `true` if a hit was found.
It also reports the point of collision which is given by

$$$
\mathbf{hit} = \mathbf{origin} + \lambda{}\,\times\,\mathbf{direction}
\mathbf{hit} = \mathbf{origin} + \lambda{}\,\times\,\mathbf{direction}, \quad \textrm{with} \quad \lambda \in [0,\infty).
$$$

The returned `normal` is the normalized surface normal at the hit point.
6 changes: 3 additions & 3 deletions docs/docs/02_documentation/06filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Jitter’s soft body implementation is based on this kind of filter (see `SoftBo
### Example: Collision groups

Collision groups might be easily implemented using a broad phase filter.
In this example, there are two "teams", team blue and team red.
In this example, there are two 'teams', team blue and team red.
A filter that disregards all collisions between team members (rigid bodies) of different colors is implemented:

```cs
Expand Down Expand Up @@ -93,6 +93,6 @@ operates similarly.
However, this callback is called after narrow phase collision detection, meaning detailed collision information (such as normal, penetration depth, and collision points) is available at this stage.
The filter can not only exclude collisions but also modify collision information.

The default narrow phase collision filter in Jitter is assigned to an instance of `TriangleEdgeCollisionFilter`, which filters out so-called "internal edges" for `TriangleShape`s.
The default narrow phase collision filter in Jitter is assigned to an instance of `TriangleEdgeCollisionFilter`, which filters out so-called 'internal edges' for `TriangleShape`s.
These internal edges typically cause collision artifacts when rigid bodies slide over the edges of connected triangles forming static geometry.
In the literature, this problem is also known as "ghost collisions".
In the literature, this problem is also known as 'ghost collisions'.
Binary file added docs/docs/02_documentation/img/dynamictree.odp
Binary file not shown.
Binary file added docs/docs/02_documentation/img/dynamictree.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c8760b8

Please sign in to comment.