The silhouette renderer reused trimesh_to_pyrender, which uploads the model's baseColor texture to the GL context; glGenTextures fails with a ctypes ArgumentError on the container's PyOpenGL/EGL stack. A silhouette needs only geometry, so build the pyrender scene with a plain MetallicRoughnessMaterial and render with RenderFlags.DEPTH_ONLY. Fixes the CXN_ShoePose crash and avoids per-render texture uploads in the optimizer loop (faster). Regression test added.
56 lines
1.9 KiB
Python
56 lines
1.9 KiB
Python
import os
|
|
|
|
os.environ.setdefault("PYOPENGL_PLATFORM", "egl")
|
|
|
|
import numpy as np
|
|
import pytest
|
|
import trimesh
|
|
|
|
pyrender = pytest.importorskip("pyrender")
|
|
|
|
from cxn.pose_solve import render_silhouette
|
|
|
|
|
|
def _egl_ok():
|
|
try:
|
|
r = pyrender.OffscreenRenderer(8, 8)
|
|
r.delete()
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
pytestmark = pytest.mark.skipif(not _egl_ok(), reason="EGL/pyrender offscreen unavailable")
|
|
|
|
|
|
def test_render_silhouette_box_is_nonempty_and_centered():
|
|
scene = trimesh.Scene(trimesh.creation.box(extents=(0.4, 0.4, 0.4)))
|
|
# Camera 2m in front (looking -Z), model at origin, no rotation.
|
|
sil = render_silhouette(scene, 0.0, 0.0, 0.0, (0.0, 0.0, 2.0), 45.0, 128, 128)
|
|
assert sil.dtype == bool
|
|
assert sil.shape == (128, 128)
|
|
frac = sil.mean()
|
|
assert 0.01 < frac < 0.9 # box visible but not filling the frame
|
|
ys, xs = np.nonzero(sil)
|
|
assert abs(xs.mean() - 64) < 12 and abs(ys.mean() - 64) < 12 # roughly centered
|
|
|
|
|
|
def test_render_silhouette_further_camera_is_smaller():
|
|
scene = trimesh.Scene(trimesh.creation.box(extents=(0.4, 0.4, 0.4)))
|
|
near = render_silhouette(scene, 0, 0, 0, (0, 0, 1.5), 45.0, 128, 128).sum()
|
|
far = render_silhouette(scene, 0, 0, 0, (0, 0, 4.0), 45.0, 128, 128).sum()
|
|
assert far < near
|
|
|
|
|
|
def test_render_silhouette_ignores_textures():
|
|
# Regression: a GLB-style mesh carrying a baseColor texture must not trigger
|
|
# a GL texture upload during silhouette rendering (silhouette = geometry only).
|
|
from PIL import Image
|
|
|
|
mesh = trimesh.creation.box(extents=(0.4, 0.2, 0.3))
|
|
uv = np.zeros((len(mesh.vertices), 2), dtype=float)
|
|
mesh.visual = trimesh.visual.TextureVisuals(uv=uv, image=Image.new("RGB", (8, 8), (200, 40, 40)))
|
|
sil = render_silhouette(trimesh.Scene(mesh), 0, 0, 0, (0, 0, 2.0), 45.0, 96, 96)
|
|
assert sil.dtype == bool
|
|
assert 0.01 < sil.mean() < 0.9
|