Skip to content

Commit 25d30d5

Browse files
authored
Merge pull request #1973 from StanfordVL/plain-geom-prim
Convert visual and collision geom prims to plain geom prim
2 parents 41d2ef0 + f017a16 commit 25d30d5

File tree

17 files changed

+308
-336
lines changed

17 files changed

+308
-336
lines changed

OmniGibson/omnigibson/object_states/particle_modifier.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from omnigibson.object_states.saturated import ModifiedParticles, Saturated
1818
from omnigibson.object_states.toggle import ToggledOn
1919
from omnigibson.object_states.update_state_mixin import UpdateStateMixin
20-
from omnigibson.prims.geom_prim import VisualGeomPrim
20+
from omnigibson.prims.geom_prim import GeomPrim
2121
from omnigibson.prims.prim_base import BasePrim
2222
from omnigibson.systems import MicroParticleSystem
2323
from omnigibson.systems.system_base import PhysicalParticleSystem
@@ -158,7 +158,7 @@ def create_projection_visualization(
158158
prototype_path = "/".join(sprite_path.split("/")[:-1]) + "/prototype"
159159
create_primitive_mesh(prototype_path, primitive_type="Sphere")
160160
relative_prototype_path = absolute_prim_path_to_scene_relative(scene, prototype_path)
161-
prototype = VisualGeomPrim(relative_prim_path=relative_prototype_path, name=f"{projection_name}_prototype")
161+
prototype = GeomPrim(relative_prim_path=relative_prototype_path, name=f"{projection_name}_prototype")
162162
prototype.load(scene)
163163
prototype.initialize()
164164
# Set the scale (native scaling --> radius 0.5) and possibly update the material
@@ -403,7 +403,7 @@ def overlap_callback(hit):
403403
)
404404

405405
# Create the visual geom instance referencing the generated mesh prim, and then hide it
406-
self.projection_mesh = VisualGeomPrim(
406+
self.projection_mesh = GeomPrim(
407407
relative_prim_path=absolute_prim_path_to_scene_relative(self.obj.scene, mesh_prim_path),
408408
name=f"{name_prefix}_projection_mesh",
409409
)
@@ -475,7 +475,7 @@ def check_overlap():
475475
for shape_attr, default_val in shape_defaults.items():
476476
if shape_attr in property_names:
477477
indicator_mesh_prim.GetAttribute(shape_attr).Set(default_val)
478-
indicator_mesh = VisualGeomPrim(
478+
indicator_mesh = GeomPrim(
479479
relative_prim_path=absolute_prim_path_to_scene_relative(self.obj.scene, indicator_mesh_path),
480480
name=f"{name_prefix}_projection_mesh_direction_indicator",
481481
)
@@ -1128,7 +1128,7 @@ def _initialize(self):
11281128
relative_projection_source_path = absolute_prim_path_to_scene_relative(
11291129
self.obj.scene, projection_visualization_path
11301130
)
1131-
self.projection_source_sphere = VisualGeomPrim(
1131+
self.projection_source_sphere = GeomPrim(
11321132
relative_prim_path=relative_projection_source_path, name=f"{name_prefix}_projection_source_sphere"
11331133
)
11341134
self.projection_source_sphere.load(self.obj.scene)

OmniGibson/omnigibson/object_states/toggle.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from omnigibson.object_states.object_state_base import AbsoluteObjectState, BooleanStateMixin
88
from omnigibson.object_states.open_state import Open
99
from omnigibson.object_states.update_state_mixin import GlobalUpdateStateMixin, UpdateStateMixin
10-
from omnigibson.prims.geom_prim import VisualGeomPrim
10+
from omnigibson.prims.geom_prim import GeomPrim
1111
from omnigibson.utils.constants import PrimType
1212
from omnigibson.utils.numpy_utils import vtarray_to_torch
1313
from omnigibson.utils.python_utils import classproperty
@@ -165,9 +165,7 @@ def _initialize(self):
165165

166166
# Create the visual geom instance referencing the generated mesh prim
167167
relative_prim_path = absolute_prim_path_to_scene_relative(self.obj.scene, mesh_prim_path)
168-
self.visual_marker = VisualGeomPrim(
169-
relative_prim_path=relative_prim_path, name=f"{self.obj.name}_visual_marker"
170-
)
168+
self.visual_marker = GeomPrim(relative_prim_path=relative_prim_path, name=f"{self.obj.name}_visual_marker")
171169
self.visual_marker.load(self.obj.scene)
172170
self.visual_marker.scale = self.scale
173171
self.visual_marker.initialize()

OmniGibson/omnigibson/objects/primitive_object.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def _post_load(self):
171171
col_approximation = "boundingCube"
172172
else:
173173
col_approximation = "convexHull"
174-
self.root_link.collision_meshes["collisions"].set_collision_approximation(col_approximation)
174+
self.root_link.set_collision_approximation(col_approximation)
175175

176176
def _initialize(self):
177177
# Run super first

OmniGibson/omnigibson/objects/stateful_object.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from omnigibson.object_states.object_state_base import REGISTERED_OBJECT_STATES
2525
from omnigibson.object_states.on_fire import OnFire
2626
from omnigibson.objects.object_base import BaseObject
27-
from omnigibson.prims.geom_prim import VisualGeomPrim
27+
from omnigibson.prims.geom_prim import GeomPrim
2828
from omnigibson.utils.constants import EmitterType, PrimType
2929
from omnigibson.utils.python_utils import classproperty, extract_class_init_kwargs_from_dict
3030
from omnigibson.utils.ui_utils import create_module_logger
@@ -348,7 +348,7 @@ def _create_emitter_apis(self, emitter_type):
348348
dummy_mesh_path = f"{link.prim_path}/emitter"
349349
lazy.pxr.UsdGeom.Sphere.Define(og.sim.stage, dummy_mesh_path)
350350
relative_dummy_mesh_path = absolute_prim_path_to_scene_relative(self._scene, dummy_mesh_path)
351-
mesh = VisualGeomPrim(relative_prim_path=relative_dummy_mesh_path, name=f"{self.name}_emitter")
351+
mesh = GeomPrim(relative_prim_path=relative_dummy_mesh_path, name=f"{self.name}_emitter")
352352
mesh.load(self._scene)
353353
mesh.visible = False
354354

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from omnigibson.prims.cloth_prim import ClothPrim
22
from omnigibson.prims.entity_prim import EntityPrim
3-
from omnigibson.prims.geom_prim import CollisionGeomPrim, CollisionVisualGeomPrim, GeomPrim, VisualGeomPrim
3+
from omnigibson.prims.geom_prim import GeomPrim
44
from omnigibson.prims.joint_prim import JointPrim
55
from omnigibson.prims.prim_base import BasePrim
66
from omnigibson.prims.rigid_prim import RigidPrim
@@ -11,14 +11,11 @@
1111
__all__ = [
1212
"BasePrim",
1313
"ClothPrim",
14-
"CollisionGeomPrim",
15-
"CollisionVisualGeomPrim",
1614
"EntityPrim",
1715
"GeomPrim",
1816
"JointPrim",
1917
"RigidPrim",
2018
"RigidDynamicPrim",
2119
"RigidKinematicPrim",
22-
"VisualGeomPrim",
2320
"XFormPrim",
2421
]

OmniGibson/omnigibson/prims/geom_prim.py

Lines changed: 6 additions & 237 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from scipy.spatial import Delaunay
44
import torch as th
55

6-
import omnigibson as og
76
import omnigibson.lazy as lazy
87
from omnigibson.utils.geometry_utils import (
98
check_points_in_cone,
@@ -12,10 +11,8 @@
1211
check_points_in_sphere,
1312
)
1413
import omnigibson.utils.transform_utils as T
15-
from omnigibson.macros import gm
1614
from omnigibson.prims.xform_prim import XFormPrim
1715
from omnigibson.utils.numpy_utils import vtarray_to_torch
18-
from omnigibson.utils.python_utils import assert_valid_key
1916
from omnigibson.utils.ui_utils import create_module_logger
2017
from omnigibson.utils.usd_utils import mesh_prim_shape_to_trimesh_mesh
2118

@@ -27,7 +24,11 @@ class GeomPrim(XFormPrim):
2724
"""
2825
Provides high level functions to deal with a geom prim and its attributes / properties.
2926
If there is an geom prim present at the path, it will use it. By default, a geom prim cannot be directly
30-
created from scratch.at
27+
created from scratch.
28+
29+
Geom prims are not inherently distinguished as collision or visual. Instead, at the link level
30+
(RigidPrim), they are tracked separately based on whether they appear with a CollisionAPI or as a child of one.
31+
Collision-related APIs and methods live on RigidPrim and operate on all collision meshes of a link.
3132
3233
Args:
3334
relative_prim_path (str): Scene-local prim path of the Prim to encapsulate or create.
@@ -43,6 +44,7 @@ def __init__(
4344
load_config=None,
4445
):
4546
self._mesh_type = None
47+
self._applied_physics_material = None
4648

4749
# Run super method
4850
super().__init__(
@@ -295,202 +297,6 @@ def extent(self):
295297
points = self.points
296298
return th.max(points, dim=0).values - th.min(points, dim=0).values
297299

298-
299-
class CollisionGeomPrim(GeomPrim):
300-
def __init__(
301-
self,
302-
relative_prim_path,
303-
name,
304-
load_config=None,
305-
):
306-
# Store values created at runtime
307-
self._collision_api = None
308-
self._mesh_collision_api = None
309-
self._physx_collision_api = None
310-
self._applied_physics_material = None
311-
312-
# Run super method
313-
super().__init__(
314-
relative_prim_path=relative_prim_path,
315-
name=name,
316-
load_config=load_config,
317-
)
318-
319-
def _post_load(self):
320-
# run super first
321-
super()._post_load()
322-
323-
# By default, CollisionGeomPrim does not show up in the rendering.
324-
self.purpose = "guide"
325-
326-
# Create API references
327-
self._collision_api = (
328-
lazy.pxr.UsdPhysics.CollisionAPI(self._prim)
329-
if self._prim.HasAPI(lazy.pxr.UsdPhysics.CollisionAPI)
330-
else lazy.pxr.UsdPhysics.CollisionAPI.Apply(self._prim)
331-
)
332-
self._physx_collision_api = (
333-
lazy.pxr.PhysxSchema.PhysxCollisionAPI(self._prim)
334-
if self._prim.HasAPI(lazy.pxr.PhysxSchema.PhysxCollisionAPI)
335-
else lazy.pxr.PhysxSchema.PhysxCollisionAPI.Apply(self._prim)
336-
)
337-
338-
# Optionally add mesh collision API if this is a mesh
339-
if self._prim.GetPrimTypeInfo().GetTypeName() == "Mesh":
340-
self._mesh_collision_api = (
341-
lazy.pxr.UsdPhysics.MeshCollisionAPI(self._prim)
342-
if self._prim.HasAPI(lazy.pxr.UsdPhysics.MeshCollisionAPI)
343-
else lazy.pxr.UsdPhysics.MeshCollisionAPI.Apply(self._prim)
344-
)
345-
# Set the approximation to be convex hull by default
346-
self.set_collision_approximation(approximation_type="convexHull")
347-
348-
self.collision_enabled = not gm.VISUAL_ONLY
349-
350-
@property
351-
def collision_enabled(self):
352-
"""
353-
Returns:
354-
bool: Whether collisions are enabled for this collision mesh
355-
"""
356-
return self.get_attribute("physics:collisionEnabled")
357-
358-
@collision_enabled.setter
359-
def collision_enabled(self, enabled):
360-
"""
361-
Sets whether collisions are enabled for this mesh
362-
363-
Args:
364-
enabled (bool): Whether collisions should be enabled for this mesh
365-
"""
366-
# Currently, trying to toggle while simulator is playing while using GPU dynamics results in a crash, so we
367-
# assert that the sim is stopped here
368-
if self._initialized and gm.USE_GPU_DYNAMICS:
369-
assert og.sim.is_stopped(), "Cannot toggle collisions while using GPU dynamics unless simulator is stopped!"
370-
self.set_attribute("physics:collisionEnabled", enabled)
371-
372-
# TODO: Maybe this should all be added to RigidPrim instead?
373-
def set_contact_offset(self, offset):
374-
"""
375-
Args:
376-
offset (float): Contact offset of a collision shape. Allowed range [maximum(0, rest_offset), 0].
377-
Default value is -inf, means default is picked by simulation based on the shape extent.
378-
"""
379-
self._physx_collision_api.GetContactOffsetAttr().Set(offset)
380-
return
381-
382-
def get_contact_offset(self):
383-
"""
384-
Returns:
385-
float: contact offset of the collision shape.
386-
"""
387-
return self._physx_collision_api.GetContactOffsetAttr().Get()
388-
389-
def set_rest_offset(self, offset):
390-
"""
391-
Args:
392-
offset (float): Rest offset of a collision shape. Allowed range [-max_float, contact_offset.
393-
Default value is -inf, means default is picked by simulatiion. For rigid bodies its zero.
394-
"""
395-
self._physx_collision_api.GetRestOffsetAttr().Set(offset)
396-
return
397-
398-
def get_rest_offset(self):
399-
"""
400-
Returns:
401-
float: rest offset of the collision shape.
402-
"""
403-
return self._physx_collision_api.GetRestOffsetAttr().Get()
404-
405-
def set_torsional_patch_radius(self, radius):
406-
"""
407-
Args:
408-
radius (float): radius of the contact patch used to apply torsional friction. Allowed range [0, max_float].
409-
"""
410-
self._physx_collision_api.GetTorsionalPatchRadiusAttr().Set(radius)
411-
return
412-
413-
def get_torsional_patch_radius(self):
414-
"""
415-
Returns:
416-
float: radius of the contact patch used to apply torsional friction. Allowed range [0, max_float].
417-
"""
418-
return self._physx_collision_api.GetTorsionalPatchRadiusAttr().Get()
419-
420-
def set_min_torsional_patch_radius(self, radius):
421-
"""
422-
Args:
423-
radius (float): minimum radius of the contact patch used to apply torsional friction. Allowed range [0, max_float].
424-
"""
425-
self._physx_collision_api.GetMinTorsionalPatchRadiusAttr().Set(radius)
426-
return
427-
428-
def get_min_torsional_patch_radius(self):
429-
"""
430-
Returns:
431-
float: minimum radius of the contact patch used to apply torsional friction. Allowed range [0, max_float].
432-
"""
433-
return self._physx_collision_api.GetMinTorsionalPatchRadiusAttr().Get()
434-
435-
def set_collision_approximation(self, approximation_type):
436-
"""
437-
Args:
438-
approximation_type (str): approximation used for collision.
439-
Can be one of: {"none", "convexHull", "convexDecomposition", "meshSimplification", "sdf",
440-
"boundingSphere", "boundingCube"}
441-
If None, the approximation will use the underlying triangle mesh.
442-
"""
443-
assert self._mesh_collision_api is not None, "collision_approximation only applicable for meshes!"
444-
assert_valid_key(
445-
key=approximation_type,
446-
valid_keys={
447-
"none",
448-
"convexHull",
449-
"convexDecomposition",
450-
"meshSimplification",
451-
"sdf",
452-
"boundingSphere",
453-
"boundingCube",
454-
},
455-
name="collision approximation type",
456-
)
457-
458-
# Make sure to add the appropriate API if we're setting certain values
459-
if approximation_type == "convexHull" and not self._prim.HasAPI(
460-
lazy.pxr.PhysxSchema.PhysxConvexHullCollisionAPI
461-
):
462-
lazy.pxr.PhysxSchema.PhysxConvexHullCollisionAPI.Apply(self._prim)
463-
elif approximation_type == "convexDecomposition" and not self._prim.HasAPI(
464-
lazy.pxr.PhysxSchema.PhysxConvexDecompositionCollisionAPI
465-
):
466-
lazy.pxr.PhysxSchema.PhysxConvexDecompositionCollisionAPI.Apply(self._prim)
467-
elif approximation_type == "meshSimplification" and not self._prim.HasAPI(
468-
lazy.pxr.PhysxSchema.PhysxTriangleMeshSimplificationCollisionAPI
469-
):
470-
lazy.pxr.PhysxSchema.PhysxTriangleMeshSimplificationCollisionAPI.Apply(self._prim)
471-
elif approximation_type == "sdf" and not self._prim.HasAPI(lazy.pxr.PhysxSchema.PhysxSDFMeshCollisionAPI):
472-
lazy.pxr.PhysxSchema.PhysxSDFMeshCollisionAPI.Apply(self._prim)
473-
elif approximation_type == "none" and not self._prim.HasAPI(lazy.pxr.PhysxSchema.PhysxTriangleMeshCollisionAPI):
474-
lazy.pxr.PhysxSchema.PhysxTriangleMeshCollisionAPI.Apply(self._prim)
475-
476-
if approximation_type == "convexHull":
477-
pch_api = lazy.pxr.PhysxSchema.PhysxConvexHullCollisionAPI(self._prim)
478-
# Also make sure the maximum vertex count is 60 (max number compatible with GPU)
479-
# https://docs.omniverse.nvidia.com/app_create/prod_extensions/ext_physics/rigid-bodies.html#collision-settings
480-
if pch_api.GetHullVertexLimitAttr().Get() is None:
481-
pch_api.CreateHullVertexLimitAttr()
482-
pch_api.GetHullVertexLimitAttr().Set(60)
483-
484-
self._mesh_collision_api.GetApproximationAttr().Set(approximation_type)
485-
486-
def get_collision_approximation(self):
487-
"""
488-
Returns:
489-
str: approximation used for collision, could be "none", "convexHull" or "convexDecomposition"
490-
"""
491-
assert self._mesh_collision_api is not None, "collision_approximation only applicable for meshes!"
492-
return self._mesh_collision_api.GetApproximationAttr().Get()
493-
494300
def apply_physics_material(self, physics_material, weaker_than_descendants=False):
495301
"""
496302
Used to apply physics material to the held prim and optionally its descendants.
@@ -534,40 +340,3 @@ def get_applied_physics_material(self):
534340
else:
535341
self._applied_physics_material = lazy.isaacsim.core.api.materials.PhysicsMaterial(prim_path=path)
536342
return self._applied_physics_material
537-
538-
539-
class VisualGeomPrim(GeomPrim):
540-
def _post_load(self):
541-
# run super first
542-
super()._post_load()
543-
544-
# TODO: tmp fix for visible metalinks
545-
if "meta" in self.name:
546-
if "togglebutton" in self.name:
547-
# Make sure togglebutton mesh is visible
548-
self.purpose = "default"
549-
elif any(
550-
[
551-
metalink in self.name
552-
for metalink in [
553-
"particlesource",
554-
"particlesink",
555-
"fillable",
556-
"particleremover",
557-
"particleapplier",
558-
"slicer",
559-
]
560-
]
561-
):
562-
# Make sure particlesource, particlesink and fillable meshes are not visible
563-
self.purpose = "guide"
564-
565-
566-
class CollisionVisualGeomPrim(CollisionGeomPrim, VisualGeomPrim):
567-
def _post_load(self):
568-
# run super first
569-
super()._post_load()
570-
571-
# The purpose should be default, not guide as set by CollisionGeomPrim
572-
# this is to make sure the geom is visualized, even though it's also collidable
573-
self.purpose = "default"

0 commit comments

Comments
 (0)