Skip to content

Commit

Permalink
[FEATURE] enable removing a single debug entity (#660)
Browse files Browse the repository at this point in the history
* feat: enable removing a single debug object

* fix: add name arg for mesh method

* feat: add a draw debug example script
  • Loading branch information
bxtbold authored Feb 2, 2025
1 parent da61654 commit 7af364c
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 33 deletions.
81 changes: 81 additions & 0 deletions examples/tutorials/draw_debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import time
import numpy as np
import genesis as gs


def main():
gs.init(backend=gs.cpu)

# Scene setup
viewer_options = gs.options.ViewerOptions(
camera_pos=(5.0, -5.0, 2.5),
camera_lookat=(0.0, 0.0, 0.0),
camera_fov=40,
max_FPS=200,
)

scene = gs.Scene(
viewer_options=viewer_options,
show_viewer=True,
)

# Add a plane for reference
scene.add_entity(morph=gs.morphs.Plane())
scene.build()

# Create debug objects
# Debug box
debug_box = scene.draw_debug_box(
bounds=[[-0.25, -0.25, 0], [0.25, 0.25, 0.5]],
color=(1, 0, 1, 1),
wireframe=True,
wireframe_radius=0.005, # Magenta
)

# Debug line
debug_line = scene.draw_debug_line(
start=(0.5, -0.25, 0.5), end=(0.5, 0.25, 0.5), radius=0.01, color=(1, 0, 0, 1)
) # Red

# Debug arrow
debug_arrow = scene.draw_debug_arrow(
pos=(1, 0, 0), vec=(0, 0, 1), radius=0.02, color=(1, 0, 0, 0.5)
) # Green

# Debug sphere
debug_sphere = scene.draw_debug_sphere(
pos=(1.5, 0, 0.5), radius=0.1, color=(0, 0, 1, 0.5)
) # Blue with alpha

# Debug multiple spheres
sphere_positions = np.array([[2, 0, 0.3], [2, 0, 0.5], [2, 0, 0.7]])
debug_spheres = scene.draw_debug_spheres(
poss=sphere_positions, radius=0.05, color=(1, 1, 0, 0.5)
) # Yellow

# Transformation matrix for frame (identity matrix with translation)
T = np.eye(4)
T[:3, 3] = [2.5, 0, 0.5]
debug_frame = scene.draw_debug_frame(
T=T, axis_length=0.5, origin_size=0.03, axis_radius=0.02
)

# Simulation loop
for step in range(500):
scene.step()
time.sleep(0.01)

# Clear individual objects after 200 steps
if step == 100:
scene.clear_debug_object(debug_box)
elif step == 200:
scene.clear_debug_object(debug_line)
elif step == 300:
scene.clear_debug_object(debug_arrow)
# All remaining objects are removed
elif step == 400:
scene.clear_debug_objects()


if __name__ == "__main__":
main()
67 changes: 55 additions & 12 deletions genesis/engine/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,9 +749,14 @@ def draw_debug_line(self, start, end, radius=0.002, color=(1.0, 0.0, 0.0, 0.5)):
The radius of the line (represented as a cylinder)
color : array_like, shape (4,), optional
The color of the line in RGBA format.
Returns
-------
node : genesis.ext.pyrender.mesh.Mesh
The created debug object.
"""
with self._visualizer.viewer_lock:
self._visualizer.context.draw_debug_line(start, end, radius, color)
return self._visualizer.context.draw_debug_line(start, end, radius, color)

@gs.assert_built
def draw_debug_arrow(self, pos, vec=(0, 0, 1), radius=0.01, color=(1.0, 0.0, 0.0, 0.5)):
Expand All @@ -768,10 +773,14 @@ def draw_debug_arrow(self, pos, vec=(0, 0, 1), radius=0.01, color=(1.0, 0.0, 0.0
The radius of the arrow body (represented as a cylinder).
color : array_like, shape (4,), optional
The color of the arrow in RGBA format.
"""
Returns
-------
node : genesis.ext.pyrender.mesh.Mesh
The created debug object.
"""
with self._visualizer.viewer_lock:
self._visualizer.context.draw_debug_arrow(pos, vec, radius, color)
return self._visualizer.context.draw_debug_arrow(pos, vec, radius, color)

@gs.assert_built
def draw_debug_frame(self, T, axis_length=1.0, origin_size=0.015, axis_radius=0.01):
Expand All @@ -788,10 +797,14 @@ def draw_debug_frame(self, T, axis_length=1.0, origin_size=0.015, axis_radius=0.
The size of the origin point (represented as a sphere).
axis_radius : float, optional
The radius of the axes (represented as cylinders).
"""
Returns
-------
node : genesis.ext.pyrender.mesh.Mesh
The created debug object.
"""
with self._visualizer.viewer_lock:
self._visualizer.context.draw_debug_frame(T, axis_length, origin_size, axis_radius)
return self._visualizer.context.draw_debug_frame(T, axis_length, origin_size, axis_radius)

@gs.assert_built
def draw_debug_mesh(self, mesh, pos=np.zeros(3), T=None):
Expand All @@ -806,10 +819,14 @@ def draw_debug_mesh(self, mesh, pos=np.zeros(3), T=None):
The position of the mesh in the scene.
T : array_like, shape (4, 4) | None, optional
The transformation matrix of the mesh. If None, the mesh will be drawn at the position specified by `pos`. Otherwise, `T` has a higher priority than `pos`.
"""
Returns
-------
node : genesis.ext.pyrender.mesh.Mesh
The created debug object.
"""
with self._visualizer.viewer_lock:
self._visualizer.context.draw_debug_mesh(mesh, pos, T)
return self._visualizer.context.draw_debug_mesh(mesh, pos, T)

@gs.assert_built
def draw_debug_sphere(self, pos, radius=0.01, color=(1.0, 0.0, 0.0, 0.5)):
Expand All @@ -824,9 +841,14 @@ def draw_debug_sphere(self, pos, radius=0.01, color=(1.0, 0.0, 0.0, 0.5)):
radius of the sphere.
color : array_like, shape (4,), optional
The color of the sphere in RGBA format.
Returns
-------
node : genesis.ext.pyrender.mesh.Mesh
The created debug object.
"""
with self._visualizer.viewer_lock:
self._visualizer.context.draw_debug_sphere(pos, radius, color)
return self._visualizer.context.draw_debug_sphere(pos, radius, color)

@gs.assert_built
def draw_debug_spheres(self, poss, radius=0.01, color=(1.0, 0.0, 0.0, 0.5)):
Expand All @@ -841,9 +863,14 @@ def draw_debug_spheres(self, poss, radius=0.01, color=(1.0, 0.0, 0.0, 0.5)):
The radius of the spheres.
color : array_like, shape (4,), optional
The color of the spheres in RGBA format.
Returns
-------
node : genesis.ext.pyrender.mesh.Mesh
The created debug object.
"""
with self._visualizer.viewer_lock:
self._visualizer.context.draw_debug_spheres(poss, radius, color)
return self._visualizer.context.draw_debug_spheres(poss, radius, color)

@gs.assert_built
def draw_debug_box(
Expand All @@ -866,10 +893,14 @@ def draw_debug_box(
Whether to draw the box as a wireframe.
wireframe_radius : float, optional
The radius of the wireframe lines.
"""
Returns
-------
node : genesis.ext.pyrender.mesh.Mesh
The created debug object.
"""
with self._visualizer.viewer_lock:
self._visualizer.context.draw_debug_box(
return self._visualizer.context.draw_debug_box(
bounds, color, wireframe=wireframe, wireframe_radius=wireframe_radius
)

Expand All @@ -884,10 +915,22 @@ def draw_debug_points(self, poss, colors=(1.0, 0.0, 0.0, 0.5)):
The positions of the points.
colors : array_like, shape (4,), optional
The color of the points in RGBA format.
Returns
-------
node : genesis.ext.pyrender.mesh.Mesh
The created debug object.
"""
with self._visualizer.viewer_lock:
return self._visualizer.context.draw_debug_points(poss, colors)

@gs.assert_built
def clear_debug_object(self, object):
"""
Clears all the debug objects in the scene.
"""
with self._visualizer.viewer_lock:
self._visualizer.context.draw_debug_points(poss, colors)
self._visualizer.context.clear_debug_object(object)

@gs.assert_built
def clear_debug_objects(self):
Expand Down
11 changes: 8 additions & 3 deletions genesis/ext/pyrender/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,15 @@ def is_transparent(self):
return False

@staticmethod
def from_points(points, colors=None, normals=None, is_visible=True, poses=None):
def from_points(points, name=None, colors=None, normals=None, is_visible=True, poses=None):
"""Create a Mesh from a set of points.
Parameters
----------
points : (n,3) float
The point positions.
name : str
The user-defined name of this object.
colors : (n,3) or (n,4) float, optional
RGB or RGBA colors for each point.
normals : (n,3) float, optionals
Expand All @@ -137,12 +139,13 @@ def from_points(points, colors=None, normals=None, is_visible=True, poses=None):
The created mesh.
"""
primitive = Primitive(positions=points, normals=normals, color_0=colors, mode=GLTF.POINTS, poses=poses)
mesh = Mesh(primitives=[primitive], is_visible=is_visible)
mesh = Mesh(primitives=[primitive], name=name, is_visible=is_visible)
return mesh

@staticmethod
def from_trimesh(
mesh,
name=None,
material=None,
is_visible=True,
poses=None,
Expand All @@ -157,6 +160,8 @@ def from_trimesh(
----------
mesh : :class:`~trimesh.base.Trimesh` or list of them
A triangular mesh or a list of meshes.
name : str
The user-defined name of this object.
material : :class:`Material`
The material of the object. Overrides any mesh material.
If not specified and the mesh has no material, a default material
Expand Down Expand Up @@ -234,7 +239,7 @@ def from_trimesh(
)
)

return Mesh(primitives=primitives, is_visible=is_visible)
return Mesh(primitives=primitives, name=name, is_visible=is_visible)

@staticmethod
def _get_trimesh_props(mesh, smooth=False, material=None):
Expand Down
Loading

0 comments on commit 7af364c

Please sign in to comment.