An SDF-based contact path so a deforming body cannot tunnel through a rigid shape between its
vertices, with full integration into the VBD solver. Newton · SolverVBD · NVIDIA L40 · 2026-06.
A parallel-jaw gripper (cube pads) closes on a soft mesh positioned so that no mesh vertex lies between the
jaws — only the interior of a face or an edge does — then lifts and holds.
Left = water-tight OFF reproduces main: the legacy per-particle path only tests
vertices, finds none in the jaws, so the mesh slips through and drops.
Right = water-tight ON: the mesh is caught by its face / edge and held in the air.
The triangle's three vertices are outside the jaws; only the face crosses the pinch. OFF: it falls. ON: a water-tight face contact holds it.
The grid's four corners are outside the jaws; the diagonal edge crosses the pinch. OFF: it falls. ON: a water-tight edge contact holds it (the sheet drapes over the grip).
The feature is purely additive and gated by enable_water_tight_rigid_soft_contact; with the flag off
the contact set and solver results are byte-for-byte identical to before.
finalize() for participating meshes that lack one.[particle, edge, face]. The internal
soft_contact_particle is renamed soft_contact_primitive (now a particle or
soft-triangle id, by range), with new soft_contact_kind / soft_contact_barycentric fields.x = Σ bᵢ·vᵢ of the soft triangle's corners, so the penalty force and
Hessian distribute as bᵢ·F and bᵢ²·H to each vertex (an edge leaves one weight at zero).penetration > 0 gate.vbd_gripper_soft_triangle and vbd_gripper_soft_grid (the videos
above; toggle enable_water_tight to reproduce the OFF / main case).How much memory each shape's SDF actually uses, measured through the real finalize() path at the
default settings (64³ max resolution, UINT16-quantised narrow band, 8³ subgrids). Analytic primitives store nothing;
only meshes allocate a volume SDF.
| Shape | SDF representation | Stored memory |
|---|---|---|
| Box, Sphere, Capsule, Cylinder, Cone, Ellipsoid, Plane | closed-form analytic (evaluated, not stored) | 0 |
| Mesh — bunny (12,200 tris) | texture volume SDF | ≈ 0.48 MB |
| Mesh — bear (3,968 tris) | texture volume SDF | ≈ 0.30 MB |
All analytic shapes report shape_sdf_index = -1 under water-tight — nothing is allocated; the contact
path evaluates their closed-form SDF.
| Component | bunny | bear |
|---|---|---|
| coarse texture (far field, float32) | 2.5 KB (9×9×8) | 1.3 KB (9×6×6) |
| subgrid texture (narrow band, uint16) | 488 KB (63³) | 307 KB (54³) |
| indirection slots (uint32) | 1.8 KB | 0.8 KB |
| total | 493 KB | 310 KB |
UINT16 → float32 roughly doubles the subgrid; max_resolution scales the narrow
band by ~the square of the ratio.Texture-SDF value vs. the exact mesh signed distance (winding-number query) at 300k points sampled within ±6 voxels of the surface (the contact-relevant band). The error is resolution-limited, so it is reported both absolutely and as a fraction of one voxel (≈ object extent / 64); the meshes are at their native USD scale.
| Mesh | voxel | MAE | RMSE | p99 | max |
|---|---|---|---|---|---|
| bunny | 26.7 mm | 1.02 mm (3.8% vox) | 1.86 mm (6.9%) | 7.8 mm (29%) | 22 mm (83%) |
| bear | 152.7 mm | 7.30 mm (4.8% vox) | 14.6 mm (9.6%) | 51 mm (33%) | 206 mm (135%) |
max_resolution roughly halves the error and ~8×'s the subgrid.