Deformable Objects#
Each deformable object has a label, a world index, and ranges identifying its simulation elements. A rod-backed curve contains bodies and joints. A triangle surface contains particles, triangles, and bending edges. A tetrahedral volume contains particles and tetrahedra.
The family names describe the simulation geometry. The builder methods and supported USD deformable imports populate these lists:
Builder lists |
Native construction |
USD deformable import |
|---|---|---|
|
|
Cable |
|
Cloth |
|
|
Volume |
Each native call records one deformable object. For example,
add_cloth_grid() delegates to
add_cloth_mesh() but records the cloth only once.
USD imports record each simulation prim once, including cable prims with several
disconnected curves. Curves welded into a graph instead share one record for the
complete graph; see Welded USD graphs. Internal rod calls
for parts of a multi-curve prim do not create extra entries.
Builder identities#
Experimental
The builder’s curve_label / curve_world, surface_label /
surface_world, and volume_label / volume_world lists may change
without the normal deprecation period.
Each pair contains one label and world index per deformable object. Native
construction records explicit labels or generates names such as curve_0,
surface_0, and volume_0. USD imports use the simulation prim’s path, or
the graph identifier for welded curves.
Labels may repeat. An index in these lists is not a body or particle index.
Use the lists to identify assets while composing or cloning a builder:
import newton
prototype = newton.ModelBuilder()
prototype.add_rod(
rod=newton.Rod([(0.0, 0.0, 1.0), (0.1, 0.0, 1.0), (0.2, 0.0, 1.0)], radius=0.02),
label="cable",
)
# Replace a template name with the application's asset name.
prototype.curve_label[0] = "gripper_cable"
scene = newton.ModelBuilder()
scene.replicate(prototype, 2, label_prefixes=["env_0", "env_1"])
print(scene.curve_label)
print(scene.curve_world)
['env_0/gripper_cable', 'env_1/gripper_cable']
[0, 1]
Labels are editable. The label and world lists must remain aligned with the recorded deformable objects, so entries must not be appended, removed, or reordered manually.
The builder assigns world indices during construction and cloning.
World -1 identifies global deformable objects.
Use begin_world() / end_world(),
add_world(), or replicate()
to assign worlds when creating or cloning deformable objects. Do not edit the
world lists: changing an entry does not move its simulation elements.
Composition and fixed-joint collapse#
add_builder(), add_world(),
and replicate() preserve the records and offset their
element ranges. Label prefixes also apply to deformable labels. These records
remain on the builder; finalize() does not copy them
to the model. The simulation ranges remain private, and the identity lists do
not provide a public state-selection API.
Labels do not affect collapse_fixed_joints(). Complete
curve records follow the remapped indices. If collapse removes part of a curve,
Newton warns and omits its incomplete record. Use joints_to_keep to preserve
required joints. Particle, triangle, and tetrahedron ranges are not affected by
fixed-joint collapse.
Welded USD graphs#
A welded USD graph is recorded by one add_rod() call,
just like a native graph. Its record includes all created segment bodies and
joints, including the generated root. The source curves are not recorded as
separate deformable objects.
The graph’s label is the existing graph_component identifier in
path_cable_attrs. This identifier reuses one source prim’s path but labels
the whole graph, not just that curve. Read it from the import result rather
than assuming which source path is chosen.
The return maps still describe each source curve. path_cable_map keeps its
segment body indices and an empty joint list; path_cable_attrs keeps its
material and graph identifier. Per-curve joint membership, including shared
joints, remains follow-up work. This does not limit the whole graph’s record.
result = builder.add_usd("harness.usda", return_deformable_results=True)
branch_path = "/World/Branch"
graph_label = result["path_cable_attrs"][branch_path]["graph_component"]
graph_index = builder.curve_label.index(graph_label)
graph_world = builder.curve_world[graph_index] # The complete welded graph.
branch_bodies, branch_joints = result["path_cable_map"][branch_path]
# branch_bodies contains only the branch's segments; branch_joints is [].