Performing Cloth Simulation with Self-Collision Detection in Newton
Newton implements cloth self-collision detection through sewing springs generated by BVH-accelerated proximity queries, using the Style3D solver to simulate realistic fabric dynamics with inter-penetration prevention.
Newton's physics engine provides a comprehensive cloth simulation framework built on the Style3D solver, enabling realistic fabric dynamics with optional self-collision detection. This article explains how to perform cloth simulation with self-collision detection in Newton by leveraging sewing springs, BVH acceleration structures, and GPU kernels to prevent inter-penetration while maintaining simulation stability.
Understanding Newton's Cloth Simulation Architecture
The Style3D Solver Foundation
Newton's cloth simulation is built on top of the Style3D solver, which extends the standard Newton pipeline with custom attributes for anisotropic stretch, bending, and self-collision handling. The solver consumes specialized geometry data computed during the mesh import stage and applies PBD (Position Based Dynamics) or XPBD integration depending on the configuration.
Core Cloth Geometry Helpers
The public API for cloth creation resides in newton/_src/solvers/style3d/cloth.py. This module provides two primary entry points:
add_cloth_mesh– Imports arbitrary triangle meshes with custom UV parameterizationadd_cloth_grid– Generates procedural rectangular grids with optional boundary constraints
Both helpers automatically compute rest-state data including panel-space triangles, edge cotangents for bending, and anisotropic stiffness parameters required by the Style3D solver.
Creating Cloth Geometry
Arbitrary Mesh Import with add_cloth_mesh
The add_cloth_mesh function (lines 91‑129 in newton/_src/solvers/style3d/cloth.py) constructs cloth from arbitrary vertex and index buffers. It performs the following operations:
- Transforms vertices to world space using the provided position and rotation
- Computes per-triangle panel-space rest data via
_compute_panel_triangles - Adds particles, triangles, and edges to the
ModelBuilder - Attaches Style3D-specific attributes including
style3d:tri_aniso_kefor anisotropic stretch and edge rest areas
The function accepts a density parameter derived from mass-per-particle calculations (lines 79‑82) to ensure physically consistent mass distribution across irregular meshes.
Procedural Grid Generation with add_cloth_grid
For regular rectangular cloth, add_cloth_grid (lines 389‑508) provides a higher-level interface. It generates vertex positions and panel UVs procedurally, then delegates to add_cloth_mesh for actual construction.
Boundary conditions are handled through boolean flags (fix_left, fix_right, fix_top, fix_bottom). When enabled, these pin selected vertices by clearing the ParticleFlags.ACTIVE flag and zeroing their mass, creating fixed constraints without additional constraint objects.
Implementing Self-Collision Detection
The Sewing Springs Approach
Newton handles self-collision through sewing springs—short distance constraints that connect vertices lying closer than a user-specified threshold. These springs act as soft repulsion forces that prevent inter-penetration before the narrow-phase collision step, avoiding expensive triangle-triangle queries.
The public entry point is sew_close_vertices (lines 674‑689 in newton/_src/solvers/style3d/cloth.py), which computes proximity pairs and adds springs to the ModelBuilder using default stiffness and damping parameters.
BVH Acceleration and GPU Kernels
The proximity query leverages a Bounding Volume Hierarchy (BVH) for acceleration. The implementation spans three components:
-
create_mesh_sew_springs(lines 600‑671) – Constructs a BVH over all mesh edges using the Warp kernelcompute_edge_aabbs, then queries each vertex's AABB to find candidate edges withinsew_distance. -
compute_sew_v(Warp kernel) (lines 228‑311) – Parallelized GPU/CPU kernel that iterates over candidate edges for each vertex, evaluates Euclidean distances, and stores up tomax_num_sewnearest neighbors. -
sew_close_vertices– Consumes the neighbor pairs and instantiates spring constraints in the simulation graph.
Enabling Self-Collisions in the Pipeline
The enable_self_collisions flag propagates through Newton's import utilities. In newton/_src/utils/import_usd.py (lines 67‑71) and newton/_src/utils/import_urdf.py (lines 81‑85), the schema attributes newton:selfCollisionEnabled and physxArticulation:enabledSelfCollisions are parsed and passed to the builder. When enabled, the mesh import pipeline automatically invokes the sewing spring generation.
Validation tests in newton/tests/test_cloth.py (lines 1091‑1105) verify that enabling self-collision prevents spurious contacts inside the cloth mesh, confirming the system's correctness.
Complete Simulation Workflow
The following example demonstrates the end-to-end pipeline: creating a grid cloth, enabling self-collision via sewing springs, registering Style3D attributes, and running the simulation at 240 Hz.
import newton
from newton.solvers import SolverStyle3D
from newton._src.solvers.style3d.cloth import add_cloth_grid, sew_close_vertices
# 1️⃣ Build the scene
builder = newton.ModelBuilder()
add_cloth_grid(
builder,
pos=[0, 0, 0],
rot=[0, 0, 0, 1], # identity quaternion
vel=[0, 0, 0],
dim_x=30,
dim_y=30,
cell_x=0.05,
cell_y=0.05,
mass=0.01,
fix_top=True,
)
# 2️⃣ Enable self‑collision (sewing springs)
sew_close_vertices(builder, sew_distance=2e-3, sew_interior=False)
# 3️⃣ Register Style3D custom attributes and create the model
SolverStyle3D.register_custom_attributes()
model = builder.finalize()
# 4️⃣ Create a solver and run the simulation
solver = SolverStyle3D(model, device="cpu")
for step in range(200):
solver.step(dt=1/240) # 240 Hz integration
# optional: visualize or log state here
Practical Code Examples
Example 1 – Simple Hanging Cloth with Self-Collision
This snippet creates a 20×20 grid pinned at the top edge with self-collision enabled via 1mm sewing springs:
import newton
from newton.solvers import SolverStyle3D
from newton._src.solvers.style3d.cloth import add_cloth_grid, sew_close_vertices
builder = newton.ModelBuilder()
add_cloth_grid(
builder,
pos=[0, 2, 0],
rot=[0, 0, 0, 1],
vel=[0, 0, 0],
dim_x=20,
dim_y=20,
cell_x=0.1,
cell_y=0.1,
mass=0.02,
fix_top=True, # pin top edge
)
sew_close_vertices(builder, sew_distance=1e-3)
SolverStyle3D.register_custom_attributes()
model = builder.finalize()
solver = SolverStyle3D(model, device="cpu")
for i in range(300):
solver.step(dt=1/240)
Example 2 – Cloth Draped Over a Sphere (Mesh Import)
For arbitrary topology, use add_cloth_mesh with pre-computed vertices and indices:
import newton
from newton.solvers import SolverStyle3D
from newton._src.solvers.style3d.cloth import add_cloth_mesh, sew_close_vertices
# Load a pre‑computed sphere‑covered mesh (e.g., from an OBJ loader)
vertices, indices = load_obj("sphere_cloth.obj") # user‑provided loader
builder = newton.ModelBuilder()
add_cloth_mesh(
builder,
pos=[0, 1, 0],
rot=[0, 0, 0, 1],
vel=[0, 0, 0],
vertices=vertices,
indices=indices,
density=0.5,
panel_verts=None, # use XY as UVs
)
sew_close_vertices(builder, sew_distance=2e-3, sew_interior=True)
SolverStyle3D.register_custom_attributes()
model = builder.finalize()
solver = SolverStyle3D(model, device="cpu")
for _ in range(400):
solver.step(dt=1/240)
Example 3 – Visualising Self-Collision Forces
Debug sewing spring forces using Newton's built-in viewer:
import newton
from newton.solvers import SolverStyle3D
from newton._src.solvers.style3d.cloth import add_cloth_grid, sew_close_vertices
from newton.viewer import Viewer # simple OpenGL viewer
builder = newton.ModelBuilder()
add_cloth_grid(
builder,
pos=[0, 1.5, 0],
rot=[0, 0, 0, 1],
vel=[0, 0, 0],
dim_x=30,
dim_y=30,
cell_x=0.08,
cell_y=0.08,
mass=0.015,
fix_top=True,
)
sew_close_vertices(builder, sew_distance=1.5e-3)
SolverStyle3D.register_custom_attributes()
model = builder.finalize()
solver = SolverStyle3D(model, device="cpu")
viewer = Viewer(model) # automatically creates a viewer
for _ in range(200):
solver.step(dt=1/240)
viewer.render() # shows cloth with spring forces as red lines
Key Source Files and Implementation Details
| File | Purpose |
|---|---|
newton/_src/solvers/style3d/cloth.py |
Core cloth helpers (add_cloth_mesh at lines 91‑129, add_cloth_grid at lines 389‑508) and self‑collision utilities (sew_close_vertices at lines 674‑689, create_mesh_sew_springs at lines 600‑671, compute_sew_v kernel at lines 228‑311). |
newton/_src/sim/builder.py |
ModelBuilder API for adding particles, triangles, edges, and springs. |
newton/_src/solvers/style3d/__init__.py |
Public API exports for the Style3D solver components. |
newton/_src/utils/import_usd.py |
Parses newton:selfCollisionEnabled schema flag (lines 67‑71). |
newton/_src/utils/import_urdf.py |
Handles physxArticulation:enabledSelfCollisions (lines 81‑85). |
newton/tests/test_cloth.py |
Validation suite including test_cloth_collision (lines 1091‑1105) for self-collision correctness. |
newton/solvers.py |
High-level SolverStyle3D registration and solver factory. |
Summary
- Newton's cloth simulation relies on the Style3D solver, which requires custom attributes like
style3d:tri_aniso_kefor anisotropic stretch and bending cotangents. - Use
add_cloth_mesh(lines 91‑129) for arbitrary topology oradd_cloth_grid(lines 389‑508) for procedural rectangular cloth with pinned boundaries. - Self-collision detection is implemented via sewing springs generated by
sew_close_vertices(lines 674‑689), which uses BVH acceleration (create_mesh_sew_springs, lines 600‑671) and the Warp kernelcompute_sew_v(lines 228‑311) for GPU-parallel proximity queries. - Enable self-collision import via USD (
newton:selfCollisionEnabled, lines 67‑71) or URDF (physxArticulation:enabledSelfCollisions, lines 81‑85) schemas, or explicitly callsew_close_verticesin Python. - Always call
SolverStyle3D.register_custom_attributes()(lines 321‑324) before finalizing the model to ensure the solver recognizes Style3D-specific data.
Frequently Asked Questions
How does Newton's sewing spring method compare to traditional triangle-triangle collision detection?
Newton's sewing springs act as soft constraints that prevent vertices from approaching each other within a specified sew_distance, effectively providing continuous collision response without explicit triangle-triangle intersection tests. This approach, implemented in create_mesh_sew_springs (lines 600‑671), is computationally cheaper than full narrow-phase collision detection and resolves inter-penetrations before they occur, whereas traditional methods require expensive geometric intersection queries after penetration happens.
What is the performance impact of enabling self-collision on large cloth meshes?
The self-collision system uses BVH acceleration and Warp GPU kernels (compute_sew_v, lines 228‑311) to parallelize proximity queries across vertices. For a 30×30 grid (900 vertices), the overhead is negligible on modern GPUs, but memory usage scales with the number of sewing springs generated. The max_num_sew parameter limits the number of springs per vertex to control memory consumption, and the BVH construction in create_mesh_sew_springs (lines 600‑671) ensures O(log n) query complexity rather than O(n²) brute-force comparison.
Can self-collision be enabled when importing cloth from USD or URDF files?
Yes. Newton parses the newton:selfCollisionEnabled schema attribute in newton/_src/utils/import_usd.py (lines 67‑71) and the physxArticulation:enabledSelfCollisions attribute in newton/_src/utils/import_urdf.py (lines 81‑85). When these flags are set to true in the source file, the import pipeline automatically invokes the sewing spring generation logic equivalent to calling sew_close_vertices manually in Python.
Why must I call SolverStyle3D.register_custom_attributes() before finalizing the model?
The Style3D solver requires custom attributes such as style3d:tri_aniso_ke (anisotropic stiffness), edge rest areas, and bending cotangents that are not part of the standard Newton particle model. The register_custom_attributes function (lines 321‑324 in newton/_src/solvers/style3d/cloth.py) registers these attributes with the ModelBuilder so that builder.finalize() correctly serializes the Style3D-specific data required by the solver. Without this call, the solver will fail to locate the necessary attribute buffers during simulation stepping.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →