Rigid Body Physics API
Rigid body & Collision
from pxr import UsdPhysics
# check rigidbody api
prim.HasAPI(UsdPhysics.RigidBodyAPI)
prim.HasAPI(pxr.UsdPhysics.CollisionAPI)
# get api
UsdPhysics.RigidBodyAPI.Get(stage, path)
UsdPhysics.CollisionAPI.Get(stage, path)
# apply/add api
UsdPhysics.RigidBodyAPI.Apply(stage, path)
UsdPhysics.CollisionAPI.Apply(stage, path)
Set up GPU for physics
By default isaac sim physics engine when running standalone will use CPU solver; however, particle physics is only available in GPU mode. TO enable GPU, we need to following lines of code:
from omni.physx import acquire_physx_interface
physx = acquire_physx_interface()
physx.overwrite_gpu_setting(1) # 1 means using GPU
set up physics call_back
self._world.add_physics_callback("frankabot_step", callback_fn=self._on_sim_step)
Make sure to remove it afterwards
self._world.remove_physics_callback("frankabot_step")
Liquid simulation
There are two ways to simulate liquid
- Generate liquid on the fly (suitable for faucet-like applications).
- Pre-generate liquid and let physics handle the final locations of the liquid pool.
For type-1: the pipeline is:
1.1 generate positions for each batch of particles.
1.2 create point instancer and specify its properties.
1.3 create a sphere to temporarily hold the liquid (make it invisible).
1.4 after certain time-steps, we crate one batch. We can do that by creating a callback for on_physics_step
Notice the activeIndices attribute, I suspect, we can use this to control what particle to simulate. More about particle simulation are here: https://graphics.pixar.com/usd/release/api/class_usd_geom_point_instancer.html
def set_up():
addPhysxParticleSystem(
stage,
particleSystemPath,
contactOffset,
restOffset,
particleContactOffset,
solidRestOffset,
fluidRestOffset,
4,
1,
Gf.Vec3f(0, 0, 0),
scenePath
)
particleSystem = stage.GetPrimAtPath(particleSystemPath)
# particle system settings
particleSystem.GetAttribute("cohesion").Set(0.002)
particleSystem.GetAttribute("smoothing").Set(0.8)
particleSystem.GetAttribute("anisotropyScale").Set(1.0)
particleSystem.GetAttribute("anisotropyMin").Set(0.2)
particleSystem.GetAttribute("anisotropyMax").Set(2.0)
particleSystem.GetAttribute("viscosity").Set(0.0091)
particleSystem.GetAttribute("surfaceTension").Set(0.0074)
particleSystem.GetAttribute("particleFriction").Set(0.1)
particleSystem.CreateAttribute("maxParticleNeighborhood", Sdf.ValueTypeNames.Int, True).Set(64)
particleSystem.GetAttribute("maxParticles").Set(20000)
# apply isoSurface params
particleSystem.CreateAttribute("enableIsosurface", Sdf.ValueTypeNames.Bool, True).Set(True)
particleSystem.CreateAttribute("maxIsosurfaceVertices", Sdf.ValueTypeNames.Int, True).Set(1024 * 1024)
particleSystem.CreateAttribute("maxIsosurfaceTriangles", Sdf.ValueTypeNames.Int, True).Set(2 * 1024 * 1024)
particleSystem.CreateAttribute("maxNumIsosurfaceSubgrids", Sdf.ValueTypeNames.Int, True).Set(1024 * 4)
particleSystem.CreateAttribute("isosurfaceGridSpacing", Sdf.ValueTypeNames.Float, True).Set(0.2)
filterSmooth = 1
filtering = 0
passIndex = 0
filtering = setGridFilteringPass(filtering, passIndex, filterSmooth)
passIndex = passIndex + 1
filtering = setGridFilteringPass(filtering, passIndex, filterSmooth)
passIndex = passIndex + 1
particleSystem.CreateAttribute("isosurfaceKernelRadius", Sdf.ValueTypeNames.Float, True).Set(0.5)
particleSystem.CreateAttribute("isosurfaceLevel", Sdf.ValueTypeNames.Float, True).Set(-0.3)
particleSystem.CreateAttribute("isosurfaceGridFilteringFlags", Sdf.ValueTypeNames.Int, True).Set(filtering)
particleSystem.CreateAttribute(
"isosurfaceGridSmoothingRadiusRelativeToCellSize", Sdf.ValueTypeNames.Float, True
).Set(0.3)
particleSystem.CreateAttribute("isosurfaceEnableAnisotropy", Sdf.ValueTypeNames.Bool, True).Set(False)
particleSystem.CreateAttribute("isosurfaceAnisotropyMin", Sdf.ValueTypeNames.Float, True).Set(0.1)
particleSystem.CreateAttribute("isosurfaceAnisotropyMax", Sdf.ValueTypeNames.Float, True).Set(2.0)
particleSystem.CreateAttribute("isosurfaceAnisotropyRadius", Sdf.ValueTypeNames.Float, True).Set(0.5)
particleSystem.CreateAttribute("numIsosurfaceMeshSmoothingPasses", Sdf.ValueTypeNames.Int, True).Set(5)
particleSystem.CreateAttribute("numIsosurfaceMeshNormalSmoothingPasses", Sdf.ValueTypeNames.Int, True).Set(5)
particleSystem.CreateAttribute("isosurfaceDoNotCastShadows", Sdf.ValueTypeNames.Bool, True).Set(True)
stage.SetInterpolationType(Usd.InterpolationTypeHeld)
def create_ball():
# create sphere on points
points = self.point_sphere(50, 1)
# basePos = Gf.Vec3f(11.0, 12.0, 35.0) + pos
basePos = pos
positions = [x + basePos for x in points]
radius = 1
# particleSpacing = 2.0 * radius * 0.6
particleSpacing = 4.0 * radius * 0.6
positions_list = positions
velocities_list = [Gf.Vec3f(0.0, 0.0, 0.0)] * len(positions)
protoIndices_list = [0] * len(positions)
protoIndices = Vt.IntArray(protoIndices_list)
positions = Vt.Vec3fArray(positions_list)
velocities = Vt.Vec3fArray(velocities_list)
particleInstanceStr = "/particlesInstance" + str(self.it)
particleInstancePath = Sdf.Path(particleInstanceStr)
# Create point instancer
pointInstancer = UsdGeom.PointInstancer.Define(stage, particleInstancePath)
prototypeRel = pointInstancer.GetPrototypesRel()
# Create particle instance prototypes
particlePrototype = PhysxParticleInstancePrototype()
particlePrototype.selfCollision = True
particlePrototype.fluid = True
particlePrototype.collisionGroup = 0
particlePrototype.mass = 0.001
prototypePath = particleInstancePath.pathString + "/particlePrototype"
sphere = UsdGeom.Sphere.Define(stage, Sdf.Path(prototypePath))
sphere.GetRadiusAttr().Set(particleSpacing)
spherePrim = sphere.GetPrim()
spherePrim.GetAttribute('visibility').Set('invisible')
spherePrim.CreateAttribute("enableAnisotropy", Sdf.ValueTypeNames.Bool, True).Set(True)
particleInstanceApi = PhysxSchema.PhysxParticleAPI.Apply(spherePrim)
particleInstanceApi.CreateSelfCollisionAttr().Set(particlePrototype.selfCollision)
particleInstanceApi.CreateFluidAttr().Set(particlePrototype.fluid)
particleInstanceApi.CreateParticleGroupAttr().Set(particlePrototype.collisionGroup)
particleInstanceApi.CreateMassAttr().Set(particlePrototype.mass)
# Reference simulation owner using PhysxPhysicsAPI
physicsApi = PhysxSchema.PhysxPhysicsAPI.Apply(spherePrim)
physicsApi.CreateSimulationOwnerRel().SetTargets([self.particleSystemPath])
# add prototype references to point instancer
prototypeRel.AddTarget(Sdf.Path(prototypePath))
# Set active particle indices
activeIndices = []
for i in range(len(positions)):
activeIndices.append(protoIndices[i])
orientations = [Gf.Quath(1.0, Gf.Vec3h(0.0, 0.0, 0.0))] * len(positions)
angular_velocities = [Gf.Vec3f(0.0, 0.0, 0.0)] * len(positions)
pointInstancer.GetProtoIndicesAttr().Set(activeIndices)
pointInstancer.GetPositionsAttr().Set(positions)
pointInstancer.GetOrientationsAttr().Set(orientations)
pointInstancer.GetVelocitiesAttr().Set(velocities)
pointInstancer.GetAngularVelocitiesAttr().Set(angular_velocities)
For Type-2, We just generate the entire shape in advance.
Set up physics materials (this is important, we need friction to pick up objects)
def _setup_physics_material(self, path):
# def _setup_physics_material(self, path: Sdf.Path):
from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf
_material_static_friction = 1.0
_material_dynamic_friction = 1.0
_material_restitution = 0.0
_physicsMaterialPath = None
if _physicsMaterialPath is None:
_physicsMaterialPath = self._stage.GetDefaultPrim().GetPath().AppendChild("physicsMaterial")
UsdShade.Material.Define(self._stage, _physicsMaterialPath)
material = UsdPhysics.MaterialAPI.Apply(self._stage.GetPrimAtPath(_physicsMaterialPath))
material.CreateStaticFrictionAttr().Set(_material_static_friction)
material.CreateDynamicFrictionAttr().Set(_material_dynamic_friction)
material.CreateRestitutionAttr().Set(_material_restitution)
collisionAPI = UsdPhysics.CollisionAPI.Get(self._stage, path)
prim = self._stage.GetPrimAtPath(path)
if not collisionAPI:
collisionAPI = UsdPhysics.CollisionAPI.Apply(prim)
# apply material
physicsUtils.add_physics_material_to_prim(self._stage, prim, _physicsMaterialPath)
Set mass:
def _apply_mass(self, mesh: UsdGeom.Mesh, mass: float):
massAPI = UsdPhysics.MassAPI.Apply(mesh.GetPrim())
massAPI.GetMassAttr().Set(mass)
Set/Get Gravity value
# Assume _my_world is of type World
self._my_world ._physics_context.get_gravity()
meters_per_unit = get_stage_units()
self._my_world ._physics_context.set_gravity(value=-9.81 / meters_per_unit)
Set up prim collision type
from omni.physx.scripts import utils
utils.setCollider(collision_prim, approximationShape="convexDecomposition")
Setup physics materials
we can only pick up stuff if it has frictions.
def _setup_physics_material(self, path: Sdf.Path):
from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf
if self._physicsMaterialPath is None:
self._physicsMaterialPath = self._stage.GetDefaultPrim().GetPath().AppendChild("physicsMaterial")
UsdShade.Material.Define(self._stage, self._physicsMaterialPath)
material = UsdPhysics.MaterialAPI.Apply(self._stage.GetPrimAtPath(self._physicsMaterialPath))
material.CreateStaticFrictionAttr().Set(self._material_static_friction)
material.CreateDynamicFrictionAttr().Set(self._material_dynamic_friction)
material.CreateRestitutionAttr().Set(self._material_restitution)
collisionAPI = UsdPhysics.CollisionAPI.Get(self._stage, path)
prim = self._stage.GetPrimAtPath(path)
if not collisionAPI:
collisionAPI = UsdPhysics.CollisionAPI.Apply(prim)
# apply material
physicsUtils.add_physics_material_to_prim(self._stage, prim, self._physicsMaterialPath)
Set up stiffness and damping
from pxr import UsdPhysics
joint = UsdPhysics.DriveAPI.Get(joint_prim, "angular")
joint.CreateDampingAttr(1e3)
joint.CreateStiffnessAttr(1e3)
Get prim position/rotation/scale
print(prim.GetAttribute("xformOp:orient").Get())
print(prim.GetAttribute("xformOp:translate").Get())
print(prim.GetAttribute("xformOp:scale").Get())
Joint Setup
from pxr import UsdPhysics
# type == "SLIDER"
joint = UsdPhysics.PrismaticJoint.Define(stage, path)
# type == "REVOLUTE"
joint = UsdPhysics.RevoluteJoint.Define(self.assembly_stage, p)
Get Joint
UsdPhysics.PrismaticJoint.Get(stage, path)
Property Setup
joint.CreateAxisAttr(mate.axis)
# print(f.limits)
if mate.limits[0] is not None:
joint.CreateLowerLimitAttr(mate.limits[0])
if mate.limits[1] is not None:
joint.CreateUpperLimitAttr(mate.limits[1])
joint.CreateBody0Rel().SetTargets([base_path])
joint.CreateBody1Rel().SetTargets([prim_path])
joint.CreateLocalPos0Attr().Set((joint_global_pose * body_0_global.GetInverse()).ExtractTranslation())
joint.CreateLocalRot0Attr().Set(
Gf.Quatf((joint_global_pose * body_0_global.GetInverse()).ExtractRotation().GetQuat())
)
joint.CreateLocalPos1Attr().Set((joint_global_pose * body_1_global.GetInverse()).ExtractTranslation())
joint.CreateLocalRot1Attr().Set(
Gf.Quatf((joint_global_pose * body_1_global.GetInverse()).ExtractRotation().GetQuat())
)