Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions genesis/engine/entities/base_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(
self._solver = solver
self._material = material
self._morph = morph
self._surface = surface
self._surface_override = surface
self._sim = scene.sim

# Set entity name (auto-generate if not provided)
Expand Down Expand Up @@ -76,8 +76,29 @@ def solver(self):
return self._solver

@property
def surface(self):
return self._surface
def surface_override(self):
"""The user-supplied surface, un-processed.

Subclasses that have a meaningful entity-level resolved Surface (e.g.
ParticleEntity, ToolEntity) expose it separately as ``entity.surface``.
Subclasses with per-geom or per-render-mesh surfaces (RigidEntity, FEMEntity)
only expose this raw form — consumers must read per-geom / per-rmesh surfaces.
"""
return self._surface_override

@property
def vis_mode(self) -> str:
"""Entity-level visualization mode (visual / collision / particle / sdf / recon).

Thin façade over `surface_override.vis_mode` — `scene.add_entity` writes the
material-validated vis_mode onto the surface, and the viewer overlay /
interactive scene mutate it at runtime via the setter below.
"""
return self._surface_override.vis_mode

@vis_mode.setter
def vis_mode(self, value: str) -> None:
self._surface_override.vis_mode = value

@property
def morph(self):
Expand Down
3 changes: 2 additions & 1 deletion genesis/engine/entities/fem_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ def __init__(
self._s_start = s_start # offset for surface triangles
self._step_global_added = None

self._surface.update_texture()
self._surface = self.surface_override.model_copy()
self._surface.finalize_texture()

self.sample()

Expand Down
19 changes: 9 additions & 10 deletions genesis/engine/entities/particle_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,21 @@ def __init__(
self._vvert_start = -1
self._vface_start = -1

# visual mesh
# visual mesh — resolve surface_override into a per-entity finalized _surface.
if isinstance(self._morph, gs.options.morphs.MeshSet):
self._vmesh = gs.Mesh.from_morph_surface(self.morph, self.surface)
self._vmesh = gs.Mesh.from_morph_surface(self.morph, self.surface_override)
self._surface = self._vmesh[0].surface

elif isinstance(self._morph, (gs.options.morphs.Primitive, gs.options.morphs.Mesh)):
self._vmesh = gs.Mesh.from_morph_surface(self.morph, self.surface)
if isinstance(self._vmesh, list):
if len(self._vmesh) > 1:
gs.raise_exception("Mesh file with multiple sub-meshes are not supported.")
else:
self._vmesh = self._vmesh[0]
vmeshes = gs.Mesh.from_morph_surface(self.morph, self.surface_override)
if len(vmeshes) > 1:
gs.raise_exception("Mesh file with multiple sub-meshes are not supported.")
self._vmesh = vmeshes[0]
self._surface = self._vmesh.surface

else:
surface.update_texture()
self._surface = self.surface_override.model_copy()
self._surface.finalize_texture()
self._vmesh = None

self.sample()
Expand Down Expand Up @@ -312,7 +311,7 @@ def sample(self):
faces=combined_faces,
vertex_normals=combined_vert_normals,
)
self._vmesh = mu.trimesh_to_mesh(combined_tmesh, 1, self._surface)
self._vmesh = mu.trimesh_to_mesh(combined_tmesh, 1, self.surface_override)

if self._need_skinning:
self._vverts = np.asarray(self._vmesh.verts, dtype=gs.np_float)
Expand Down
14 changes: 7 additions & 7 deletions genesis/engine/entities/rigid_entity/rigid_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,13 @@ def init_ckpt(self):
def _load_morph(self, morph: Morph):
"""Load a single morph into the entity."""
if isinstance(morph, gs.morphs.Mesh):
self._load_mesh(morph, self._surface)
self._load_mesh(morph, self._surface_override)
elif isinstance(morph, (gs.morphs.MJCF, gs.morphs.URDF, gs.morphs.Drone, gs.morphs.USD)):
self._load_scene(morph, self._surface)
self._load_scene(morph, self._surface_override)
elif isinstance(morph, gs.morphs.Primitive):
self._load_primitive(morph, self._surface)
self._load_primitive(morph, self._surface_override)
elif isinstance(morph, gs.morphs.Terrain):
self._load_terrain(morph, self._surface)
self._load_terrain(morph, self._surface_override)
else:
gs.raise_exception(f"Unsupported morph: {morph}.")

Expand Down Expand Up @@ -164,7 +164,7 @@ def _load_heterogeneous_morphs(self):
if isinstance(morph, (gs.morphs.URDF, gs.morphs.MJCF)):
# Parse variant scene file
morph._enable_mujoco_compatibility = self._morph._enable_mujoco_compatibility
v_l_infos, v_links_j_infos, v_links_g_infos, _ = self._parse_scene(morph, self._surface)
v_l_infos, v_links_j_infos, v_links_g_infos, _ = self._parse_scene(morph, self._surface_override)

# Validate that the variant has the same joint structure as the primary
if len(v_l_infos) != n_links:
Expand Down Expand Up @@ -215,9 +215,9 @@ def _load_heterogeneous_morphs(self):

elif isinstance(morph, (gs.morphs.Mesh, gs.morphs.Primitive)):
if isinstance(morph, gs.morphs.Mesh):
g_infos = self._load_mesh(morph, self._surface, load_geom_only_for_heterogeneous=True)
g_infos = self._load_mesh(morph, self._surface_override, load_geom_only_for_heterogeneous=True)
else:
g_infos = self._load_primitive(morph, self._surface, load_geom_only_for_heterogeneous=True)
g_infos = self._load_primitive(morph, self._surface_override, load_geom_only_for_heterogeneous=True)
if morph.fixed != self._morph.fixed:
gs.raise_exception("Mixing fixed and non-fixed morphs in heterogeneous entities is not supported.")
cg_infos, vg_infos = self._postprocess_geoms_info(morph, g_infos, is_robot=False)
Expand Down
3 changes: 3 additions & 0 deletions genesis/engine/entities/tool_entity/tool_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ def __init__(
):
super().__init__(idx, scene, morph, solver, material, surface, name=name)

self._surface = self.surface_override.model_copy()
self._surface.finalize_texture()

self._init_pos = np.array(morph.pos, dtype=gs.np_float)
self._init_quat = np.array(morph.quat, dtype=gs.np_float)

Expand Down
6 changes: 3 additions & 3 deletions genesis/engine/interactive_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,9 @@ def set_entity_vis_mode(self, entity: "RigidEntity", mode: str):
"""Switch entity rendering between ``"visual"`` and ``"collision"``."""
from genesis.ext import pyrender

if not isinstance(entity.surface, gs.surfaces.Surface):
if not isinstance(entity, gs.engine.entities.RigidEntity):
return
old_mode = entity.surface.vis_mode
old_mode = entity.vis_mode
if old_mode == mode:
return

Expand All @@ -234,7 +234,7 @@ def set_entity_vis_mode(self, entity: "RigidEntity", mode: str):
ctx.remove_node(ctx.rigid_nodes[geom.uid])
del ctx.rigid_nodes[geom.uid]

entity.surface.vis_mode = mode
entity.vis_mode = mode
rigid_solver.update_geoms_render_T()
rigid_solver.update_vgeoms()
rigid_solver.update_vgeoms_render_T()
Expand Down
Loading
Loading