Soft2D
A 2D multi-material continuum physics engine designed for real-time applications.
Loading...
Searching...
No Matches
User Documentation

This documentation provides comprehensive details on the use and implementation of soft2d.

Units

All physical quantity units in soft2d follow the international standard, unless specified otherwise. For instance, parameters related to length should be in 'meters', and those related to velocity in 'meters per second'.

Basic Concepts

World, body, collider, and trigger are the most important concepts in soft2d.

World

A world is a container that contains all simulation-related objects within a scene and simulates them over time under physical laws. See World section.

Body

A body is a continuum to be simulated, which is composed of a group of particles. A body has properties such as shape, center, material, etc. See Body section.

Bodies with different shapes.
Custom body.
Mesh body.

Collider

A collider is an obstacle within the world that blocks the motion of bodies. See Collider section.

Kinematic colliders (in green color).

Trigger

A trigger is a spatial area with a specific shape, which is able to detect particles passing through it. See Trigger section.

A trigger (in red color) detects and removes particles passing through it.

User Examples

The Github repository soft2d-release contains numerous examples demonstrating the usage of soft2d. Users can explore these examples to understand soft2d better.

A preview of user examples.

World

A world is a container that contains all simulation-related objects within a scene and simulates them over time under physical laws.

Runtime

Soft2D leverages the Taichi AOT system for GPU execution. Prior to creating a world, a taichi runtime (TiRuntime) should be initialized to set up the necessary GPU codes and compute backends.

World Configuration

When creating a world, a range of parameters (S2WorldConfig) should be specified as part of its configuration. A typical world configuration can be found Default World Configuration Example, and a detailed explanation of each parameter is provided below.

  • max_allowed_particle_num, max_allowed_body_num, ..., etc.

    These parameters specify the capabilities of the world, which affect GPU memory usage. For example, for every particle, we store a series of data, such as its position, velocity, tag, etc. These parameters significantly affect the GPU memory footprint.

  • grid_resolution

    The resolution of the background grid. Users are only required to provide a single integer indicating the maximum resolution value along the x-axis and y-axis. The smaller one will be automatically calculated by soft2d. To obtain both two components of the background's resolution, use s2_get_world_grid_resolution().

  • offset

    The offset of the world. An example of world offset can be found at World Offset Example.

  • extent

    The extent of world. An example of world extent can be found at World Extent Example.

  • substep_dt

    The time step of sub-steps. See Time Integration section.

  • gravity

    World's gravity (meter per second squared).

  • out_world_boundary_policy

    The policy that controls the behavior of a body when it leaves the world. See OutWorldBoundaryPolicy

  • enable_debugging

    Enable the debugging mode. Some buffer exports require this option to be enabled. See S2BufferName.

  • enable_world_query

    Enable world querying. See Trigger Events.

  • mesh_body_force_scale

    A scale factor to adjust the magnitude of mesh bodies' internal force. See Mesh Body.

  • collision_penalty_force_scale_along_normal_dir

    An adjustable parameter to avoid particle-collider penetration. See Collision Handling.

  • collision_penalty_force_scale_along_velocity_dir

    An adjustable parameter to avoid particle-collider penetration. See Collision Handling.

  • fine_grid_scale

    A scale factor to control the resolution of the fine grid. See Fine Grid.

Shape

When creating a body, a collider or a trigger, its shape should be specified. A shape describes an object's geometric appearance, such as a box or a circle. All supported shapes are listed in S2ShapeType.

Different shapes.

Kinematics

Kinematics defines the motion state of a body, collider, or trigger. It includes properties like center and linear_velocity. Refer to S2Kinematics for details.

Mobility

The mobility of an object (S2Body, S2Collider, or S2Trigger) could be static, kinematic or dynamic. See S2Mobility for more details.

Currently, objects have different available mobilities in soft2d:

  • Bodies currently support static and dynamic mobilities.
  • Colliders currently support static and kinematic mobilities.
  • Triggers only support static mobility.
Object Static Kinematic Dynamic
Body Y Y
Collider Y Y
Trigger Y

Material

When creating a body, it is necessary to specify a physical material. This defines the object's physical characteristics. Materials Example demonstrates the behavior of different materials.

Material Types

Currently, soft2d supports four types of materials: fluid, elastic body, snow and sand.

Constitutive Models

Soft2D is based on the continuum mechanics theory. The constitutive model used in soft2d is the fixed corotated model, which requires Young's modulus and Poisson's ratio as inputs.

Young's modulus

Young's modulus describes the "stiffness" of a material. A detailed explanation can be found at Wiki - Young's modulus. In soft2d, we use "MPa" as the default unit for Young's modulus parameters.

‍Fluids technically do not have Young's modulus. In soft2d, it's used to indicate fluid's degree of incompressibility.

Poisson's ratio

Poisson's ratio describes how a material stretches perpendicularly when compressed in a specific direction. More details are available in Wiki - Poisson's ratio.

Particle

A body is composed of a group of particles. Every particle has its own properties, such as position, velocity and tag, etc. These data can be accessed via a particle callback function (See Particle Callback Functions).

Particle Tag

Every particle has a user-specified tag, which is useful for logic (See Trigger Events) or rendering. When creating a body, users are required to specify a tag which is then assigned to all particles in that body. The tag of each particle can be later modified in a particle callback function (See Particle Callback Functions) during the simulation.

Particle ID

Upon creation, each particle is automatically assigned a unique, persistent ID. The memory location of a particle in the GPU buffer might change during the simulation. For example, when some particles are removed, left particles in the buffer will be reordered. As a result, one should use a particle's ID to distinguish it from other particles.

Body

A body is a continuum to be simulated, which is composed of a group of particles. A body has properties such as shape, center, material, etc. When the shape of a body is specified, particles will automatically sampled within its area.

There are two kinds of special bodies: CustomBody and MeshBody. They provide more flexibility for users. CustomBody allows users to custom sample particles to form a body. MeshBody enables users to construct a body from a 2D mesh.

‍The ownership of a body belongs to the world.

Particle Sampling

When the shape of a body is specified, soft2d automatically samples particles to "fill" that shape. A Poisson's sampling method is employed in this process. The sampled particles' density is decided heuristically and automatically.

‍In a large world, it might not have the enough accuracy to represent a relatively small body. An example of such an occasion is shown in World Extent Example.

MeshBody

Mesh body is a special type of body. Particles in a mesh body are connected by edges. Edges are like constraints, which "drag" particles. In a mesh body, only particles interact with other bodies, while edges do not. The simulation pipeline of the mesh body is a little bit different from the body, one can adjust the magnitude of the mesh body's internal force by S2WorldConfig.mesh_body_force_scale.

Collider

A collider is an obstacle within the world that blocks the motion of bodies.

Collision Handling

During the simulation, particles might penetrate into colliders. To avoid this, in soft2d, collision handling is performed after every sub-step. Soft2D uses the penalty method to prevent particle-collider penetration. One can adjust the magnitude of the penalty force via S2WorldConfig.collision_penalty_force_scale_along_normal_dir and S2WorldConfig.collision_penalty_force_scale_along_velocity_dir.

Another occasion when penetration might happen is when colliders overlap particles while using s2_set_collider_position(). In such occasions, particles can be stuck into the colliders. Users should try to avoid this happening.

Fine Grid

All colliders are rasterized into a background grid during the simulation. A coarse grid may lead to inaccurate collision handling. To solve this problem, soft2d employs a fine grid alongside the standard background grid to store the discretized colliders (and triggers). The resolution of the fine grid is the product of S2WorldConfig.fine_grid_scale and the resolution of the standard background grid (S2WorldConfig.grid_resolution). See Background Grid for more details.

The figure below demonstrates an intuitive comparison of discretized colliders on grids with different resolutions (grid_resolution=128, fine_grid_scale=1, 2, 4, respectively).

Discretized colliders on 128x128, 256x256, 512x512 resolution grids

Collision Parameters

Users are able to control collision behaviors by specifying a set of collision parameters (S2CollisionParameter) when creating a collider. These include collision type, friction coefficient and restitution coefficient. The following animations show the effects of different collision parameters.

Different collision types: STICKY, SLIP and SEPARATE
Friction and restitution: From left to right: restitution_coeff is 0, 0.05, 0.1, 0.15, 0.2; From top to bottom: friction_coeff is 0, 0.25, 0.5, 0.75, 1.0

Trigger

A trigger is a spatial area with a specific shape, which is able to detect particles passing through it. Like colliders, triggers are also stored on the fine grid.

S2WorldConfig.enable_world_query must be enabled when using triggers.

World Querying (Trigger Events)

Currently, world querying can be performed by trigger events.

Trigger events support several operations:

All the above operations support filtering particles with a specific tag. Such functions have a by_tag suffix.

Particle Callback Functions

A trigger allows users to provide a user-defined callback function to access or manipulate particle data. Utilizing particle callback, one can retrieve particle data, such as position, velocity, etc., on the host side. Moreover, users can execute two kinds of manipulations in the callback:

  • Modify each particle's tag.
  • Mark each particle should be removed or not.

An example of particle callback can be found at Trigger Callback Example.

Exporting Data

Soft2D offers several methods to export internal data.

  • Exporting buffers on the device (GPU) side.

    Soft2D allows access to its internal buffers via their names. All available buffer names can be found in S2BufferName. The handle of these buffers can be retrieved by s2_get_buffer() function. One can use utility functions such as ti_copy_memory_device_to_device() (provided by taichi c-api) to copy the buffer data into their own GPU buffer. Soft2D also provides a s2_export_buffer_to_texture() function. This function copies the data into a user-specified TiTexture. An example of exporting a buffer to a texture can be found at Debugging Example.

‍Currently, s2_export_buffer_to_texture() supports only S2_BUFFER_NAME_FINE_GRID_COLLIDER_NUM and S2_BUFFER_NAME_FINE_GRID_TRIGGER_ID.

  • Exporting particle data (in a trigger) on the host (CPU) side.

    Particle callback functions provide a way to access particle data in a trigger. Using a particle callback, one can store particle data in the host memory. See Particle Callback Functions section for more details.

Engine Architecture

This section introduces the simulation framework of soft2d physics engine.

Simulation Flow

The fundamental logical flow of soft2d can be visualized with the following flow chart.

+--------------------------+
| World Initialization |
+------------+-------------+
|
|<--------------------+
| |
| |
+----------------v------------------+ |
| Step | |
| | |
| | | |
| +------------v-------------+ | |
| | Pre-Step | | |
| | | | |
| | +--------------------+ | | |
| | | Destroy objects | | | |
| | +---------+----------+ | | |
| | | | | |
| | +---------v----------+ | | |
| | | Update objects | | | |
| | +---------+----------+ | | |
| | | | | |
| | +---------v----------+ | | |
| | | Remove && Reorder | | | |
| | | particles | | | |
| | +--------------------+ | | |
| | | | |
| +------------+-------------+ | |
| | | |
| | | |
| +------------v-------------+ | |
| | Sub-steps | | |
| +------------+-------------+ | |
| | | |
| | | |
| +------------v-------------+ | |
| | Post-Step | | |
| | | | |
| | World query enabled? | | |
| | | | | |
| | | | | |
| | +-----------+ | | |
| | | NO | | | |
| | YES| | | | |
| | +--------v--------+ | | | |
| | | World query | | | | |
| | | && | | | | |
| | |Particle callback| | | | |
| | +--------+--------+ | | | |
| | | | | | |
| | |<----------+ | | |
| | | | | |
| +------------+-------------+ | |
| | | |
+----------------v------------------+ |
| |
+---------------------+

The soft2d engine executes several sequential phases during a step:

  • Pre-Step phase: This initial phase prepares for the upcoming step. At this phase, user-destroyed objects (bodies, colliders and triggers) will be actually destroyed. Then, objects (such as kinematic colliders) will be updated if necessary. Finally, user-removed particles (via trigger events) will be actually removed.
  • Sub-steps phase: The actual simulation phase.
  • Post-Step phase: At this phase, soft2d firstly checks if S2WorldConfig.enable_world_query is enabled. If so, particle data will be fetched back from GPU.

Data Flow

In soft2d, all simulation-related data is stored on the device (GPU) memory. Data retrieval from GPU to CPU takes place at the post-step stage. If S2WorldConfig.enable_world_query is enabled, particle data will be read back from GPU to CPU. Then, trigger events and user-defined callbacks will be performed on the host particle data. Any user modifications to the particle data will be sent to GPU again.

‍The detection of particles located in a trigger is performed on the host side.

Multithreading

Real-time applications often run with multiple threads. For instance, most mainstream game engines utilize a logic (game) thread and a rendering thread. The rendering thread is responsible for creating the graphics runtime and drawing the scene. To ensure thread safety within such an environment, users should initialize soft2d on the rendering thread using the game engine's graphics runtime. User operations involving GPU dispatching should also be executed on the rendering thread. To manage multi-threading issues, soft2d queues all user operations, such as object addition or removal, into the s2_step() function. As a result, user need run the s2_step() on the rendering thread.

Here lists all functions that need be invoked on the rendering thread in a multi-threading environment:

Data Hierarchy

Soft2D organizes data across several levels.

  • World level: This encompasses all parameters in S2WorldConfig, along with all grid-associated data.
  • Body level: This includes material, mobility, bounding boxes etc.
  • Particle level: This includes attributes like position, velocity, tag, id, etc.

Algorithm Overview

This section provides detailed insights into the internal algorithms of the soft2d engine.

Updated Lagrangian Method

Soft2D is based on the continuum mechanics theory, and employs the updated Lagrangian method for physical simulation. The updated Lagrangian method discretizes the continuum using a Lagrangian (particle) method and calculates the force field on the grid.

Background Grid

In the updated Lagrangian method, a background grid is required for computing the force acting at every point in continua (bodies). The resolution of the background grid is a critical factor in determining the quality of the simulation. One can adjust the background grid resolution through S2WorldConfig.grid_resolution. Background Grid Example provides a visualization of the background grid. The following figure shows an intuitive comparison of grids with different resolutions (32x32, 64x64, 128x128).

Simulate a same scene with different background grid resolutions: 32x32, 64x64, 128x128.

Fine Grid

Besides bodies, both colliders and triggers are discretized into a grid during the simulation. However, to improve the flexibility, soft2d uses a different grid to store colliders and triggers. To distinguish with the background grid, we call the grid storing colliders and triggers as "fine grid". The fine grid's resolution is determined by multiplying S2WorldConfig.fine_grid_scale by the resolution of the background grid. See Collider - Fine Grid section for more details.

OutWorldBoundaryPolicy

As the updated Lagrangian method requires a grid for simulation, a body that leaves the world cannot be simulated. Soft2D will either deactivate or remove such bodies. One can specify this behavior via S2WorldConfig.out_world_boundary_policy.

We use Axis-Aligned Bounding Boxes (AABB) to check if a body leaves the world (The AABB of a body is the minimal axis-aligned box covering all its particles). When the condition

AABB(body).low_corner.x < world.offset.x ||
AABB(body).high_corner.x > world.offset.x + world.extent.x ||
AABB(body).low_corner.y < world.offset.y ||
AABB(body).high_corner.y > world.offset.y + world.extent.y

satisfies, we treat this body as it leaves the world. Or a more intuitive way: we treat a body out of the world if any of its particles move out of the scope of the world.

‍Unlike bodies, by contrast, colliders and triggers can work normally even if they are out of the world.

Simulating a Large World

Despite the need for a background grid, soft2d offers methods for simulating a large world. This can be achieved by adjusting S2WorldConfig.offset and S2WorldConfig.extent.

World Offset

One can move the world (background grid) by adjusting the world offset. As the result, a larger world is able to be simulated. If a body leaves the world after modifying the world offset, the body will be deactivated or removed according to S2WorldConfig.out_world_boundary_policy.

A demonstration of world offset.

World Extent

One can adjust S2WorldConfig.extent to modify the real extent of the grid, which would enable users to simulate physical scenes at different scales. A demonstration of world extent can be found at World Extent Exmaple.

‍In soft2d, we employ a uniform background grid for performance consideration. This means that all cells have the same size. As a result, simulating extremely small bodies and extremely large bodies in a same scene can be challenging.

Time Integration

Soft2D utilizes the semi-implicit Euler (a.k.a symplectic Euler) method for time integration. Each step (s2_step()) is further divided into several sub-steps, each with a smaller time step. A call to s2_step(dt) leads to ceil(dt/substep_dt) times of sub-steps.

Inherently, the semi-implicit Euler method could lead to numerical instability (a.k.a simulation "explosion") if substep_dt or Young's modulus is too large. One can adjust S2WorldConfig.substep_dt or Young's modulus of the body to avoid the numerical divergence.

FAQ