@@ -271,6 +271,77 @@ def test_batched_offscreen_rendering(show_viewer, tol):
271271 assert_allclose (steps_rgb_arrays [0 ][i ], steps_rgb_arrays [1 ][i ], tol = tol )
272272
273273
274+ @pytest .mark .required
275+ def test_point_cloud (show_viewer ):
276+ CAMERA_DIST = 8.0
277+ OBJ_OFFSET = 10.0
278+ BOX_HALFSIZE = 1.0
279+ SPHERE_RADIUS = 1.0
280+
281+ scene = gs .Scene (
282+ show_viewer = show_viewer ,
283+ show_FPS = False ,
284+ )
285+ scene .add_entity (
286+ morph = gs .morphs .Sphere (
287+ pos = (0.0 , OBJ_OFFSET , 0.0 ),
288+ radius = SPHERE_RADIUS ,
289+ fixed = True ,
290+ ),
291+ )
292+ camera_sphere = scene .add_camera (
293+ pos = (0.0 , OBJ_OFFSET , CAMERA_DIST ),
294+ lookat = (0.0 , OBJ_OFFSET , 0.0 ),
295+ GUI = show_viewer ,
296+ )
297+ scene .add_entity (
298+ morph = gs .morphs .Box (
299+ pos = (0.0 , - OBJ_OFFSET , 0.0 ),
300+ size = (2.0 * BOX_HALFSIZE , 2.0 * BOX_HALFSIZE , 2.0 * BOX_HALFSIZE ),
301+ fixed = True ,
302+ )
303+ )
304+ camera_box_1 = scene .add_camera (
305+ pos = (0.0 , - OBJ_OFFSET , CAMERA_DIST ),
306+ lookat = (0.0 , - OBJ_OFFSET , 0.0 ),
307+ GUI = show_viewer ,
308+ )
309+ camera_box_2 = scene .add_camera (
310+ pos = np .array ((CAMERA_DIST , CAMERA_DIST - OBJ_OFFSET , CAMERA_DIST )),
311+ lookat = (0.0 , - OBJ_OFFSET , 0.0 ),
312+ GUI = show_viewer ,
313+ )
314+ for camera in scene .visualizer .cameras :
315+ camera ._near = 1.0
316+ scene .build ()
317+
318+ if show_viewer :
319+ for camera in scene .visualizer .cameras :
320+ camera .render (rgb = True , depth = True )
321+
322+ point_cloud , mask = camera_box_1 .render_pointcloud (world_frame = False )
323+ point_cloud = point_cloud [mask ]
324+ assert_allclose (CAMERA_DIST - point_cloud [:, 2 ], BOX_HALFSIZE , atol = 1e-4 )
325+ assert np .all (- BOX_HALFSIZE <= point_cloud [:, :2 ].min (axis = 0 ))
326+ assert np .all (point_cloud [:, :2 ].max (axis = 0 ) <= BOX_HALFSIZE )
327+
328+ point_cloud , mask = camera_box_2 .render_pointcloud (world_frame = False )
329+ point_cloud = point_cloud [mask ]
330+ point_cloud = point_cloud @ gu .z_up_to_R (np .array ((1.0 , 1.0 , 1.0 )), np .array ((0.0 , 0.0 , 1.0 ))).T
331+ point_cloud -= np .array ((CAMERA_DIST , CAMERA_DIST , CAMERA_DIST ))
332+ assert_allclose (np .linalg .norm (point_cloud , ord = float ("inf" ), axis = - 1 ), BOX_HALFSIZE , atol = 1e-4 )
333+
334+ point_cloud , mask = camera_box_2 .render_pointcloud (world_frame = True )
335+ point_cloud = point_cloud [mask ]
336+ point_cloud += np .array ((0.0 , OBJ_OFFSET , 0.0 ))
337+ assert_allclose (np .linalg .norm (point_cloud , ord = float ("inf" ), axis = - 1 ), BOX_HALFSIZE , atol = 1e-4 )
338+
339+ # It is not possible to get higher accuracy because of tesselation
340+ point_cloud , mask = camera_sphere .render_pointcloud (world_frame = False )
341+ point_cloud = point_cloud [mask ]
342+ assert_allclose (np .linalg .norm ((0.0 , 0.0 , CAMERA_DIST ) - point_cloud , axis = - 1 ), SPHERE_RADIUS , atol = 1e-2 )
343+
344+
274345@pytest .mark .required
275346def test_batched_mounted_camera_rendering (show_viewer , tol ):
276347 scene = gs .Scene (
0 commit comments