Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
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
4 changes: 3 additions & 1 deletion genesis/engine/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,9 @@ def add_entity(
gs.raise_exception(f"Unsupported material for morph: {material} and {morph}.")

if surface.double_sided is None:
if isinstance(material, gs.materials.PBD.Cloth):
if hasattr(morph, "double_sided"):
surface.double_sided = morph.double_sided
elif isinstance(material, gs.materials.PBD.Cloth):
surface.double_sided = True
else:
surface.double_sided = False
Expand Down
6 changes: 6 additions & 0 deletions genesis/options/morphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,14 @@ class Plane(Primitive):
Whether the entity needs to be visualized. Set it to False if you need a invisible object only for collision purposes. Defaults to True. `visualization` and `collision` cannot both be False. **This is only used for RigidEntity.**
collision : bool, optional
Whether the entity needs to be considered for collision checking. Defaults to True. `visualization` and `collision` cannot both be False. **This is only used for RigidEntity.**
one_sided : bool, optional
Whether the entity needs to be rendered as a one-sided or two-sided plane.
"""

fixed: bool = True
normal: tuple = (0, 0, 1)
one_sided: bool = False
double_sided: bool | None = None

def __init__(self, **data):
super().__init__(**data)
Expand All @@ -348,6 +352,8 @@ def __init__(self, **data):
if self.requires_jac_and_IK:
gs.raise_exception("`requires_jac_and_IK` must be False for `Plane`.")

self.double_sided = not self.one_sided

self.normal = tuple(np.array(self.normal) / np.linalg.norm(self.normal))


Expand Down
58 changes: 43 additions & 15 deletions genesis/utils/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,26 +792,54 @@ def create_cylinder(radius, height, sections=None, color=(1.0, 1.0, 1.0, 1.0)):
return mesh


def create_plane(size=1e3, color=None, normal=(0, 0, 1)):
def create_plane(size=1e3, color=None, normal=(0, 0, 1), one_sided: bool = False):
thickness = 1e-2 # for safety
mesh = trimesh.creation.box(extents=[size, size, thickness])
if one_sided:
half = size * 0.5
verts = np.array(
[
[-half, -half, 0.0],
[half, -half, 0.0],
[half, half, 0.0],
[-half, -half, 0.0],
[half, half, 0.0],
[-half, half, 0.0],
],
dtype=np.float32,
)
faces = np.arange(6, dtype=np.int32).reshape(-1, 3)
uv = np.array(
[
[0, 0],
[size, 0],
[size, size],
[0, 0],
[size, size],
[0, size],
],
dtype=np.float32,
)
mesh = trimesh.Trimesh(verts, faces, process=False)
else:
mesh = trimesh.creation.box(extents=[size, size, thickness])
uv = np.array(
[
[0, 0],
[0, 0],
[0, size],
[0, size],
[size, 0],
[size, 0],
[size, size],
[size, size],
],
dtype=np.float32,
)
mesh.vertices[:, 2] -= thickness / 2
mesh.vertices = gu.transform_by_R(mesh.vertices, gu.z_to_R(normal))
if color is None: # use checkerboard texture
mesh.visual = trimesh.visual.TextureVisuals(
uv=np.array(
[
[0, 0],
[0, 0],
[0, size],
[0, size],
[size, 0],
[size, 0],
[size, size],
[size, size],
],
dtype=np.float32,
),
uv=uv,
material=trimesh.visual.material.SimpleMaterial(
image=Image.open(os.path.join(get_assets_dir(), "textures/checker.png")),
),
Expand Down
5 changes: 5 additions & 0 deletions genesis/vis/rasterizer_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ def on_rigid(self):
mesh = geom.get_sdf_trimesh()
else:
mesh = geom.get_trimesh()
if isinstance(rigid_entity.morph, gs.morphs.Plane) and not rigid_entity.morph.double_sided:
mesh = mu.create_plane(one_sided=not rigid_entity.morph.double_sided)
else:
mesh = geom.get_trimesh()

geom_T = geoms_T[geom.idx][self.rendered_envs_idx]
self.rigid_nodes[geom.uid] = self.add_node(
pyrender.Mesh.from_trimesh(
Expand Down