Skip to content

Commit

Permalink
Merge branch 'og-develop' into fix/playback-scale
Browse files Browse the repository at this point in the history
  • Loading branch information
cremebrule committed Feb 18, 2025
2 parents 57856bd + b2d40ba commit 312b03e
Show file tree
Hide file tree
Showing 21 changed files with 891 additions and 447 deletions.
119 changes: 119 additions & 0 deletions omnigibson/examples/objects/view_cloth_configurations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
from omnigibson.utils.asset_utils import get_all_object_categories, get_all_object_category_models
from omnigibson.macros import gm

import omnigibson as og
import omnigibson.lazy as lazy
from omnigibson.utils.constants import PrimType
from omnigibson.utils.ui_utils import KeyboardEventHandler, choose_from_options
import torch as th
from bddl.object_taxonomy import ObjectTaxonomy

# Make sure object states and GPU dynamics are enabled (GPU dynamics needed for cloth)
gm.ENABLE_OBJECT_STATES = True
gm.USE_GPU_DYNAMICS = True


def main(random_selection=False, headless=False, short_exec=False):
"""
Demo showing the multiple configurations stored on each cloth object.
"""
og.log.info(f"Demo {__file__}\n " + "*" * 80 + "\n Description:\n" + main.__doc__ + "*" * 80)

# Select a category to load
available_obj_categories = get_all_object_categories()
object_taxonomy = ObjectTaxonomy()
cloth_obj_categories = [
category
for category in available_obj_categories
if object_taxonomy.get_synset_from_category(category)
and "cloth" in object_taxonomy.get_abilities(object_taxonomy.get_synset_from_category(category))
]
obj_category = choose_from_options(
options=cloth_obj_categories, name="object category", random_selection=random_selection
)

# Select a model to load
available_obj_models = get_all_object_category_models(obj_category)
obj_model = choose_from_options(
options=available_obj_models, name="object model", random_selection=random_selection
)

# Create and load this object into the simulator
obj_cfg = {
"type": "DatasetObject",
"name": "cloth",
"category": obj_category,
"model": obj_model,
"prim_type": PrimType.CLOTH,
"position": [0, 0, 0.5],
"orientation": [0, 0, 0, 1],
"load_config": {
"default_configuration": "settled",
},
}

# Create the scene config to load -- empty scene + custom cloth object
cfg = {
"scene": {
"type": "Scene",
},
"objects": [obj_cfg],
}

# Create the environment
env = og.Environment(configs=cfg)

# Grab object references
obj = env.scene.object_registry("name", "cloth")

# Set viewer camera
og.sim.viewer_camera.set_position_orientation(
position=th.tensor([0.46382895, -2.66703958, 1.22616824]),
orientation=th.tensor([0.58779174, -0.00231237, -0.00318273, 0.80900271]),
)

def reset_points_to_configuration(configuration):
print(f"Resetting to {configuration} configuration")
obj.root_link.reset_points_to_configuration(configuration)
obj.set_position_orientation(position=th.zeros(3), orientation=th.tensor([0.0, 0.0, 0.0, 1.0]))
obj.set_position_orientation(
position=th.tensor([0, 0, obj.aabb_extent[2] / 2.0 - obj.aabb_center[2]]),
orientation=th.tensor([0.0, 0.0, 0.0, 1.0]),
)

KeyboardEventHandler.initialize()
KeyboardEventHandler.add_keyboard_callback(
key=lazy.carb.input.KeyboardInput.Q,
callback_fn=lambda: reset_points_to_configuration("default"),
)
print("Press Q to reset to default configuration")

KeyboardEventHandler.add_keyboard_callback(
key=lazy.carb.input.KeyboardInput.W,
callback_fn=lambda: reset_points_to_configuration("settled"),
)
print("Press W to reset to settled configuration")

KeyboardEventHandler.add_keyboard_callback(
key=lazy.carb.input.KeyboardInput.E,
callback_fn=lambda: reset_points_to_configuration("folded"),
)
print("Press E to reset to folded configuration")

KeyboardEventHandler.add_keyboard_callback(
key=lazy.carb.input.KeyboardInput.R,
callback_fn=lambda: reset_points_to_configuration("crumpled"),
)
print("Press R to reset to crumpled configuration")

# Step through the environment
max_steps = 100 if short_exec else 10000
for i in range(max_steps):
env.step(th.empty(0))

# Always close the environment at the end
og.clear()


if __name__ == "__main__":
main()
10 changes: 5 additions & 5 deletions omnigibson/object_states/attached_to.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
# Create settings for this module
m = create_module_macros(module_path=__file__)

m.ATTACHMENT_LINK_PREFIX = "attachment"
m.ATTACHMENT_META_LINK_TYPE = "attachment"

m.DEFAULT_POSITION_THRESHOLD = 0.05 # 5cm
m.DEFAULT_ORIENTATION_THRESHOLD = th.deg2rad(th.tensor([5.0])).item() # 5 degrees
Expand Down Expand Up @@ -76,12 +76,12 @@ def remove(self):
og.sim.remove_callback_on_stop(name=f"{self.obj.name}_detach")

@classproperty
def metalink_prefix(cls):
def meta_link_type(cls):
"""
Returns:
str: Unique keyword that defines the metalink associated with this object state
str: Unique keyword that defines the meta link associated with this object state
"""
return m.ATTACHMENT_LINK_PREFIX
return m.ATTACHMENT_META_LINK_TYPE

@classmethod
def get_dependencies(cls):
Expand Down Expand Up @@ -375,7 +375,7 @@ def _disable_collision_between_child_and_parent(self, child, parent):
child_link.add_filtered_collision_pair(floor_link)

# Temporary hack to disable gravity for the attached child object if the parent is kinematic_only
# Otherwise, the parent metalink will oscillate due to the gravity force of the child.
# Otherwise, the parent meta link will oscillate due to the gravity force of the child.
if parent.kinematic_only:
child.disable_gravity()

Expand Down
6 changes: 3 additions & 3 deletions omnigibson/object_states/contains.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# Create settings for this module
m = create_module_macros(module_path=__file__)

m.CONTAINER_LINK_PREFIX = "container"
m.CONTAINER_META_LINK_TYPE = "container"
m.VISUAL_PARTICLE_OFFSET = 0.01 # Offset to visual particles' poses when checking overlaps with container volume


Expand All @@ -37,8 +37,8 @@ def __init__(self, obj):
self._compute_info = None # Intermediate computation information to store

@classproperty
def metalink_prefix(cls):
return m.CONTAINER_LINK_PREFIX
def meta_link_type(cls):
return m.CONTAINER_META_LINK_TYPE

def _get_value(self, system):
"""
Expand Down
6 changes: 3 additions & 3 deletions omnigibson/object_states/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@ def get_states_by_dependency_order(states=None):
return list(reversed(list(nx.algorithms.topological_sort(get_state_dependency_graph(states)))))


# Define all metalinks
METALINK_PREFIXES = set()
# Define all meta links
META_LINK_TYPES = set()
for state in get_states_by_dependency_order():
if issubclass(state, LinkBasedStateMixin):
try:
METALINK_PREFIXES.add(state.metalink_prefix)
META_LINK_TYPES.add(state.meta_link_type)
except NotImplementedError:
pass
12 changes: 6 additions & 6 deletions omnigibson/object_states/heat_source_or_sink.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# Create settings for this module
m = create_module_macros(module_path=__file__)

m.HEATSOURCE_LINK_PREFIX = "heatsource"
m.HEATSOURCE_META_LINK_TYPE = "heatsource"
m.HEATING_ELEMENT_MARKER_SCALE = [1.0] * 3

# TODO: Delete default values for this and make them required.
Expand Down Expand Up @@ -116,12 +116,12 @@ def is_compatible_asset(cls, prim, **kwargs):
return True, None

@classproperty
def metalink_prefix(cls):
return m.HEATSOURCE_LINK_PREFIX
def meta_link_type(cls):
return m.HEATSOURCE_META_LINK_TYPE

@classmethod
def requires_metalink(cls, **kwargs):
# No metalink required if inside
def requires_meta_link(cls, **kwargs):
# No meta link required if inside
return not kwargs.get("requires_inside", False)

@property
Expand Down Expand Up @@ -251,7 +251,7 @@ def overlap_callback(hit):
affected_objects.remove(obj)

else:
# Position is either the AABB center of the default link or the metalink position itself
# Position is either the AABB center of the default link or the meta link position itself
heat_source_pos = (
self.link.aabb_center
if self.link == self._default_link
Expand Down
49 changes: 29 additions & 20 deletions omnigibson/object_states/link_based_state_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ def is_compatible(cls, obj, **kwargs):
if not compatible:
return compatible, reason

# Check whether this state requires metalink
if not cls.requires_metalink(**kwargs):
# Check whether this state requires meta link
if not cls.requires_meta_link(**kwargs):
return True, None
metalink_prefix = cls.metalink_prefix
meta_link_type = cls.meta_link_type
for link in obj.links.values():
if metalink_prefix in link.name:
if link.is_meta_link and link.meta_link_type == meta_link_type:
return True, None

return (
False,
f"LinkBasedStateMixin {cls.__name__} requires metalink with prefix {cls.metalink_prefix} "
f"LinkBasedStateMixin {cls.__name__} requires meta link with type {cls.meta_link_type} "
f"for obj {obj.name} but none was found! To get valid compatible object models, please use "
f"omnigibson.utils.asset_utils.get_all_object_category_models_with_abilities(...)",
)
Expand All @@ -44,35 +44,43 @@ def is_compatible_asset(cls, prim, **kwargs):
if not compatible:
return compatible, reason

# Check whether this state requires metalink
if not cls.requires_metalink(**kwargs):
# Check whether this state requires meta link
if not cls.requires_meta_link(**kwargs):
return True, None
metalink_prefix = cls.metalink_prefix
meta_link_type = cls.meta_link_type
for child in prim.GetChildren():
if child.GetTypeName() == "Xform":
if metalink_prefix in child.GetName():
# With the new format, we can know for sure by checking the meta link type
if (
child.HasAttribute("ig:metaLinkType")
and child.GetAttribute("ig:metaLinkType").Get() == meta_link_type
):
return True, None

# Until the next dataset release, also accept the old format
# TODO: Remove this block after the next dataset release
if meta_link_type in child.GetName():
return True, None
return (
False,
f"LinkBasedStateMixin {cls.__name__} requires metalink with prefix {cls.metalink_prefix} "
f"LinkBasedStateMixin {cls.__name__} requires meta link with prefix {cls.meta_link_type} "
f"for asset prim {prim.GetName()} but none was found! To get valid compatible object models, "
f"please use omnigibson.utils.asset_utils.get_all_object_category_models_with_abilities(...)",
)

@classproperty
def metalink_prefix(cls):
def meta_link_type(cls):
"""
Returns:
str: Unique keyword that defines the metalink associated with this object state
str: Unique keyword that defines the meta link associated with this object state
"""
NotImplementedError()

@classmethod
def requires_metalink(cls, **kwargs):
def requires_meta_link(cls, **kwargs):
"""
Returns:
Whether an object state instantiated with constructor arguments **kwargs will require a metalink
Whether an object state instantiated with constructor arguments **kwargs will require a meta link
or not
"""
# True by default
Expand All @@ -91,7 +99,7 @@ def link(self):
def links(self):
"""
Returns:
dict: mapping from link names to links that match the metalink_prefix
dict: mapping from link names to links that match the meta_link_type
"""
return self._links

Expand All @@ -100,19 +108,20 @@ def _default_link(self):
"""
Returns:
None or RigidPrim: If supported, the fallback link associated with this link-based state if
no valid metalink is found
no valid meta link is found
"""
# No default link by default
return None

def initialize_link_mixin(self):
assert not self._initialized

# TODO: Extend logic to account for multiple instances of the same metalink? e.g: _0, _1, ... suffixes
# TODO: Extend logic to account for multiple instances of the same meta link? e.g: _0, _1, ... suffixes
for name, link in self.obj.links.items():
if self.metalink_prefix in name or (
self._default_link is not None and link.name == self._default_link.name
):
is_appropriate_meta_link = link.is_meta_link and link.meta_link_type == self.meta_link_type
# TODO: Remove support for this default meta link logic after the next dataset release
is_default_link = self._default_link is not None and link.name == self._default_link.name
if is_appropriate_meta_link or is_default_link:
self._links[name] = link
# Make sure the scale is similar if the link is not a cloth prim
if not isinstance(link, ClothPrim):
Expand Down
4 changes: 2 additions & 2 deletions omnigibson/object_states/on_fire.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ def __init__(
self.ignition_temperature = ignition_temperature

@classmethod
def requires_metalink(cls, **kwargs):
# Does not require metalink to be specified
def requires_meta_link(cls, **kwargs):
# Does not require meta link to be specified
return False

@property
Expand Down
Loading

0 comments on commit 312b03e

Please sign in to comment.