Deformable Bodies (Beta)#
This documentation introduces the new deformable body beta feature based on two new USD schemas: the Omni Physics Deformable Schema, which is staged for becoming part of the standard USD Physics Schema, and PhysX specific schema extensions in PhysX Schema Addition. The new schemas and implementations replace the deprecated deformable body schema and implementation as well as the particle cloth feature described here.
To enable the deformable beta feature in the Omniverse Kit UI, see Enable Deformable Schema Beta.
For information on how to migrate deprecated schema code, functions in omni.physx.scripts.deformableUtils
or USD assets, see Deformable Migration Guide.
Single Mesh Surface Deformable#
To create a single mesh surface deformable, a UsdGeom.Mesh
, limited to triangular faces, is required that can serve as a simulation mesh:
from pxr import Usd, UsdGeom, Vt, Gf
def create_trimesh(stage, path, res):
triMesh = UsdGeom.Mesh.Define(stage, path)
step = 1.0 / res
verts = [(i * step, j * step, 0.0) for j in range(res + 1) for i in range(res + 1)]
idx = lambda i, j: j * (res + 1) + i
tris = [(idx(i,j), idx(i+1,j), idx(i+1,j+1)) + (idx(i,j), idx(i+1,j+1), idx(i,j+1))
for j in range(res) for i in range(res)]
triMesh.GetPointsAttr().Set(Vt.Vec3fArray(verts))
triMesh.GetFaceVertexCountsAttr().Set([3] * (2 * res**2))
triMesh.GetFaceVertexIndicesAttr().Set([i for t in tris for i in t])
return triMesh
Once a suitable triangle mesh is available a single mesh surface deformable can be defined by applying OmniPhysicsDeformableBodyAPI
, OmniPhysicsSurfaceDeformableSimAPI
and UsdPhysics.CollisionAPI
. PhysX specific attributes can be set by applying PhysxSurfaceDeformableBodyAPI
and PhysxSchema.PhysxCollisionAPI
. The following code snippet additionally shows how to apply APIs and set attributes based on codeless schemas:
from pxr import Usd, UsdGeom, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
stage = omni.usd.get_context().get_stage()
triMesh = create_trimesh(stage, "/World/TriMesh", 6)
prim = triMesh.GetPrim()
# Apply deformable body API and set mass
prim.ApplyAPI("OmniPhysicsDeformableBodyAPI")
if prim.HasAPI("OmniPhysicsDeformableBodyAPI"):
prim.GetAttribute("omniphysics:mass").Set(0.5)
# Apply volume simulation API and set rest shape properties
prim.ApplyAPI("OmniPhysicsSurfaceDeformableSimAPI")
if prim.HasAPI("OmniPhysicsSurfaceDeformableSimAPI"):
restShapePointsAttr = prim.GetAttribute("omniphysics:restShapePoints")
restShapePointsAttr.Set(triMesh.GetPointsAttr().Get())
restTriVtxIndicesAttr = prim.GetAttribute("omniphysics:restTriVtxIndices")
# Convert face vertex indices to Gf.Vec3i indices
triVtxIndices = list(zip(*[iter(triMesh.GetFaceVertexIndicesAttr().Get())]*3))
restTriVtxIndicesAttr.Set(triVtxIndices)
# Apply collision API
collisionAPI = UsdPhysics.CollisionAPI.Apply(prim)
# Optionally set physx specific APIs and properties
prim.ApplyAPI("PhysxSurfaceDeformableBodyAPI")
if prim.HasAPI("PhysxSurfaceDeformableBodyAPI"):
prim.GetAttribute("physxDeformableBody:disableGravity").Set(True)
prim.GetAttribute("physxDeformableBody:selfCollision").Set(True)
physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(prim)
if physxCollisionAPI:
physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
physxCollisionAPI.GetRestOffsetAttr().Set(0.01)
While the Omni Physics Deformable Schema allows the specification of a deformable body with zero, one or multiple colliders, the Omni PhysX implementation is limited to deformable bodies with exactly one collider. Therefore, in the case of a single mesh deformable body, adding a UsdPhysics.CollisionAPI
to the mesh is mandatory.
Omni Physics Deformable Schema allows for a rest shape topology (restTriVtxIndices
) that diverges from the simulation mesh topology (faceVertexIndices
), however, Omni PhysX is currently limited to accepting only identical topologies.
The basic setup can be simplified by using omni.physx.scripts.deformableUtils.set_physics_surface_deformable_body
:
from pxr import Usd, UsdGeom, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils
stage = omni.usd.get_context().get_stage()
triMesh = create_trimesh(stage, "/World/TriMesh", 6)
prim = triMesh.GetPrim()
# Call deformableUtils helper
success = deformableUtils.set_physics_surface_deformable_body(stage, prim.GetPath())
# Apply customizations
if prim.HasAPI("OmniPhysicsDeformableBodyAPI"):
prim.GetAttribute("omniphysics:mass").Set(0.5)
prim.ApplyAPI("PhysxSurfaceDeformableBodyAPI")
if prim.HasAPI("PhysxSurfaceDeformableBodyAPI"):
prim.GetAttribute("physxDeformableBody:disableGravity").Set(True)
prim.GetAttribute("physxDeformableBody:selfCollision").Set(True)
physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(prim)
if physxCollisionAPI:
physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
physxCollisionAPI.GetRestOffsetAttr().Set(0.01)
Surface Deformable Hierarchy#
This section provides detailed steps for creating a surface deformable hierarchy in Omni PhysX. The following components need to be specified:
Root: Using a
UsdGeom.Xform
prim enables the specification of a coordinate space within which the deformable will be simulated.Simulation mesh: A
UsdGeom.Mesh
prim, limited to triangular faces, is used to define the simulation state and the rest shape of the deformable body.Collision mesh: For surface deformable bodies, using a separate collision mesh is not supported. Instead the simulation mesh needs to be marked for collision detection.
Optionally one can specify:
Graphics geometry: Any number of
UsdGeom.PointBased
prims can be used to visualize the deformable.
If a suitable simulation mesh is not available, it can be helpful to have the simulation mesh automatically generated from a given UsdGeom.Mesh
prim, which is covered in Auto Surface Deformable Hierarchy.
In order to demonstrate the flexibility around render meshes a helper is introduced to create a quad mesh:
def create_quadmesh(stage, path, res):
quadMesh = UsdGeom.Mesh.Define(stage, path)
step = 1.0 / res
v = [(i*step, j*step, 0.0) for j in range(res+1) for i in range(res+1)]
idx = lambda i, j: j*(res+1)+i
quads = [(idx(i,j), idx(i+1,j), idx(i+1,j+1), idx(i,j+1))
for j in range(res) for i in range(res)]
quadMesh.GetPointsAttr().Set(Vt.Vec3fArray(v))
quadMesh.GetFaceVertexCountsAttr().Set([4]*(res*res))
quadMesh.GetFaceVertexIndicesAttr().Set([p for quad in quads for p in quad])
return quadMesh
The following example shows how a hierarchy can be set up:
from pxr import Usd, UsdGeom, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
stage = omni.usd.get_context().get_stage()
# Create a root prim
rootXform = UsdGeom.Xform.Define(stage, "/World/DeformableBody")
rootPrim = rootXform.GetPrim()
rootPrim.ApplyAPI("OmniPhysicsDeformableBodyAPI")
if rootPrim.HasAPI("OmniPhysicsDeformableBodyAPI"):
rootPrim.GetAttribute("omniphysics:mass").Set(0.5)
# Apply customizations
rootPrim.ApplyAPI("PhysxSurfaceDeformableBodyAPI")
if rootPrim.HasAPI("PhysxSurfaceDeformableBodyAPI"):
rootPrim.GetAttribute("physxDeformableBody:disableGravity").Set(True)
rootPrim.GetAttribute("physxDeformableBody:selfCollision").Set(True)
# Define a simulation mesh
simPath = "/World/DeformableBody/SimulationMesh"
simMesh = create_trimesh(stage, simPath, 6)
simPrim = simMesh.GetPrim()
simPrim.ApplyAPI("OmniPhysicsSurfaceDeformableSimAPI")
if simPrim.HasAPI("OmniPhysicsSurfaceDeformableSimAPI"):
restShapePointsAttr = simPrim.GetAttribute("omniphysics:restShapePoints")
restShapePointsAttr.Set(simMesh.GetPointsAttr().Get())
triVtxIndices = list(zip(*[iter(simMesh.GetFaceVertexIndicesAttr().Get())]*3))
restTriVtxIndicesAttr = simPrim.GetAttribute("omniphysics:restTriVtxIndices")
restTriVtxIndicesAttr.Set(triVtxIndices)
# Add bind pose for registering other meshes with respect to sim mesh
purposesAttrName = "deformablePose:custom:omniphysics:purposes"
pointsAttrName = "deformablePose:custom:omniphysics:points"
simPrim.ApplyAPI("OmniPhysicsDeformablePoseAPI", "custom")
if simPrim.HasAPI("OmniPhysicsDeformablePoseAPI", "custom"):
simPrim.GetAttribute(purposesAttrName).Set(["bindPose"])
simPrim.GetAttribute(pointsAttrName).Set(simMesh.GetPointsAttr().Get())
# Mark the simulation mesh for collision detection
collisionAPI = UsdPhysics.CollisionAPI.Apply(simPrim)
# Apply customizations
physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(simPrim)
if (physxCollisionAPI):
physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
physxCollisionAPI.GetRestOffsetAttr().Set(0.01)
# Don't render simulation mesh
simMesh.GetPurposeAttr().Set("guide")
# Optionally add a render mesh
renderPath = "/World/DeformableBody/RenderMesh"
renderMesh = create_quadmesh(stage, renderPath, 12)
renderPrim = renderMesh.GetPrim()
# Add bind pose for registering configuration with respect to sim mesh
renderPrim.ApplyAPI("OmniPhysicsDeformablePoseAPI", "custom")
if renderPrim.HasAPI("OmniPhysicsDeformablePoseAPI", "custom"):
renderPrim.GetAttribute(purposesAttrName).Set(["bindPose"])
renderPrim.GetAttribute(pointsAttrName).Set(renderMesh.GetPointsAttr().Get())
Auto Surface Deformable Hierarchy#
Instead of the manual setup shown above, omni.physx.scripts.deformableUtils.create_auto_surface_deformable_hierarchy
can be used to automatically generate a suitable simulation mesh from a given UsdGeom.Mesh
source mesh. For instance, it is helpful when the provided mesh consists of quads or is excessively high-resolution. The function sets up the hierarchy using a PhysxAutoDeformableBodyAPI
:
from pxr import Usd, UsdGeom, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils
from omni.physx import get_physx_cooking_interface
stage = omni.usd.get_context().get_stage()
# Setup source mesh for generation of simulation mesh
cookingSrcPath = "/World/CookingSrcMesh"
cookingSrcMesh = create_quadmesh(stage, cookingSrcPath, 6)
cookingSrcMesh.MakeInvisible()
# Create a root prim
rootXform = UsdGeom.Xform.Define(stage, "/World/DeformableBody")
rootPrim = rootXform.GetPrim()
# Create render mesh, could be multiple
renderPath = "/World/DeformableBody/RenderMesh"
renderMesh = create_quadmesh(stage, renderPath, 12)
success = deformableUtils.create_auto_surface_deformable_hierarchy(
stage,
rootPrim.GetPath(),
"/World/DeformableBody/SimulationMesh",
cookingSrcPath,
cooking_src_simplification_enabled=False,
set_visibility_with_guide_purpose=True
)
# Apply customizations to root
rootPrim.ApplyAPI("PhysxSurfaceDeformableBodyAPI")
if rootPrim.HasAPI("PhysxSurfaceDeformableBodyAPI"):
rootPrim.GetAttribute("physxDeformableBody:disableGravity").Set(True)
rootPrim.GetAttribute("physxDeformableBody:selfCollision").Set(True)
# Apply customizations to sim mesh
simPrim = stage.GetPrimAtPath("/World/DeformableBody/SimulationMesh")
physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(simPrim)
if physxCollisionAPI:
physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
physxCollisionAPI.GetRestOffsetAttr().Set(0.01)
# Trigger synchronous generation of simulation mesh data
get_physx_cooking_interface().cook_auto_deformable_body(str(rootPrim.GetPath()))
See implementation of create_auto_surface_deformable_hierarchy
for details on how to set up a PhysxAutoDeformableBodyAPI
manually.
Note that the cooking process is triggered synchronously in the example. This is not required if no immediate access to generated mesh data is required. The mesh data is always guaranteed to be available before the simulation starts.
Single Mesh Volume Deformable#
In order to create a single mesh volume deformable, a UsdGeom.TetMesh
prim is required that can serve as a simulation mesh. Here is an example that shows how to set up a simple mesh forming a cube:
from pxr import Usd, UsdGeom, Vt, Gf
def create_simulation_tetmesh(stage, path, add_surface=False):
# Create a tet mesh prim
tetMesh = UsdGeom.TetMesh.Define(stage, path)
# Set the points
points = Vt.Vec3fArray([
(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0),
(0, 0, 1), (1, 0, 1), (1, 1, 1), (0, 1, 1),
])
# Define three tetrahedra
tetVtxIndices = Vt.Vec4iArray([
(0, 1, 3, 4), (1, 2, 3, 6), (1, 4, 5, 6), (3, 4, 6, 7), (1, 3, 4, 6),
])
tetMesh.GetPointsAttr().Set(points)
tetMesh.GetTetVertexIndicesAttr().Set(tetVtxIndices)
# Adding surface information for collision detection
if add_surface:
surfaceFaceVertexIndices = UsdGeom.TetMesh.ComputeSurfaceFaces(tetMesh)
tetMesh.GetSurfaceFaceVertexIndicesAttr().Set(surfaceFaceVertexIndices)
return tetMesh
Once a tetrahedron mesh is available a single mesh volume deformable can be defined by applying OmniPhysicsDeformableBodyAPI
, OmniPhysicsVolumeDeformableSimAPI
and UsdPhysics.CollisionAPI
. PhysX specific attributes can be set by applying PhysxBaseDeformableBodyAPI
and PhysxSchema.PhysxCollisionAPI
. The following code snippet additionally shows how to apply APIs and set attributes based on codeless schemas:
from pxr import Usd, UsdGeom, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
stage = omni.usd.get_context().get_stage()
tetMesh = create_simulation_tetmesh(stage, "/World/TetMesh", add_surface=True)
prim = tetMesh.GetPrim()
# Apply deformable body API and set mass
prim.ApplyAPI("OmniPhysicsDeformableBodyAPI")
if prim.HasAPI("OmniPhysicsDeformableBodyAPI"):
prim.GetAttribute("omniphysics:mass").Set(30.0)
# Apply volume simulation API and set rest shape properties
prim.ApplyAPI("OmniPhysicsVolumeDeformableSimAPI")
if prim.HasAPI("OmniPhysicsVolumeDeformableSimAPI"):
restShapePointsAttr = prim.GetAttribute("omniphysics:restShapePoints")
restShapePointsAttr.Set(tetMesh.GetPointsAttr().Get())
restTetVtxIndicesAttr = prim.GetAttribute("omniphysics:restTetVtxIndices")
restTetVtxIndicesAttr.Set(tetMesh.GetTetVertexIndicesAttr().Get())
# Apply collision API
collisionAPI = UsdPhysics.CollisionAPI.Apply(prim)
# Optionally set physx specific APIs and properties
prim.ApplyAPI("PhysxBaseDeformableBodyAPI")
if prim.HasAPI("PhysxBaseDeformableBodyAPI"):
prim.GetAttribute("physxDeformableBody:disableGravity").Set(True)
physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(prim)
if physxCollisionAPI:
physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
physxCollisionAPI.GetRestOffsetAttr().Set(0.01)
While the Omni Physics Deformable Schema allows the specification of a deformable body with zero, one or multiple colliders, the Omni PhysX implementation is limited to deformable bodies with exactly one collider. Therefore, in the case of a single mesh deformable body, adding a UsdPhysics.CollisionAPI
to the mesh is mandatory.
Omni Physics Deformable Schema allows for a rest shape topology (restTetVtxIndices
) that diverges from the simulation mesh topology (tetVertexIndices
), however, Omni PhysX is currently limited to accepting only identical topologies.
The basic setup can be simplified by using omni.physx.scripts.deformableUtils.set_physics_volume_deformable_body
:
from pxr import Usd, UsdGeom, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils
stage = omni.usd.get_context().get_stage()
tetMesh = create_simulation_tetmesh(stage, "/World/TetMesh", add_surface=True)
prim = tetMesh.GetPrim()
# Call deformableUtils helper
success = deformableUtils.set_physics_volume_deformable_body(stage, prim.GetPath())
# Apply customizations
if (prim.HasAPI("OmniPhysicsDeformableBodyAPI")):
prim.GetAttribute("omniphysics:mass").Set(30.0)
prim.ApplyAPI("PhysxBaseDeformableBodyAPI")
if (prim.HasAPI("PhysxBaseDeformableBodyAPI")):
prim.GetAttribute("physxDeformableBody:disableGravity").Set(True)
physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(prim)
if (physxCollisionAPI):
physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
physxCollisionAPI.GetRestOffsetAttr().Set(0.01)
Volume Deformable Hierarchy#
This section provides detailed steps for creating a volume deformable hierarchy in Omni PhysX. The following components need to be specified:
Root: Using a
UsdGeom.Xform
prim enables the specification of a coordinate space within which the deformable will be simulated.Simulation mesh: A
UsdGeom.TetMesh
prim is used to define the simulation state and the rest shape of the deformable body.
Optionally one can also specify:
Collision mesh: Optionally a separate
UsdGeom.TetMesh
prim is used to define geometry used for collision detection. If no separate collision mesh is specified, it’s mandatory to mark the simulation mesh for collision detection.Graphics geometry: Any number of
UsdGeom.PointBased
prims can be used to visualize the deformable.
If suitable simulation and collision meshes are not available, it can be helpful to have the meshes automatically generated from a given UsdGeom.Mesh
prim, which is covered in Auto Volume Deformable Hierarchy.
First a helper function to create a collision tetmesh is defined:
from pxr import Usd, UsdGeom, Vt, Gf
def create_collision_tetmesh(stage, path):
# Create a tet mesh prim
tetMesh = UsdGeom.TetMesh.Define(stage, path)
points = Vt.Vec3fArray([
(0.134, 0.134, 0.134), # 0: bottom-front-left
(0.866, 0.134, 0.134), # 1: bottom-front-right
(0.866, 0.866, 0.134), # 2: bottom-back-right
(0.134, 0.866, 0.134), # 3: bottom-back-left
(0.134, 0.134, 0.866), # 4: top-front-left
(0.866, 0.134, 0.866), # 5: top-front-right
(0.866, 0.866, 0.866), # 6: top-back-right
(0.134, 0.866, 0.866), # 7: top-back-left
(0.5, 0.5, 0.0), # 8: bottom face center
(0.5, 0.5, 1.0), # 9: top face center
(0.0, 0.5, 0.5), # 10: left face center
(1.0, 0.5, 0.5), # 11: right face center
(0.5, 0.0, 0.5), # 12: front face center
(0.5, 1.0, 0.5), # 13: back face center
(0.5, 0.5, 0.5), # 14 center
])
tetVtxIndices = Vt.Vec4iArray([
(0, 1, 8, 14), (1, 2, 8, 14), (2, 3, 8, 14), (3, 0, 8, 14), # bottom tets
(4, 5, 9, 14), (5, 6, 9, 14), (6, 7, 9, 14), (7, 4, 9, 14), # top tets
(0, 1, 12, 14), (1, 5, 12, 14), (5, 4, 12, 14), (4, 0, 12, 14), # front tets
(3, 2, 13, 14), (2, 6, 13, 14), (6, 7, 13, 14), (7, 3, 13, 14), # back tets
(0, 3, 10, 14), (3, 10, 7, 14), (7, 10, 4, 14), (4, 10, 0, 14), # left tets
(1, 2, 11, 14), (2, 11, 6, 14), (6, 11, 5, 14), (5, 11, 1, 14), # right tets
])
tetMesh.GetPointsAttr().Set(points)
tetMesh.GetTetVertexIndicesAttr().Set(tetVtxIndices)
# Adding surface information for collision detection
surfaceFaceVertexIndices = UsdGeom.TetMesh.ComputeSurfaceFaces(tetMesh)
tetMesh.GetSurfaceFaceVertexIndicesAttr().Set(surfaceFaceVertexIndices)
return tetMesh
Then a helper function to create a render mesh with details is defined:
from pxr import Usd, UsdGeom, Vt, Gf
import numpy as np
def create_sphere_mesh(stage, path):
subdivs, amplitude, freq, slope = 6, 0.01, 30.0, 0.5
mesh = UsdGeom.Mesh.Define(stage, path)
# Initial Octahedron
pts = [(1.0,0.5,0.5), (0.0,0.5,0.5), (0.5,1.0,0.5),
(0.5,0.0,0.5), (0.5,0.5,1.0), (0.5,0.5,0.0)]
tris = [(0,2,4), (2,1,4), (1,3,4), (3,0,4), (2,0,5), (1,2,5), (3,1,5), (0,3,5)]
mid = {}
for _ in range(subdivs):
new = []
for i,j,k in tris:
def m(a,b):
key = tuple(sorted((a,b)))
if key not in mid:
p = np.add(pts[a], pts[b]) / 2
mid[key] = len(pts)
pts.append(tuple(p))
return mid[key]
a,b,c = m(i,j), m(j,k), m(k,i)
new += [(i,a,c), (j,b,a), (k,c,b), (a,b,c)]
tris = new
for i, p in enumerate(pts):
v = np.array(p) - 0.5
n = v / np.linalg.norm(v)
theta = np.arccos(n[2]) # [0, pi]
phi = np.mod(np.arctan2(n[1], n[0]), 2 * np.pi) # [0, 2π]
fade = np.sin(theta) ** 3
wave = amplitude * fade * np.sin(freq * (theta + slope * phi))
pts[i] = tuple(0.5 + (0.5 + wave) * n)
mesh.GetPointsAttr().Set(Vt.Vec3fArray(pts))
mesh.GetFaceVertexCountsAttr().Set([3]*len(tris))
mesh.GetFaceVertexIndicesAttr().Set([i for tri in tris for i in tri])
return mesh
Finally the deformable body hierarchy can be created:
from pxr import Usd, UsdGeom, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
stage = omni.usd.get_context().get_stage()
# Create a root prim
rootXform = UsdGeom.Xform.Define(stage, "/World/DeformableBody")
rootPrim = rootXform.GetPrim()
rootPrim.ApplyAPI("OmniPhysicsDeformableBodyAPI")
if (rootPrim.HasAPI("OmniPhysicsDeformableBodyAPI")):
rootPrim.GetAttribute("omniphysics:mass").Set(30.0)
# Apply customizations to root
rootPrim.ApplyAPI("PhysxBaseDeformableBodyAPI")
if (rootPrim.HasAPI("PhysxBaseDeformableBodyAPI")):
rootPrim.GetAttribute("physxDeformableBody:disableGravity").Set(True)
# Define a simulation mesh
simPath = "/World/DeformableBody/SimulationMesh"
simMesh = create_simulation_tetmesh(stage, simPath, add_surface=False)
simPrim = simMesh.GetPrim()
simPrim.ApplyAPI("OmniPhysicsVolumeDeformableSimAPI")
if (simPrim.HasAPI("OmniPhysicsVolumeDeformableSimAPI")):
restShapePointsAttr = simPrim.GetAttribute("omniphysics:restShapePoints")
restShapePointsAttr.Set(simMesh.GetPointsAttr().Get())
restTetVtxIndicesAttr = simPrim.GetAttribute("omniphysics:restTetVtxIndices")
restTetVtxIndicesAttr.Set(simMesh.GetTetVertexIndicesAttr().Get())
# Add bind pose for registering other meshes with respect to sim mesh
purposesAttrName = "deformablePose:custom:omniphysics:purposes"
pointsAttrName = "deformablePose:custom:omniphysics:points"
simPrim.ApplyAPI("OmniPhysicsDeformablePoseAPI", "custom")
if simPrim.HasAPI("OmniPhysicsDeformablePoseAPI", "custom"):
simPrim.GetAttribute(purposesAttrName).Set(["bindPose"])
simPrim.GetAttribute(pointsAttrName).Set(simMesh.GetPointsAttr().Get())
# Define a separate collision mesh (instead we could also apply the
# CollisionAPI to the simPrim)
collisionPath = "/World/DeformableBody/CollisionMesh"
collisionMesh = create_collision_tetmesh(stage, collisionPath)
collisionPrim = collisionMesh.GetPrim()
collisionAPI = UsdPhysics.CollisionAPI.Apply(collisionPrim)
# Add bind pose for registering configuration with respect to sim mesh
collisionPrim.ApplyAPI("OmniPhysicsDeformablePoseAPI", "custom")
if collisionPrim.HasAPI("OmniPhysicsDeformablePoseAPI", "custom"):
collisionPrim.GetAttribute(purposesAttrName).Set(["bindPose"])
collisionPrim.GetAttribute(pointsAttrName).Set(collisionMesh.GetPointsAttr().Get())
# Apply customizations to collision mesh
collisionPrim.ApplyAPI("PhysxCollisionAPI")
if (collisionPrim.HasAPI("PhysxCollisionAPI")):
collisionPrim.GetAttribute("physxCollision:contactOffset").Set(0.02)
collisionPrim.GetAttribute("physxCollision:restOffset").Set(0.01)
# Optionally add a render mesh
renderPath = "/World/DeformableBody/RenderMesh"
renderMesh = create_sphere_mesh(stage, renderPath)
# Add bind pose for registering configuration with respect to sim mesh
renderPrim.ApplyAPI("OmniPhysicsDeformablePoseAPI", "custom")
if renderPrim.HasAPI("OmniPhysicsDeformablePoseAPI", "custom"):
renderPrim.GetAttribute(purposesAttrName).Set(["bindPose"])
renderPrim.GetAttribute(pointsAttrName).Set(renderMesh.GetPointsAttr().Get())
Auto Volume Deformable Hierarchy#
Instead of the manual setup shown above, omni.physx.scripts.deformableUtils.create_auto_volume_deformable_hierarchy
can be used to automatically generate suitable simulation and collision tetrahedral meshes from a given source UsdGeom.Mesh
prim. This is helpful especially since tetrahedral meshes are often not available and need to be generated from graphical assets. The function sets up the hierarchy using a PhysxAutoDeformableBodyAPI
:
from pxr import Usd, UsdGeom, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils
from omni.physx import get_physx_cooking_interface
stage = omni.usd.get_context().get_stage()
# Create a root prim
rootXform = UsdGeom.Xform.Define(stage, "/World/DeformableBody")
rootPrim = rootXform.GetPrim()
# Create render mesh, could be multiple
renderPath = "/World/DeformableBody/RenderMesh"
renderMesh = create_sphere_mesh(stage, renderPath)
success = deformableUtils.create_auto_volume_deformable_hierarchy(
stage = stage,
root_prim_path = rootPrim.GetPath(),
simulation_tetmesh_path = "/World/DeformableBody/SimulationMesh",
collision_tetmesh_path = "/World/DeformableBody/CollisionMesh",
cooking_src_mesh_path = renderPath,
simulation_hex_mesh_enabled = True,
cooking_src_simplification_enabled = True,
set_visibility_with_guide_purpose = True
)
if (rootPrim.HasAPI("OmniPhysicsDeformableBodyAPI")):
rootPrim.GetAttribute("omniphysics:mass").Set(30.0)
# Apply customizations to root
rootPrim.ApplyAPI("PhysxBaseDeformableBodyAPI")
if (rootPrim.HasAPI("PhysxBaseDeformableBodyAPI")):
rootPrim.GetAttribute("physxDeformableBody:disableGravity").Set(True)
# Apply customizations to collision mesh
collisionPrim = stage.GetPrimAtPath("/World/DeformableBody/CollisionMesh")
physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(collisionPrim)
if physxCollisionAPI:
physxCollisionAPI.GetContactOffsetAttr().Set(0.02)
physxCollisionAPI.GetRestOffsetAttr().Set(0.01)
# Trigger synchronous generation of simulation mesh data
get_physx_cooking_interface().cook_auto_deformable_body(str(rootPrim.GetPath()))
Note how in this example the render mesh within the deformable body hierarchy is used as the source cooking mesh. This is different from the previous example for surface deformable bodies.
See implementation of create_auto_volume_deformable_hierarchy
for details on how to set up a PhysxAutoDeformableBodyAPI
manually. If simulation_hex_mesh_enabled
parameter is set to True, a PhysxAutoDeformableHexahedralMeshAPI
is applied which triggers the setup of a separate simulation hexahedrally structured tet mesh. When the deformable body is instantiated in PhysX the simulation mesh is tagged as a special hexahedral mesh enabling corresponding optimizations. This feature can currently not be enabled through manual setup without PhysxAutoDeformableHexahedralMeshAPI
.
Note that the cooking process is triggered synchronously in the example. This is not required if no immediate access to generated mesh data is required. The mesh data is always guaranteed to be available before the simulation starts.
Create and Assign Materials#
Physics materials define how a deformable body’s volume reacts to external forces. The Omni Physics Deformable Schema provides three API schema layers that can be stacked on a UsdShade.Material
prim (see Omni Physics Deformable Schema for more details, but also note the relevant limitations of the current implementation):
OmniPhysicsBaseMaterialAPI
: shared friction, density parameters that are also used by rigid bodies.OmniPhysicsDeformableMaterialAPI
: generic parameters for both volume and surface deformables (Young’s modulus, Poisson’s ratio).OmniPhysicsSurfaceDeformableMaterialAPI
: extra parameters that only apply to surface deformables (thickness, bend stiffness) and (stretch, shear stiffness - not supported).
PhysX specific API schemas add non-standard parameters through
PhysxDeformableMaterialAPI
and PhysxSurfaceDeformableMaterialAPI
(elasticity damping, bend damping).
The material binding mechanism is analogous to how rigid body materials are bound, see Configure Rigid Body’s Material Properties.
The following sections show Python snippets for volume and surface deformables that each create two materials with different stiffness parameters, and bind them to separate deformable bodies.
Volume Deformables#
The following code snippet provides a helper to create a volume deformable:
from pxr import Usd, UsdGeom, UsdShade, Sdf, Vt, Gf, UsdPhysics, PhysxSchema
from omni.physx.scripts import deformableUtils
def create_volume_deformable(stage, path, offset):
# Create a root prim
rootXform = UsdGeom.Xform.Define(stage, path)
rootPrim = rootXform.GetPrim()
# Set the offset
rootXform.AddTranslateOp().Set(offset)
# Create render mesh, could be multiple
renderPath = path + "/RenderMesh"
renderMesh = create_sphere_mesh(stage, renderPath)
success = deformableUtils.create_auto_volume_deformable_hierarchy(
stage = stage,
root_prim_path = rootPrim.GetPath(),
simulation_tetmesh_path = rootPrim.GetPath().AppendChild("SimulationMesh"),
collision_tetmesh_path = rootPrim.GetPath().AppendChild("CollisionMesh"),
cooking_src_mesh_path = renderPath,
simulation_hex_mesh_enabled = True,
cooking_src_simplification_enabled = True,
set_visibility_with_guide_purpose = True
)
return rootPrim
The following code snippet shows how to create a volume deformable and a suitable deformable material:
from pxr import Usd, UsdGeom, UsdShade, Sdf, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils, physicsUtils
def create_volume_material(stage, path, youngs, poissons):
mat = UsdShade.Material.Define(stage, path)
prim = mat.GetPrim()
# Common parameters
prim.ApplyAPI("OmniPhysicsBaseMaterialAPI")
prim.GetAttribute("omniphysics:staticFriction").Set(10.0)
prim.GetAttribute("omniphysics:dynamicFriction").Set(10.0)
prim.GetAttribute("omniphysics:density").Set(1000.0)
# Common deformable parameters
prim.ApplyAPI("OmniPhysicsDeformableMaterialAPI")
prim.GetAttribute("omniphysics:youngsModulus").Set(youngs)
prim.GetAttribute("omniphysics:poissonsRatio").Set(poissons)
# PhysX extras (optional)
prim.ApplyAPI("PhysxDeformableMaterialAPI")
prim.GetAttribute("physxDeformableMaterial:elasticityDamping").Set(0.0)
return mat
# Get stage and add ground plane
stage = omni.usd.get_context().get_stage()
planePath = "/World/GroundPlane"
physicsUtils.add_ground_plane(stage, planePath, "Z", 25.0, Gf.Vec3f(0.0), Gf.Vec3f(0.5))
# Create deformable bodies
softDeformablePrim = create_volume_deformable(stage,
"/World/DeformableBody_soft",
Gf.Vec3f(0, -1, 0))
hardDeformablePrim = create_volume_deformable(stage,
"/World/DeformableBody_hard",
Gf.Vec3f(0, 1, 0))
# Create materials
softMatPath = "/World/DeformableMaterial_soft"
hardMatPath = "/World/DeformableMaterial_hard"
softMat = create_volume_material(stage, softMatPath, youngs=1e5, poissons=0.45)
hardMat = create_volume_material(stage, hardMatPath, youngs=1e8, poissons=0.45)
# Bind the materials to the deformable bodies
bindingApi = UsdShade.MaterialBindingAPI.Apply(softDeformablePrim)
bindingApi.Bind(softMat, UsdShade.Tokens.weakerThanDescendants, "physics")
bindingApi = UsdShade.MaterialBindingAPI.Apply(hardDeformablePrim)
bindingApi.Bind(hardMat, UsdShade.Tokens.weakerThanDescendants, "physics")
Note that the material as bound to the simulation mesh defines the behavior of the deformable body. Binding to the root deformable body prim works, as the material binding recursively applies to all sub prims. Currently multi material binding via UsdGeom.Subset
or binding specifically to the collision mesh for surface material properties is not supported.
If the material should be general purpose (i.e. used for physics and rendering), the materialPurpose
parameter of UsdShade.MaterialBindingAPI
can be omitted.
Surface Deformables#
The following code snippet provides a helper to create a surface deformable:
from pxr import Usd, UsdGeom, UsdShade, Sdf, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils, physicsUtils
def create_surface_deformable(stage, path, offset, dim):
# Create simulation mesh
triMesh = create_trimesh(stage, path, dim)
prim = triMesh.GetPrim()
# Set the offset
triMesh.AddTranslateOp().Set(offset)
# Call deformableUtils helper
success = deformableUtils.set_physics_surface_deformable_body(stage, prim.GetPath())
# Apply customizations
prim.ApplyAPI("PhysxSurfaceDeformableBodyAPI")
if prim.HasAPI("PhysxSurfaceDeformableBodyAPI"):
prim.GetAttribute("physxDeformableBody:selfCollision").Set(True)
return prim
Having a surface deformable available, a surface material is created and bound to the deformable as follows:
def create_surface_material(stage, path, youngs, poissons, thickness):
mat = UsdShade.Material.Define(stage, path)
prim = mat.GetPrim()
# base + surface specific schema APIs
prim.ApplyAPI("OmniPhysicsBaseMaterialAPI")
prim.GetAttribute("omniphysics:dynamicFriction").Set(0.2)
prim.GetAttribute("omniphysics:density").Set(100.0)
prim.ApplyAPI("OmniPhysicsDeformableMaterialAPI")
prim.GetAttribute("omniphysics:youngsModulus").Set(youngs)
prim.GetAttribute("omniphysics:poissonsRatio").Set(poissons)
prim.ApplyAPI("OmniPhysicsSurfaceDeformableMaterialAPI")
prim.GetAttribute("omniphysics:surfaceThickness").Set(thickness)
# Estimate bend stiffness from Young's modulus and Poisson's ratio
# surfaceThickness is incorporated in PhysX
bendStiffness = youngs/(12.0*(1.0-poissons**2))
prim.GetAttribute("omniphysics:surfaceBendStiffness").Set(bendStiffness)
# PhysX extras
prim.ApplyAPI("PhysxSurfaceDeformableMaterialAPI")
prim.GetAttribute("physxDeformableMaterial:elasticityDamping").Set(0.0)
prim.GetAttribute("physxDeformableMaterial:bendDamping").Set(0.0)
return mat
# Get stage and add ground plane
stage = omni.usd.get_context().get_stage()
planePath = "/World/GroundPlane"
breamPath = "/World/Beam"
physicsUtils.add_ground_plane(stage, planePath, "Z", 25.0, Gf.Vec3f(0.0), Gf.Vec3f(0.5))
physicsUtils.add_collider_box(stage, breamPath, Gf.Vec3f(0.1, 4, 0.5))
# Create deformable bodies
softDeformablePrim = create_surface_deformable(
stage,
"/World/DeformableBody_soft",
Gf.Vec3f(-0.5, -1.5, 0.5),
20
)
hardDeformablePrim = create_surface_deformable(
stage,
"/World/DeformableBody_hard",
Gf.Vec3f(-0.5, 0.5, 0.5),
20
)
# Create and bind materials
softMatPath = "/World/DeformableMaterial_soft"
hardMatPath = "/World/DeformableMaterial_hard"
softMat = create_surface_material(stage,
softMatPath,
youngs=5e4,
poissons=0.45,
thickness=0.01
)
hardMat = create_surface_material(stage,
hardMatPath,
youngs=2e7,
poissons=0.45,
thickness=0.01
)
bindingApi = UsdShade.MaterialBindingAPI.Apply(softDeformablePrim)
bindingApi.Bind(softMat, UsdShade.Tokens.weakerThanDescendants, "physics")
bindingApi = UsdShade.MaterialBindingAPI.Apply(hardDeformablePrim)
bindingApi.Bind(hardMat, UsdShade.Tokens.weakerThanDescendants, "physics")
Note that surfaceStretchStiffness
and surfaceShearStiffness
are not supported, and the surface bend stiffness is not currently automatically deduced from youngsModulus
, poissonsRatio
and surfaceThickness
by the current implementation. See Material Limitations for more details.
Currently multi material binding via UsdGeom.Subset
or binding specifically to the collision mesh for surface material properties is not supported.
If the material should be general purpose (i.e. used for physics and rendering), the materialPurpose
parameter of UsdShade.MaterialBindingAPI
can be omitted.
Material Friction Combine Modes#
The PhysX deformable solver only supports dynamic friction, and static friction values take no effect. It is recommended to use sufficiently high dynamic friction valued to emulate static friction-like behavior.
PhysX supports combine-mode logic for rigid materials. For rigid-deformable contacts, dynamic friction combine mode is supported as well. The friction combine mode needs to be configured on the rigid material using the frictionCombineMode
attribute of PhysxSchema.PhysxMaterialAPI
. Combine modes for deformable-deformable contacts are not supported.
Attachments and Collision Filters#
Attaching a deformable body to another deformable body, rigid body, collider or more generally to an arbitrary UsdGeom.Xformable
prim involves:
defining various low-level
OmniPhysicsAttachment
prims to specify suitable attachment points.defining
OmniPhysicsElementCollisionFilter
prims to suppress unwanted collisions.
The following code snippet shows how to instantiate a low-level vertex-vertex attachment:
from pxr import Usd, UsdGeom, UsdShade, Sdf, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils, physicsUtils
stage = omni.usd.get_context().get_stage()
planePath = "/World/GroundPlane"
anchorPath = "/World/Anchor"
deformablePath0 = "/World/DeformableBody0"
deformablePath1 = "/World/DeformableBody1"
attachmentPath0 = "/World/VtxXformAttachment"
attachmentPath1 = "/World/VtxVtxAttachment"
elementFilterPath = "/World/ElementCollisionFilter"
physicsUtils.add_ground_plane(stage, planePath, "Z", 25.0, Gf.Vec3f(0.0), Gf.Vec3f(0.5))
# Create anchor Xform
anchor = UsdGeom.Xform.Define(stage, anchorPath)
anchor.AddTranslateOp().Set(Gf.Vec3f(0.0, 0.0, 2.0))
# Create two surface deformable
dim = 20 # number of vertices per side
deformableBody0 = create_surface_deformable(
stage,
deformablePath0,
Gf.Vec3f(0.0,0.0,2.0),
dim-1
)
UsdGeom.Xformable(deformableBody0).AddScaleOp().Set(Gf.Vec3f(0.5, 0.5, 0.5))
deformableBody1 = create_surface_deformable(
stage,
deformablePath1,
Gf.Vec3f(0.50,0.0,2.0),
dim-1
)
UsdGeom.Xformable(deformableBody1).AddScaleOp().Set(Gf.Vec3f(0.5, 0.5, 0.5))
# Create a VtxXform attachment
attachment0 = stage.DefinePrim(attachmentPath0, "OmniPhysicsVtxXformAttachment")
attachment0.GetRelationship("omniphysics:src0").SetTargets([deformablePath0])
attachment0.GetRelationship("omniphysics:src1").SetTargets([anchorPath])
attachment0.GetAttribute("omniphysics:vtxIndicesSrc0").Set([0, dim*dim-dim])
localPositions = [Gf.Vec3f(0.0), Gf.Vec3f(0.0, 0.5, 0.0)]
attachment0.GetAttribute("omniphysics:localPositionsSrc1").Set(localPositions)
# Create a VtxVtx attachment
attachment1 = stage.DefinePrim(attachmentPath1, "OmniPhysicsVtxVtxAttachment")
attachment1.GetRelationship("omniphysics:src0").SetTargets([deformablePath0])
attachment1.GetRelationship("omniphysics:src1").SetTargets([deformablePath1])
attachment1.GetAttribute("omniphysics:vtxIndicesSrc0").Set([dim-1, dim*dim-1])
attachment1.GetAttribute("omniphysics:vtxIndicesSrc1").Set([0,dim*dim-dim])
When the example above is simulated, collisions between the two surface deformables occur at the vertex attachment sites. These could be filtered using a OmniPhysicsElementCollisionFilter
prim, however this is currently not supported for two surface deformable bodies. Instead collisions could be filtered wholesale by using standard prim level group or pair filtering.
For more information on how to instantiate low level attachment and collision filter primitives, see Attachments and Element Collision Filtering.
The following examples illustrate how omni.physx.scripts.deformableUtils.create_auto_deformable_attachment
can be used to create a high-level attachment based on geometric overlaps. A UsdGeom.Scope
with PhysxAutoDeformableAttachmentAPI
is created, containing all the necessary low-level prims as children.
Attaching a Volume Deformable to a Collider#
The following code snippet shows how to attach a volume deformable to a collider, by creating them such that their geometries overlap in world space:
from pxr import Usd, UsdGeom, UsdShade, Sdf, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils, physicsUtils
stage = omni.usd.get_context().get_stage()
planePath = "/World/GroundPlane"
colliderPath = "/World/Box"
deformablePath = "/World/DeformableBody"
attachmentPath = "/World/Attachment"
# Add a ground plane
physicsUtils.add_ground_plane(stage, planePath, "Z", 25.0, Gf.Vec3f(0.0), Gf.Vec3f(0.5))
# Create a rigid box collider
box_prim = physicsUtils.add_rigid_box(
stage,
colliderPath,
size = Gf.Vec3f(0.3),
position = Gf.Vec3f(0.0, 0.0, 1.0),
density = 0.0,
)
# Create a volume deformable
deformableBody = create_volume_deformable(
stage,
deformablePath,
Gf.Vec3f(-0.5,-0.5,0.0)
)
# Create an attachment between the deformable and the collider
deformableUtils.create_auto_deformable_attachment(
stage,
attachmentPath,
deformablePath,
colliderPath,
)
# Customize high-level attachment
attachment = stage.GetPrimAtPath(attachmentPath)
prefix = "physxAutoDeformableAttachment:"
attachment.GetAttribute(prefix+"deformableVertexOverlapOffset").Set(0.05)
attachment.GetAttribute(prefix+"collisionFilteringOffset").Set(0.1)
In an analogous manner, attachments can also be created between two volume deformables, or a volume deformable and a surface deformable. Attachments between two surface deformables are currently not supported.
Sometimes it’s necessary to increase the distance up to which collision filtering is active. This can be achieved on the high-level attachment attribute collisionFilteringOffset
as shown above. By default Omni PhysX chooses a value based on heuristics. For disabling collision detection completely, it is better to disable element level collision filtering entirely by setting the enableCollisionFiltering
attribute to False
and instead employ standard prim level group or pair filtering.
PhysxAutoDeformableAttachmentAPI
attributes related to generating attachment points along collider surfaces (poisson sampling) are currently not supported.
Attaching a Surface Deformable to an Xformable#
The following code snippet shows how to attach a surface deformable to an UsdGeom.Xformable
prim. By default all of the simulation mesh vertices would be attached to the coordinate frame. In order to only attach a subset of the vertices, a mask shape is used:
from pxr import Usd, UsdGeom, UsdShade, Sdf, Vt, Gf, UsdPhysics, PhysxSchema
import omni.usd
from omni.physx.scripts import deformableUtils, physicsUtils
stage = omni.usd.get_context().get_stage()
planePath = "/World/GroundPlane"
xformPath = "/World/Anchor"
deformablePath = "/World/DeformableBody"
attachmentPath = "/World/Attachment"
maskShapePath = "/World/Attachment/MaskShape"
# Add a ground plane
physicsUtils.add_ground_plane(stage, planePath, "Z", 25.0, Gf.Vec3f(0.0), Gf.Vec3f(0.5))
# Create an Xformable
xform = UsdGeom.Xform.Define(stage, xformPath)
# Create a surface deformable
deformableBody = create_surface_deformable(
stage,
deformablePath,
Gf.Vec3f(-0.5,0.0,1.0),
20
)
# Create an attachment between the deformable and the Xformable
deformableUtils.create_auto_deformable_attachment(
stage,
attachmentPath,
deformablePath,
xformPath,
20
)
# Limit the affected vertices to those inside of a mask UsdGeom.Cube shape
maskShape = UsdGeom.Cube.Define(stage, maskShapePath)
maskShape.AddTranslateOp().Set(Gf.Vec3f(0.0, 0.0, 1.0))
maskShape.AddScaleOp().Set(Gf.Vec3f(0.5, 0.02, 0.02))
attachment = stage.GetPrimAtPath(attachmentPath)
maskShapesRel = attachment.GetRelationship("physxAutoDeformableAttachment:maskShapes")
maskShapesRel.SetTargets([maskShapePath])
Note that only UsdGeom.Sphere
, UsdGeom.Box
and UsdGeom.Capsule
shapes are supported as mask shapes.
Omni PhysX Deformable Limitations#
This section describes limitations of the current Omni PhysX implementation. Limitations are present on multiple levels:
Partial implementation of the Omni Physics Deformable Schema.
Partial implementation of the PhysX Deformable Schema.
Limitations of the underlying PhysX implementation.
Collision Mesh Limitations#
While the Omni Physics Deformable Schema allows the specification of a deformable body with zero or multiple colliders, the Omni PhysX implementation is limited to deformable bodies with exactly one collider.
For surface deformable bodies, the simulation mesh needs to be used for collision detection. As opposed to volume deformable bodies, using a separate collision mesh is not supported.
Simulation Mesh and Rest Shape Limitations#
Kinematic animation of the simulation mesh points is supported for volume deformables only. The
kinematicEnabled
attribute fromOmniPhysicsDeformableBodyAPI
is ignored for surface deformables.The Omni Physics Deformable Schema allows for a rest shape topologies that diverges from simulation mesh topologies, as long as there is a one to one correspondence between rest shape elements and simulation mesh elements (triangles or tetrahedra). Omni PhysX is currently limited to accepting only identical topologies, i.e. matching triangle or tetrahedron vertex indices and matching point counts.
Manipulating the rest shape at simulation time is not supported.
Material Limitations#
Currently multi material binding via
UsdGeom.Subset
or binding specifically to the collision mesh for surface material properties (i.e. static and dynamic friction) is not supported.OmniPhysicsDeformableMaterialAPI
staticFriction
is currently not supported for both PhysX volume and surface deformables. Sufficiently highdynamicFriction
values are recommended to achieve similar behavior.OmniPhysicsSurfaceDeformableMaterialAPI
override parameters are currently not supported as advertised by the Omni Physics Deformable Schema documentation -youngsModulus
,poissonsRatio
ofOmniPhysicsDeformableMaterialAPI
are meant to define all surface stiffnesses applied to the volume given by the geometry andsurfaceThickness
by default. ThesurfaceStretchStiffness
,surfaceShearStiffness
andsurfaceBendStiffness
parameters are meant to be specific overrides of that default, if set to non-zero values. In the current implementation however:surfaceStretchStiffness
andsurfaceShearStiffness
are not supported at all for in plane elasticity.surfaceBendStiffness
is the only way to define resistance to bending. PhysX derives an edge bend stiffness that is proportional to \(\text{surfaceBendStiffness} \cdot \text{surfaceThickness}^{3}\).
PhysxSchema.PhysxMaterialAPI
frictionCombineMode
is supported for rigid-deformable contacts only, but not for deformable-deformable contacts. Applying aPhysxSchema.PhysxMaterialAPI
to a deformable material has no effect.
Attachments and Collision Filter Limitations#
The low-Level attachment type
OmniPhysicsTriTriAttachment
is not supported.Collision filtering via
OmniPhysicsElementCollisionFilter
is currently not supported between two surface deformable bodies.Attachment stiffness and damping are not supported.
Autogenerated attachments via
PhysxAutoDeformableAttachmentAPI
are limited as follows:Attachments between two surface deformables are not supported.
Rigid surface sampling is currently not supported. The attributes
enableRigidSurfaceAttachments
,rigidSurfaceSamplingDistance
are ignored.Attachment mask shapes are restricted to
UsdGeom.Sphere
,UsdGeom.Box
andUsdGeom.Capsule
prims. Other shape types are ignored.
Render Mesh Skinning Limitations#
PhysxAutoDeformableMeshSimplificationAPI
,physxDeformableBody:forceConforming
has no effect when used on surface deformables.PhysxAutoDeformableMeshSimplificationAPI
,physxDeformableBody:remeshingEnabled
should be set toFalse
when used on surface deformables, unless the source mesh (specified withPhysxAutoDeformableBodyAPI
physxDeformableBody:cookingSourceMesh
) is closed. Otherwise a double layered simulation mesh is created, which doesn’t work well with skinning.Skinning on surface deformables is expected to not work well with non-manifold simulation meshes.