Skip to content

Commit 1b2ad53

Browse files
Kashu7100duburcqa
authored andcommitted
dev rendering backend
1 parent b4feff4 commit 1b2ad53

File tree

5 files changed

+80
-20
lines changed

5 files changed

+80
-20
lines changed

examples/rigid/single_franka_batch_render.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def main():
1515
parser.add_argument("-r", "--render_all_cameras", action="store_true", default=False)
1616
parser.add_argument("-o", "--output_dir", type=str, default="img_output/test")
1717
parser.add_argument("-u", "--use_rasterizer", action="store_true", default=False)
18+
parser.add_argument("-d", "--debug", action="store_true", default=False)
1819
args = parser.parse_args()
1920

2021
########################## init ##########################
@@ -37,6 +38,14 @@ def main():
3738
)
3839

3940
########################## cameras ##########################
41+
debug_cam = scene.add_camera(
42+
res=(720, 1280),
43+
pos=(1.5, -0.5, 1.0),
44+
lookat=(0.0, 0.0, 0.5),
45+
fov=60,
46+
GUI=args.vis,
47+
debug=True,
48+
)
4049
cam_0 = scene.add_camera(
4150
res=(512, 512),
4251
pos=(1.5, 0.5, 1.5),
@@ -75,14 +84,20 @@ def main():
7584
# Create an image exporter
7685
exporter = FrameImageExporter(args.output_dir)
7786

87+
if args.debug:
88+
debug_cam.start_recording()
7889
for i in range(args.n_steps):
7990
scene.step()
91+
if args.debug:
92+
debug_cam.render()
8093
if args.render_all_cameras:
8194
rgba, depth, _, _ = scene.render_all_cameras(rgb=True, depth=True)
8295
exporter.export_frame_all_cameras(i, rgb=rgba, depth=depth)
8396
else:
8497
rgba, depth, _, _ = cam_1.render(rgb=True, depth=True)
8598
exporter.export_frame_single_camera(i, cam_1.idx, rgb=rgba, depth=depth)
99+
if args.debug:
100+
debug_cam.stop_recording("debug_cam.mp4")
86101

87102

88103
if __name__ == "__main__":

genesis/engine/scene.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ def add_camera(
529529
spp=256,
530530
denoise=None,
531531
env_idx=None,
532+
debug=False,
532533
):
533534
"""
534535
Add a camera to the scene.
@@ -567,6 +568,12 @@ def add_camera(
567568
Whether to denoise the camera's rendered image. Only available when using the RayTracer renderer. Defaults
568569
to True on Linux, otherwise False. If OptiX denoiser is not available in your platform, consider enabling
569570
the OIDN denoiser option when building the RayTracer.
571+
debug : bool
572+
Whether to use the debug camera. It enables to create cameras that can used to monitor / debug the
573+
simulation without being part of the "sensors". Their output is rendered by the usual simple Rasterizer
574+
systematically, no matter if BatchRender and RayTracer is enabled. This way, it is possible to record the
575+
simulation with arbitrary resolution and camera pose, without interfering with what robots can perceive
576+
from their environment. Defaults to False.
570577
571578
Returns
572579
-------
@@ -576,7 +583,7 @@ def add_camera(
576583
if denoise is None:
577584
denoise = sys.platform != "darwin"
578585
return self._visualizer.add_camera(
579-
res, pos, lookat, up, model, fov, aperture, focus_dist, GUI, spp, denoise, env_idx
586+
res, pos, lookat, up, model, fov, aperture, focus_dist, GUI, spp, denoise, env_idx, debug
580587
)
581588

582589
@gs.assert_unbuilt

genesis/vis/batch_renderer.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,19 @@ def build(self):
8585
if gs.backend != gs.cuda:
8686
gs.raise_exception("BatchRenderer requires CUDA backend.")
8787

88-
cameras = self._visualizer._cameras
88+
self._cameras = gs.List([camera for camera in self._visualizer._cameras if not camera.debug])
8989
lights = self._lights
9090
rigid = self._visualizer.scene.rigid_solver
9191
n_envs = max(self._visualizer.scene.n_envs, 1)
92-
res = cameras[0].res
92+
res = self._cameras[0].res
9393
gpu_id = gs.device.index
9494
use_rasterizer = self._renderer_options.use_rasterizer
9595

9696
# Cameras
97-
n_cameras = len(cameras)
98-
cameras_pos = torch.stack([camera.get_pos() for camera in cameras], dim=1)
99-
cameras_quat = torch.stack([camera.get_quat() for camera in cameras], dim=1)
100-
cameras_fov = torch.tensor([camera.fov for camera in cameras], dtype=gs.tc_float, device=gs.device)
97+
n_cameras = len(self._cameras)
98+
cameras_pos = torch.stack([camera.get_pos() for camera in self._cameras], dim=1)
99+
cameras_quat = torch.stack([camera.get_quat() for camera in self._cameras], dim=1)
100+
cameras_fov = torch.tensor([camera.fov for camera in self._cameras], dtype=gs.tc_float, device=gs.device)
101101

102102
# Build taichi arrays to store light properties once. If later we need to support dynamic lights, we should
103103
# consider storing light properties as taichi fields in Genesis.
@@ -179,8 +179,8 @@ def render(self, rgb=True, depth=False, segmentation=False, normal=False, force_
179179
self.update_scene()
180180

181181
# Render frame
182-
cameras_pos = torch.stack([camera.get_pos() for camera in self._visualizer._cameras], dim=1)
183-
cameras_quat = torch.stack([camera.get_quat() for camera in self._visualizer._cameras], dim=1)
182+
cameras_pos = torch.stack([camera.get_pos() for camera in self._cameras], dim=1)
183+
cameras_quat = torch.stack([camera.get_quat() for camera in self._cameras], dim=1)
184184
render_options = np.array((rgb_, depth_, False, False, aliasing), dtype=np.uint32)
185185
rgba_arr_all, depth_arr_all = self._renderer.render(
186186
self._visualizer.scene.rigid_solver, cameras_pos, cameras_quat, render_options
@@ -217,3 +217,7 @@ def reset(self):
217217
@property
218218
def lights(self):
219219
return self._lights
220+
221+
@property
222+
def cameras(self):
223+
return self._cameras

genesis/vis/camera.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import time
44
import math
5+
from functools import lru_cache
56

67
import cv2
78
import numpy as np
@@ -66,6 +67,14 @@ class Camera(Sensor):
6667
The far plane of the camera.
6768
transform : np.ndarray, shape (4, 4), optional
6869
The transform matrix of the camera.
70+
env_idx : int, optional
71+
The index of the environment to track the camera.
72+
debug : bool, optional
73+
Whether to use the debug camera. It enables to create cameras that can used to monitor / debug the
74+
simulation without being part of the "sensors". Their output is rendered by the usual simple Rasterizer
75+
systematically, no matter if BatchRender and RayTracer is enabled. This way, it is possible to record the
76+
simulation with arbitrary resolution and camera pose, without interfering with what robots can perceive
77+
from their environment. Defaults to False.
6978
"""
7079

7180
def __init__(
@@ -87,6 +96,7 @@ def __init__(
8796
far=100.0,
8897
transform=None,
8998
env_idx=None,
99+
debug=False,
90100
):
91101
self._idx = idx
92102
self._uid = gs.UID()
@@ -111,6 +121,7 @@ def __init__(
111121
self._is_built = False
112122
self._attached_link = None
113123
self._attached_offset_T = None
124+
self._debug = debug
114125

115126
self._env_idx = env_idx
116127
self._envs_offset = None
@@ -323,13 +334,13 @@ def _batch_render(
323334
# If n_envs == 0, the second dimension of the output is camera.
324335
# Only return the current camera's image
325336
if rgb_arr:
326-
rgb_arr = rgb_arr[self._idx]
337+
rgb_arr = rgb_arr[self.idx]
327338
if depth:
328-
depth_arr = depth_arr[self._idx]
339+
depth_arr = depth_arr[self.idx]
329340
if segmentation:
330-
seg_arr = seg_arr[self._idx]
341+
seg_arr = seg_arr[self.idx]
331342
if normal:
332-
normal_arr = normal_arr[self._idx]
343+
normal_arr = normal_arr[self.idx]
333344
return rgb_arr, depth_arr, seg_arr, normal_arr
334345

335346
@gs.assert_built
@@ -385,11 +396,11 @@ def render(
385396
"""
386397
rgb_arr, depth_arr, seg_arr, seg_color_arr, seg_idxc_arr, normal_arr = None, None, None, None, None, None
387398

388-
if self._batch_renderer is not None:
399+
if not self._debug and self._batch_renderer is not None:
389400
rgb_arr, depth_arr, seg_idxc_arr, normal_arr = self._batch_render(
390401
rgb, depth, segmentation, normal, force_render, antialiasing
391402
)
392-
elif self._raytracer is not None:
403+
elif self._debug and self._raytracer is not None:
393404
if rgb:
394405
self._raytracer.update_scene()
395406
rgb_arr = self._raytracer.render_camera(self)
@@ -695,7 +706,7 @@ def stop_recording(self, save_to_filename=None, fps=60):
695706
+ f'_cam_{self.idx}_{time.strftime("%Y%m%d_%H%M%S")}.mp4'
696707
)
697708

698-
if self._rgb_stacked:
709+
if not self._debug and self._rgb_stacked:
699710
for env_idx in self._visualizer._context.rendered_envs_idx:
700711
env_imgs = [imgs[env_idx] for imgs in self._recorded_imgs]
701712
env_name, env_ext = os.path.splitext(save_to_filename)
@@ -753,7 +764,7 @@ def is_built(self):
753764

754765
@property
755766
def idx(self):
756-
"""The integer index of the camera."""
767+
"""The global integer index of the camera."""
757768
return self._idx
758769

759770
@property
@@ -839,6 +850,11 @@ def env_idx(self):
839850
"""Index of the environment being tracked by the camera."""
840851
return self._env_idx
841852

853+
@property
854+
def debug(self):
855+
"""Whether the camera is a debug camera."""
856+
return self._debug
857+
842858
@property
843859
def pos(self):
844860
"""The current position of the camera for the tracked environment."""

genesis/vis/visualizer.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,17 +127,35 @@ def destroy(self):
127127
self.viewer_lock = None
128128
self._renderer = None
129129

130-
def add_camera(self, res, pos, lookat, up, model, fov, aperture, focus_dist, GUI, spp, denoise, env_idx):
131-
cam_idx = len(self._cameras)
130+
def add_camera(self, res, pos, lookat, up, model, fov, aperture, focus_dist, GUI, spp, denoise, env_idx, debug):
131+
cam_idx = (
132+
len([c for c in self._cameras if not c.debug]) if not debug else len([c for c in self._cameras if c.debug])
133+
)
132134
camera = Camera(
133-
self, cam_idx, model, res, pos, lookat, up, fov, aperture, focus_dist, GUI, spp, denoise, env_idx=env_idx
135+
self,
136+
cam_idx,
137+
model,
138+
res,
139+
pos,
140+
lookat,
141+
up,
142+
fov,
143+
aperture,
144+
focus_dist,
145+
GUI,
146+
spp,
147+
denoise,
148+
env_idx=0 if debug else env_idx,
149+
debug=debug,
134150
)
135151
self._cameras.append(camera)
136152
return camera
137153

138154
def add_light(self, pos, dir, intensity, directional, castshadow, cutoff):
139155
if self._batch_renderer is not None:
140156
self._batch_renderer.add_light(pos, dir, intensity, directional, castshadow, cutoff)
157+
else:
158+
gs.raise_exception("`add_light` is specifically for batch renderer.")
141159

142160
def reset(self):
143161
self._t = -1

0 commit comments

Comments
 (0)