# How DART Handles Soft Body Dynamics and Soft Contact Constraints: A Complete Technical Guide

> Discover how DART handles soft body dynamics using mass-spring systems and resolves soft contact constraints within its solver. Dive into a complete technical guide for DART.

- Repository: [DART: Dynamic Animation and Robotics Toolkit/dart](https://github.com/dartsim/dart)
- Tags: deep-dive
- Published: 2026-02-28

---

**DART implements soft body dynamics using a mass-spring system centered on `SoftBodyNode` with point masses, and resolves soft contacts through a specialized `SoftContactConstraint` class that integrates directly into the constraint-based solver.**

DART (Dynamic Animation and Robotics Toolkit) extends its rigid-body physics engine to support deformable objects through a specialized soft-body architecture. The implementation, found in the `dartsim/dart` repository, follows the formulation described by Sumit Jain and C. Karen Liu in their "Soft Contacts" research, enabling realistic simulation of soft-rigid and soft-soft interactions within a unified constraint-based framework.

## Soft Body Architecture and Core Components

DART models deformable objects using a **mass-spring-damper** representation rather than finite element methods. This approach balances computational efficiency with realistic deformation behavior.

### SoftBodyNode and Point Mass Representation

The `SoftBodyNode` class, defined in [`dart/dynamics/soft_body_node.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/soft_body_node.hpp), serves as the primary container for soft body dynamics. Unlike rigid `BodyNode` instances, a `SoftBodyNode` maintains a collection of **`PointMass`** objects stored in `mPointMasses`. Each point mass tracks its individual position, velocity, and mass value, forming a dynamic graph connected by springs and dampers.

Key properties governing the material behavior reside in `SoftBodyNodeUniqueProperties` (accessed via the aspect system) and include:
- **`kv`**: Vertex stiffness controlling resistance to volume deformation
- **`ke`**: Edge stiffness governing spring constants between connected masses  
- **`dampCoeff`**: Damping coefficient for internal energy dissipation

The `SoftBodyNodeHelper` utility within the same header provides convenience functions like `setBox()`, `setSphere()`, and `setCylinder()` to generate common geometric configurations with automatically populated point mass lattices.

### SoftBodyAspect and State Management

DART utilizes its aspect architecture to separate soft-body data from the core rigid-body system while maintaining integration within the simulation pipeline. The `SoftBodyAspect` class, located in [`dart/dynamics/detail/soft_body_node_aspect.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/detail/soft_body_node_aspect.hpp), encapsulates:
- `SoftBodyNodeUniqueState`: Current positions, velocities, and the augmented mass matrix
- `SoftBodyNodeUniqueProperties`: Material parameters and connectivity data

During each simulation step, the aspect updates the **augmented mass matrix** via `updateMassMatrix()`, assembling contributions from all point masses into the global system that the constraint solver processes.

### SoftMeshShape for Visualization

To render deformable objects, DART provides `SoftMeshShape` in [`dart/dynamics/soft_mesh_shape.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/soft_mesh_shape.hpp). This shape class dynamically constructs a triangle mesh from the current point mass positions, allowing real-time visualization of deformation without affecting the physics simulation.

## Soft Contact Constraint Mechanics

When collision detection identifies contact involving a soft body, DART instantiates a `SoftContactConstraint` from [`dart/constraint/soft_contact_constraint.hpp`](https://github.com/dartsim/dart/blob/main/dart/constraint/soft_contact_constraint.hpp) rather than a standard rigid contact constraint.

### Contact Point Selection and Jacobian Computation

The constraint constructor identifies the **nearest point mass** to the contact point using `selectCollidingPointMass()`, storing references in `mPointMass1` and `mPointMass2` for soft-rigid or soft-soft collisions. During the `update()` phase, the constraint:

1. Computes relative velocity at the contact point via `getRelVelocity()`
2. Generates contact Jacobians (`mJacobians1`, `mJacobians2`) mapping point mass velocities to contact space
3. Constructs friction directions using `getTangentBasisMatrixODE()` derived from the contact normal
4. Enforces non-penetration, restitution, and Coulomb friction through `applyImpulse()`, `applyUnitImpulse()`, and `getVelocityChange()`

### Global Constraint Parameters

Tuning parameters for soft contact stability are implemented as static members of the constraint class:
- `mErrorAllowance`: Position error tolerance before corrective forces apply
- `mErrorReductionParameter` (ERP): Baumgarte stabilization coefficient for error correction  
- `mConstraintForceMixing` (CFM): Regularization parameter preventing singular matrices

These parameters integrate soft contacts into DART's global constraint solver alongside rigid-body contacts, joints, and other constraints.

## Dynamics Simulation Pipeline

The soft body simulation follows a structured update sequence within the `World::step()` loop:

1. **Force Accumulation**: External forces (gravity, user input) apply to individual point masses, while internal spring/damper forces calculate based on relative displacements and velocities between connected masses using the `kv`, `ke`, and `dampCoeff` parameters.

2. **Mass Matrix Assembly**: The system constructs the generalized inertia matrix `mI2` from point mass properties, augmented to include soft-body degrees of freedom in the global system.

3. **Collision Detection**: The collision pipeline generates `collision::Contact` objects; soft body involvement triggers `SoftContactConstraint` creation.

4. **Constraint Solution**: The unified constraint solver processes soft contacts simultaneously with rigid contacts, solving the Linear Complementarity Problem (LCP) for the augmented system including both rigid-body and point-mass variables.

5. **State Integration**: Velocities and positions update according to the solved impulses, with the `SoftBodyAspect` propagating changes back to individual `PointMass` instances.

## Practical Implementation Guide

### Creating a Soft Box

The following example demonstrates instantiating a soft body cube using the helper utilities:

```cpp
#include <dart/dynamics/soft_body_node.hpp>
#include <dart/simulation/world.hpp>

// Create skeleton to contain the soft body
auto* softSkeleton = new dart::dynamics::Skeleton();

// Initialize SoftBodyNode with default properties
auto* softNode = new dart::dynamics::SoftBodyNode(
    nullptr, nullptr,
    dart::dynamics::SoftBodyNode::Properties());

// Configure as a box with specific material properties
dart::dynamics::SoftBodyNodeHelper::setBox(
    softNode,
    Eigen::Vector3d(0.5, 0.5, 0.5),    // dimensions
    Eigen::Isometry3d::Identity(),     // local transform
    1.0,                               // total mass
    1.0,                               // vertex stiffness (kv)
    1.0,                               // edge stiffness (ke)
    0.01);                             // damping coefficient

// Finalize skeleton setup
softSkeleton->addBodyNode(softNode);
softSkeleton->init();

// Add to simulation world
auto world = dart::simulation::World::create();
world->addSkeleton(softSkeleton);

```

### Running the Simulation

Soft body dynamics and contact handling occur automatically during the world update:

```cpp
const double dt = 0.001;  // 1ms timestep

for (int i = 0; i < 1000; ++i) {
  world->step();  // Solves all constraints including SoftContactConstraint
  
  // Access current deformation state
  const auto& pointMasses = softNode->getPointMasses();
  for (const auto* pm : pointMasses) {
    Eigen::Vector3d pos = pm->getPositionsInWorld();
    // Process or log point mass positions
  }
}

```

### Inspecting Soft Contact Constraints

For debugging or analysis, you can access active soft contact constraints from the solver:

```cpp
auto* solver = world->getConstraintSolver();
for (auto* constraint : solver->getConstraints()) {
  if (constraint->getType() == 
      dart::constraint::SoftContactConstraint::getStaticType()) {
    
    auto* softConstraint = static_cast<
        dart::constraint::SoftContactConstraint*>(constraint);
    
    // Access collision parameters
    double friction = softConstraint->mFrictionCoeff;
    Eigen::Vector3d normal = softConstraint->mBodyDirection1;
  }
}

```

## Summary

- **DART models soft bodies using `SoftBodyNode`**, which contains discrete `PointMass` elements connected by springs and dampers rather than using continuous finite element methods.
- **The aspect architecture** (`SoftBodyAspect`) maintains separation between soft-body state/properties and rigid-body core systems while allowing unified simulation.
- **Soft contacts resolve through `SoftContactConstraint`**, which selects the nearest point mass to compute contact Jacobians and handles friction using `getTangentBasisMatrixODE()` within the global constraint solver.
- **Material parameters** `kv` (vertex stiffness), `ke` (edge stiffness), and `dampCoeff` control deformation behavior and are stored in `SoftBodyNodeUniqueProperties`.
- **Full integration** with rigid-body dynamics occurs automatically when calling `World::step()`, with soft contacts solved simultaneously alongside rigid contacts using the ERP/CFM stabilization parameters.

## Frequently Asked Questions

### How does DART represent the mass distribution in soft bodies?

DART discretizes the soft body into **point masses** (`PointMass` class) rather than using a continuous mass field. Each point mass stores its individual scalar mass and 3D position, and the total generalized inertia matrix (`mI2`) is assembled dynamically from these discrete masses during the `SoftBodyNode::init()` phase and updated each step via `updateMassMatrix()`.

### Can soft bodies in DART collide with each other, or only with rigid bodies?

The `SoftContactConstraint` implementation handles **both soft-rigid and soft-soft collisions**. When two soft bodies collide, the constraint selects the nearest point mass on each body (`mPointMass1` and `mPointMass2`) and computes coupling Jacobians for both deformable objects simultaneously within the same constraint solver framework used for rigid contacts.

### What is the computational cost of adding soft bodies compared to rigid bodies?

Soft bodies increase the **degrees of freedom** proportionally to their point mass count, expanding the linear system the constraint solver must process. Each point mass adds three translational DOFs, and internal spring forces require additional computations compared to rigid bodies. However, DART maintains performance by integrating soft bodies into the same constraint-based pipeline rather than using a separate penalty-based solver.

### Where can I find a complete working example of soft body simulation in DART?

The official repository provides a minimal runnable example in [`examples/soft_bodies/main.cpp`](https://github.com/dartsim/dart/blob/main/examples/soft_bodies/main.cpp), which demonstrates creating a soft box, configuring material stiffness parameters, adding the skeleton to a world, and stepping the simulation. This file serves as the canonical reference for implementing custom soft body scenarios using the `SoftBodyNodeHelper` utilities and `SoftMeshShape` visualization.