Skip to content

Commit c9f314d

Browse files
duburcqaYilingQiao
authored andcommitted
[BUG FIX] Fix point cloud rendering from depth map (cont'd). (Genesis-Embodied-AI#1515)
* Fix point cloud generation from depth map. * Expose depth-only rendering option, w/o MSAA for invertible mapping. * Fix camera render API.
1 parent a2f9612 commit c9f314d

File tree

10 files changed

+257
-285
lines changed

10 files changed

+257
-285
lines changed

genesis/engine/entities/rigid_entity/rigid_geom.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def __init__(
106106
if len(self._sdf_faces) > 50000:
107107
mesh_descr = f"({mesh.metadata['mesh_path']})" if "mesh_path" in mesh.metadata else ""
108108
gs.logger.warning(
109-
"Beware that SDF pre-processing of mesh {mesh_descr} having more than 50000 vertices may take a very "
109+
f"Beware that SDF pre-processing of mesh {mesh_descr} having more than 50000 vertices may take a very "
110110
"long time (>10min) and require large RAM allocation (>20Gb). Please either enable convexify or "
111111
"decimation. (see FileMorph options)"
112112
)

genesis/ext/pyrender/camera.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,7 @@ class PerspectiveCamera(Camera):
109109
"""
110110

111111
def __init__(self, yfov, znear=DEFAULT_Z_NEAR, zfar=None, aspectRatio=None, name=None):
112-
super(PerspectiveCamera, self).__init__(
113-
znear=znear,
114-
zfar=zfar,
115-
name=name,
116-
)
112+
super(PerspectiveCamera, self).__init__(znear=znear, zfar=zfar, name=name)
117113

118114
self.yfov = yfov
119115
self.aspectRatio = aspectRatio
@@ -213,11 +209,7 @@ class OrthographicCamera(Camera):
213209
"""
214210

215211
def __init__(self, xmag, ymag, znear=DEFAULT_Z_NEAR, zfar=DEFAULT_Z_FAR, name=None):
216-
super(OrthographicCamera, self).__init__(
217-
znear=znear,
218-
zfar=zfar,
219-
name=name,
220-
)
212+
super(OrthographicCamera, self).__init__(znear=znear, zfar=zfar, name=name)
221213

222214
self.xmag = xmag
223215
self.ymag = ymag
@@ -313,11 +305,7 @@ class IntrinsicsCamera(Camera):
313305
"""
314306

315307
def __init__(self, fx, fy, cx, cy, znear=DEFAULT_Z_NEAR, zfar=DEFAULT_Z_FAR, name=None):
316-
super(IntrinsicsCamera, self).__init__(
317-
znear=znear,
318-
zfar=zfar,
319-
name=name,
320-
)
308+
super(IntrinsicsCamera, self).__init__(znear=znear, zfar=zfar, name=name)
321309

322310
self.fx = fx
323311
self.fy = fy

genesis/ext/pyrender/offscreen.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,15 @@ def render(
104104
self,
105105
scene,
106106
renderer,
107+
rgb=True,
108+
seg=False,
109+
normal=False,
110+
depth=False,
107111
flags=RenderFlags.NONE,
108112
camera_node=None,
109113
shadow=False,
110-
seg=False,
111-
ret_depth=False,
112114
plane_reflection=False,
113115
env_separate_rigid=False,
114-
normal=False,
115116
):
116117
"""Render a scene with the given set of flags.
117118
@@ -131,6 +132,9 @@ def render(
131132
depth_im : (h, w) float32
132133
The depth buffer in linear units.
133134
"""
135+
if seg and rgb:
136+
gs.raise_exception("RGB and segmentation map cannot be rendered in the same forward pass.")
137+
134138
if not self._has_valid_context:
135139
gs.raise_exception(
136140
"Ensure that the right context is set before rendering. Please call the method 'make_current'."
@@ -144,6 +148,9 @@ def render(
144148
if shadow and not self._is_software:
145149
flags |= RenderFlags.SHADOWS_ALL
146150

151+
if depth and not (rgb or seg):
152+
flags |= RenderFlags.DEPTH_ONLY
153+
147154
if plane_reflection and not self._is_software:
148155
flags |= RenderFlags.REFLECTIVE_FLOOR
149156

@@ -156,23 +163,30 @@ def render(
156163
else:
157164
seg_node_map = None
158165

159-
if ret_depth:
166+
if depth:
160167
flags |= RenderFlags.RET_DEPTH
161168

162-
if self._platform.supports_framebuffers():
163-
flags |= RenderFlags.OFFSCREEN
164-
retval = renderer.render(scene, flags, seg_node_map)
165-
else:
166-
renderer.render(scene, flags, seg_node_map)
167-
depth = renderer.read_depth_buf()
168-
if flags & RenderFlags.DEPTH_ONLY:
169-
retval = depth
169+
if rgb or depth or seg:
170+
if self._platform.supports_framebuffers():
171+
flags |= RenderFlags.OFFSCREEN
172+
retval = renderer.render(scene, flags, seg_node_map)
170173
else:
171-
color = renderer.read_color_buf()
172-
retval = color, depth
174+
if flags & RenderFlags.ENV_SEPARATE:
175+
gs.raise_exception("'env_separate_rigid=True' not supported on this platform.")
176+
if normal:
177+
gs.raise_exception("'normal=True' not supported on this platform.")
178+
renderer.render(scene, flags, seg_node_map)
179+
if depth:
180+
depth = renderer.read_depth_buf()
181+
if flags & RenderFlags.DEPTH_ONLY:
182+
retval = (depth,)
183+
else:
184+
color = renderer.read_color_buf()
185+
retval = (color, depth)
186+
else:
187+
retval = ()
173188

174189
if normal:
175-
176190
class CustomShaderCache:
177191
def __init__(self):
178192
self.program = None
@@ -193,8 +207,8 @@ def get_program(self, vertex_shader, fragment_shader, geometry_shader=None, defi
193207
if env_separate_rigid:
194208
flags |= RenderFlags.ENV_SEPARATE
195209
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
196-
normal_arr, _ = renderer.render(scene, flags, is_first_pass=False)
197-
retval = retval + (normal_arr,)
210+
normal_arr, *_ = renderer.render(scene, flags, is_first_pass=False, force_skip_shadows=True)
211+
retval = (*retval, normal_arr)
198212

199213
renderer._program_cache = old_cache
200214

genesis/ext/pyrender/renderer.py

Lines changed: 21 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def point_size(self):
115115
def point_size(self, value):
116116
self._point_size = float(value)
117117

118-
def render(self, scene, flags, seg_node_map=None, is_first_pass=True):
118+
def render(self, scene, flags, seg_node_map=None, *, is_first_pass=True, force_skip_shadows=False):
119119
"""Render a scene with the given set of flags.
120120
121121
Parameters
@@ -144,7 +144,7 @@ def render(self, scene, flags, seg_node_map=None, is_first_pass=True):
144144
self._update_context(scene, flags)
145145
self.jit.update(scene)
146146

147-
if flags & RenderFlags.DEPTH_ONLY or flags & RenderFlags.SEG or flags & RenderFlags.FLAT:
147+
if flags & RenderFlags.SEG or flags & RenderFlags.DEPTH_ONLY or flags & RenderFlags.FLAT:
148148
flags &= ~RenderFlags.REFLECTIVE_FLOOR
149149

150150
if flags & RenderFlags.ENV_SEPARATE and flags & RenderFlags.OFFSCREEN:
@@ -159,7 +159,7 @@ def render(self, scene, flags, seg_node_map=None, is_first_pass=True):
159159
env_idx = i if use_env_idx else -1
160160

161161
# Render necessary shadow maps
162-
if not (flags & RenderFlags.DEPTH_ONLY or flags & RenderFlags.SEG):
162+
if not (force_skip_shadows or flags & RenderFlags.SEG or flags & RenderFlags.DEPTH_ONLY):
163163
for ln in scene.light_nodes:
164164
take_pass = False
165165
if isinstance(ln.light, DirectionalLight) and flags & RenderFlags.SHADOWS_DIRECTIONAL:
@@ -180,37 +180,28 @@ def render(self, scene, flags, seg_node_map=None, is_first_pass=True):
180180
self._floor_pass(scene, flags, env_idx=env_idx)
181181

182182
retval = self._forward_pass(scene, flags, seg_node_map=seg_node_map, env_idx=env_idx)
183-
if isinstance(retval, tuple):
183+
if retval is not None:
184184
if retval_list is None:
185-
retval_list = tuple([[val] for val in retval])
185+
retval_list = tuple([val] for val in retval)
186186
else:
187187
for idx, val in enumerate(retval):
188188
retval_list[idx].append(val)
189-
elif retval is not None:
190-
if retval_list is None:
191-
retval_list = [retval]
192-
else:
193-
retval_list.append(retval)
194189

195190
# If necessary, make normals pass
196191
if flags & (RenderFlags.VERTEX_NORMALS | RenderFlags.FACE_NORMALS):
197-
self._normals_pass(scene, flags, env_idx=env_idx)
198-
199-
if use_env_idx:
200-
if isinstance(retval_list, list):
201-
retval_list = np.stack(retval_list, axis=0)
202-
elif isinstance(retval_list, tuple):
203-
retval_list = tuple([np.stack(val_list, axis=0) for val_list in retval_list])
204-
else:
205-
if isinstance(retval_list, list):
206-
retval_list = retval_list[0]
207-
elif isinstance(retval_list, tuple):
208-
retval_list = tuple([val_list[0] for val_list in retval_list])
192+
self._normal_pass(scene, flags, env_idx=env_idx)
209193

210194
# Update camera settings for retrieving depth buffers
211195
self._latest_znear = scene.main_camera_node.camera.znear
212196
self._latest_zfar = scene.main_camera_node.camera.zfar
213197

198+
if retval_list is None:
199+
return
200+
201+
if use_env_idx:
202+
retval_list = tuple(np.stack(val_list, axis=0) for val_list in retval_list)
203+
else:
204+
retval_list = tuple([val_list[0] for val_list in retval_list])
214205
return retval_list
215206

216207
def render_text(
@@ -313,114 +304,6 @@ def render_texts(self, texts, x, y, font_name="UbuntuMono-Regular", font_pt=40,
313304
for i, text in enumerate(texts):
314305
font.render_string(text, x, int(y - i * font_pt * 1.1), scale, TextAlign.TOP_LEFT)
315306

316-
def read_depth_buf(self):
317-
"""Read and return the current viewport's color buffer.
318-
319-
Returns
320-
-------
321-
depth_im : (h, w) float32
322-
The depth buffer in linear units.
323-
"""
324-
width, height = self.viewport_width, self.viewport_height
325-
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)
326-
glReadBuffer(GL_FRONT)
327-
depth_buf = glReadPixels(
328-
0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT
329-
)
330-
331-
depth_im = np.frombuffer(depth_buf, dtype=np.float32)
332-
depth_im = depth_im.reshape((height, width))
333-
depth_im = np.flip(depth_im, axis=0)
334-
335-
inf_inds = (depth_im == 1.0)
336-
depth_im = 2.0 * depth_im - 1.0
337-
z_near, z_far = self._latest_znear, self._latest_zfar
338-
noninf = np.logical_not(inf_inds)
339-
if z_far is None:
340-
depth_im[noninf] = 2 * z_near / (1.0 - depth_im[noninf])
341-
else:
342-
depth_im[noninf] = ((2.0 * z_near * z_far) /
343-
(z_far + z_near - depth_im[noninf] *
344-
(z_far - z_near)))
345-
depth_im[inf_inds] = 0.0
346-
347-
# Resize for macos if needed
348-
if sys.platform == 'darwin':
349-
depth_im = self._resize_image(depth_im)
350-
351-
return depth_im
352-
353-
def read_color_buf(self):
354-
"""Read and return the current viewport's color buffer.
355-
356-
Alpha cannot be computed for an on-screen buffer.
357-
358-
Returns
359-
-------
360-
color_im : (h, w, 3) uint8
361-
The color buffer in RGB byte format.
362-
"""
363-
# Extract color image from frame buffer
364-
width, height = self.viewport_width, self.viewport_height
365-
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)
366-
glReadBuffer(GL_FRONT)
367-
color_buf = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
368-
369-
# Re-format them into numpy arrays
370-
color_im = np.frombuffer(color_buf, dtype=np.uint8)
371-
color_im = color_im.reshape((height, width, 3))
372-
color_im = np.flip(color_im, axis=0)
373-
374-
# Resize for macos if needed
375-
if sys.platform == "darwin":
376-
color_im = self._resize_image(color_im, True)
377-
378-
return color_im
379-
380-
def get_tex_image(self, tex_id, bind_target=GL_TEXTURE_2D, read_target=GL_TEXTURE_2D, width=None, height=None):
381-
"""Read and return the current viewport's color buffer.
382-
383-
Returns
384-
-------
385-
depth_im : (h, w) float32
386-
The depth buffer in linear units.
387-
"""
388-
# width, height = self.viewport_width, self.viewport_height
389-
# width, height = 8192, 8192
390-
# glBindFramebuffer(GL_READ_FRAMEBUFFER, self._shadow_fb)
391-
# glReadBuffer(GL_NONE)
392-
# depth_buf = glReadPixels(
393-
# 0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT
394-
# )
395-
396-
glBindTexture(bind_target, tex_id)
397-
depth_buf = glGetTexImage(read_target, 0, GL_RGB, GL_FLOAT)
398-
399-
depth_im = np.frombuffer(depth_buf, dtype=np.float32)
400-
if width is None:
401-
height = int(depth_im.size**0.5)
402-
width = height
403-
depth_im = depth_im.reshape((height, width, 3))
404-
depth_im = np.flip(depth_im, axis=0)
405-
406-
return depth_im
407-
408-
inf_inds = depth_im == 1.0
409-
depth_im = 2.0 * depth_im - 1.0
410-
z_near, z_far = self._latest_znear, self._latest_zfar
411-
noninf = np.logical_not(inf_inds)
412-
if z_far is None:
413-
depth_im[noninf] = 2 * z_near / (1.0 - depth_im[noninf])
414-
else:
415-
depth_im[noninf] = (2.0 * z_near * z_far) / (z_far + z_near - depth_im[noninf] * (z_far - z_near))
416-
depth_im[inf_inds] = 0.0
417-
418-
# # Resize for macos if needed
419-
# if sys.platform == 'darwin':
420-
# depth_im = self._resize_image(depth_im)
421-
422-
return depth_im
423-
424307
def delete(self):
425308
"""Free all allocated OpenGL resources."""
426309
# Free shaders
@@ -505,7 +388,7 @@ def _forward_pass(self, scene, flags, seg_node_map=None, env_idx=-1):
505388

506389
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
507390

508-
if flags & RenderFlags.SEG:
391+
if flags & RenderFlags.SEG or flags & RenderFlags.DEPTH_ONLY:
509392
glDisable(GL_MULTISAMPLE)
510393
else:
511394
glEnable(GL_MULTISAMPLE)
@@ -569,7 +452,7 @@ def _shadow_mapping_pass(self, scene, light_node, flags, env_idx=-1):
569452

570453
self.jit.shadow_mapping_pass(self, V, P, flags, ProgramFlags.NONE, env_idx=env_idx)
571454

572-
def _normals_pass(self, scene, flags, env_idx=-1):
455+
def _normal_pass(self, scene, flags, env_idx=-1):
573456
# Set up viewport for render
574457
self._configure_forward_pass_viewport(flags)
575458
program = None
@@ -990,7 +873,7 @@ def _configure_forward_pass_viewport(self, flags):
990873
# If using offscreen render, bind main framebuffer
991874
if flags & RenderFlags.OFFSCREEN:
992875
self._configure_main_framebuffer()
993-
if flags & RenderFlags.SEG:
876+
if flags & RenderFlags.SEG or flags & RenderFlags.DEPTH_ONLY:
994877
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self._main_fb)
995878
else:
996879
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self._main_fb_ms)
@@ -1149,7 +1032,7 @@ def _delete_main_framebuffer(self):
11491032
def _read_main_framebuffer(self, scene, flags):
11501033
width, height = self._main_fb_dims
11511034

1152-
if not flags & RenderFlags.SEG:
1035+
if not (flags & RenderFlags.SEG or flags & RenderFlags.DEPTH_ONLY):
11531036
# Bind framebuffer and blit buffers
11541037
glBindFramebuffer(GL_READ_FRAMEBUFFER, self._main_fb_ms)
11551038
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self._main_fb)
@@ -1167,19 +1050,19 @@ def _read_main_framebuffer(self, scene, flags):
11671050

11681051
# Resize
11691052
depth_im = self._resize_image(depth_im, antialias=False)
1170-
else:
1171-
depth_im = None
11721053

11731054
if flags & RenderFlags.DEPTH_ONLY:
1174-
return depth_im
1055+
return (depth_im,)
11751056

11761057
# Read color
11771058
color_im = self.jit.read_color_buf(width, height, flags & RenderFlags.RGBA)
11781059

11791060
# Resize
11801061
color_im = self._resize_image(color_im, antialias=not flags & RenderFlags.SEG)
11811062

1182-
return color_im, depth_im
1063+
if flags & RenderFlags.RET_DEPTH:
1064+
return color_im, depth_im
1065+
return (color_im,)
11831066

11841067
def _resize_image(self, value, antialias):
11851068
"""Rescale the generated image if necessary."""

genesis/ext/pyrender/texture.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ def delete(self):
163163
##################
164164
# OpenGL code
165165
##################
166+
166167
def _add_to_context(self):
167168
if self._texid is not None:
168169
return

0 commit comments

Comments
 (0)