[Bug]: test_batched_offscreen_rendering intermittently fails due to pixel variance
Bug Description
The test tests/test_render.py::test_batched_offscreen_renderingis failing intermittently due to minor pixel-level discrepancies in rendered outputs.
Steps to Reproduce
If possible, provide a script triggering the bug, e.g.
pytest -v --forked -m required tests/test_render.py::test_batched_offscreen_rendering
Make sure to attached any needed assets (here attachement.xml)!
Expected Behavior
expect to pass the test
Screenshots/Videos
No response
Relevant log output
@pytest.mark.required
@pytest.mark.flaky(reruns=3, condition=(sys.platform == "darwin"))
def test_batched_offscreen_rendering(tmp_path, show_viewer, tol):
scene = gs.Scene(
vis_options=gs.options.VisOptions(
# rendered_envs_idx=(0, 1, 2),
env_separate_rigid=False,
),
show_viewer=show_viewer,
show_FPS=False,
)
plane = scene.add_entity(
morph=gs.morphs.Plane(),
surface=gs.surfaces.Aluminium(
ior=10.0,
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/sphere.obj",
scale=0.1,
pos=(-0.2, -0.8, 0.2),
fixed=True,
),
surface=gs.surfaces.Rough(
diffuse_texture=gs.textures.ColorTexture(
color=(1.0, 0.5, 0.5),
),
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/sphere.obj",
scale=0.1,
pos=(-0.2, -0.5, 0.2),
fixed=True,
),
surface=gs.surfaces.Rough(
color=(1.0, 1.0, 1.0),
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/sphere.obj",
scale=0.1,
pos=(-0.2, -0.2, 0.2),
fixed=True,
),
surface=gs.surfaces.Smooth(
color=(0.6, 0.8, 1.0),
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/sphere.obj",
scale=0.1,
pos=(-0.2, 0.2, 0.2),
fixed=True,
),
surface=gs.surfaces.Iron(
color=(1.0, 1.0, 1.0),
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/sphere.obj",
scale=0.1,
pos=(-0.2, 0.5, 0.2),
fixed=True,
),
surface=gs.surfaces.Gold(
color=(1.0, 1.0, 1.0),
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/sphere.obj",
scale=0.1,
pos=(-0.2, 0.8, 0.2),
fixed=True,
),
surface=gs.surfaces.Glass(
color=(1.0, 1.0, 1.0),
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/sphere.obj",
scale=0.1,
pos=(0.2, -0.8, 0.2),
fixed=True,
),
surface=gs.surfaces.Smooth(
color=(1.0, 1.0, 1.0, 0.5),
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/wooden_sphere_OBJ/wooden_sphere.obj",
scale=0.025,
pos=(0.2, -0.5, 0.2),
fixed=True,
),
)
scene.add_entity(
morph=gs.morphs.Mesh(
file="meshes/wooden_sphere_OBJ/wooden_sphere.obj",
scale=0.025,
pos=(0.2, -0.2, 0.2),
fixed=True,
),
surface=gs.surfaces.Rough(
diffuse_texture=gs.textures.ImageTexture(
image_path="textures/checker.png",
)
),
)
robot = scene.add_entity(
gs.morphs.MJCF(file="xml/franka_emika_panda/panda.xml"),
)
cam = scene.add_camera(
pos=(0.9, 0.0, 0.4),
lookat=(0.0, 0.0, 0.4),
res=(500, 500),
fov=60,
spp=512,
GUI=False,
)
scene.build(n_envs=3, env_spacing=(2.0, 2.0))
cam.start_recording()
for _ in range(7):
dofs_lower_bound, dofs_upper_bound = robot.get_dofs_limit()
qpos = dofs_lower_bound + (dofs_upper_bound - dofs_lower_bound) * torch.rand(robot.n_qs)
steps_rgb_arrays = []
for _ in range(2):
scene.step()
robots_rgb_arrays = []
robot.set_qpos(torch.tile(qpos, (3, 1)))
scene.visualizer.update()
for i in range(3):
pos_i = scene.envs_offset[i] + np.array([0.9, 0.0, 0.4])
lookat_i = scene.envs_offset[i] + np.array([0.0, 0.0, 0.4])
cam.set_pose(pos=pos_i, lookat=lookat_i)
rgb_array, *_ = cam.render(rgb=True, depth=False, segmentation=False, colorize_seg=False, normal=False)
assert np.max(np.std(rgb_array.reshape((-1, 3)), axis=0)) > 10.0
robots_rgb_arrays.append(rgb_array)
steps_rgb_arrays.append(robots_rgb_arrays)
for i in range(3):
> assert_allclose(steps_rgb_arrays[0][i], steps_rgb_arrays[1][i], tol=tol)
tests/test_render.py:273:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
actual = array([[[10, 20, 31],
[10, 20, 31],
[10, 20, 31],
...,
[10, 20, 31],
[10, 20, ...54],
...,
[39, 55, 73],
[39, 55, 73],
[39, 55, 73]]], shape=(500, 500, 3), dtype=uint8)
desired = array([[[10, 20, 31],
[10, 20, 31],
[10, 20, 31],
...,
[10, 20, 31],
[10, 20, ...54],
...,
[39, 55, 73],
[39, 55, 73],
[39, 55, 73]]], shape=(500, 500, 3), dtype=uint8)
def assert_allclose(actual, desired, *, atol=None, rtol=None, tol=None, err_msg=""):
assert (tol is not None) ^ (atol is not None or rtol is not None)
if tol is not None:
atol = tol
rtol = tol
if rtol is None:
rtol = 0.0
if atol is None:
atol = 0.0
args = [actual, desired]
for i, arg in enumerate(args):
if isinstance(arg, torch.Tensor):
arg = tensor_to_array(arg)
elif isinstance(arg, (tuple, list)):
arg = [tensor_to_array(val) for val in arg]
args[i] = np.asanyarray(arg)
if all(e.size == 0 for e in args):
return
> np.testing.assert_allclose(*args, atol=atol, rtol=rtol, err_msg=err_msg)
E AssertionError:
E Not equal to tolerance rtol=1e-09, atol=1e-09
E
E Mismatched elements: 2 / 750000 (0.000267%)
E Max absolute difference among violations: 1
E Max relative difference among violations: 0.00518135
E ACTUAL: array([[[10, 20, 31],
E [10, 20, 31],
E [10, 20, 31],...
E DESIRED: array([[[10, 20, 31],
E [10, 20, 31],
E [10, 20, 31],...
tests/utils.py:260: AssertionError
Environment
- OS: Ubuntu 24.04 & Windows
- GPU/CPU: 1050 on Ubuntu & 4060Ti on Windows
- GPU-driver version 550.163.01 on Ubuntu & 580.88 on Windows
- CUDA / CUDA-toolkit version 12.4 on Ubuntu & 12.6 on Windows
Release version or Commit ID
aeabb23e8515471f3c309901dc54ab0b7970934a
Additional Context
No response
You should fill the environment information. Knowing whether you are using some Nvidia GPU is critical for this kind of issue, because no flakiness has been observed so far on this platform.
Here's the environment information for twice tests where I encountered the issue: 1. OS: Ubuntu 24.04 GPU: NVIDIA GeForce GTX 1050 Driver: 550.163.01 CUDA: 12.4 2. OS: Windows GPU: NVIDIA GeForce RTX 4060 Ti Driver: 580.88 CUDA: 12.6
Ok, that is disappointing. Are you sure your GPU is used for rendering? I will mark those tests as XPASS if so.