added mesh surface arrows
This commit is contained in:
@@ -10,6 +10,7 @@ from orisys.finger.mesh import UVSurfaceMesh
|
||||
from orisys.finger.viewer import flow_magnitude_vertex_colors, scalar_map_vertex_colors
|
||||
|
||||
from .contact_arrow import ContactArrowOverlay
|
||||
from .flow_arrow import FlowArrowOverlay
|
||||
from .mesh_camera import (
|
||||
apply_filament_sun_light,
|
||||
apply_shade_factors,
|
||||
@@ -64,6 +65,16 @@ def _vertex_colors(mesh, *, color_mode, threshold, value_min, value_max, flow=No
|
||||
)
|
||||
|
||||
|
||||
|
||||
def _background_rgba01(color: tuple[int, int, int]) -> list[float]:
|
||||
r, g, b = (int(color[0]), int(color[1]), int(color[2]))
|
||||
return [r / 255.0, g / 255.0, b / 255.0, 1.0]
|
||||
|
||||
|
||||
def _background_rgb01(color: tuple[int, int, int]) -> np.ndarray:
|
||||
return np.asarray(_background_rgba01(color)[:3], dtype=np.float64)
|
||||
|
||||
|
||||
class _FilamentOffscreenBackend:
|
||||
"""Filament OffscreenRenderer (Linux headless / platforms with EGL)."""
|
||||
|
||||
@@ -81,7 +92,9 @@ class _FilamentOffscreenBackend:
|
||||
lookat: np.ndarray,
|
||||
show_contact_arrow: bool,
|
||||
mesh_lighting=None,
|
||||
mesh_background: tuple[int, int, int] = (0, 0, 0),
|
||||
contact_arrow_style=None,
|
||||
flow_arrow_style=None,
|
||||
):
|
||||
import open3d as o3d
|
||||
|
||||
@@ -96,6 +109,7 @@ class _FilamentOffscreenBackend:
|
||||
self.world_to_cam = world_to_cam
|
||||
self.lookat = lookat
|
||||
self.mesh_lighting = mesh_lighting
|
||||
self.mesh_background = mesh_background
|
||||
self._shade_factors = (
|
||||
precompute_shade_factors(mesh.rest_vertices, mesh.triangles, mesh_lighting)
|
||||
if mesh_lighting is not None
|
||||
@@ -106,8 +120,9 @@ class _FilamentOffscreenBackend:
|
||||
enabled=show_contact_arrow,
|
||||
style=contact_arrow_style,
|
||||
)
|
||||
self._flow_arrow = FlowArrowOverlay(mesh, style=flow_arrow_style)
|
||||
self._renderer = o3d.visualization.rendering.OffscreenRenderer(self.width, self.height)
|
||||
self._renderer.scene.set_background([0.05, 0.05, 0.08, 1.0])
|
||||
self._renderer.scene.set_background(_background_rgba01(self.mesh_background))
|
||||
if mesh_lighting is not None:
|
||||
apply_filament_sun_light(
|
||||
self._renderer,
|
||||
@@ -117,6 +132,7 @@ class _FilamentOffscreenBackend:
|
||||
self._material = _make_lit_material(o3d)
|
||||
self._mesh_added = False
|
||||
self._arrow_added = False
|
||||
self._flow_arrow_added = False
|
||||
self._apply_camera()
|
||||
|
||||
def _apply_camera(self) -> None:
|
||||
@@ -138,7 +154,7 @@ class _FilamentOffscreenBackend:
|
||||
self.width = width
|
||||
self.height = height
|
||||
self._renderer = self._o3d.visualization.rendering.OffscreenRenderer(self.width, self.height)
|
||||
self._renderer.scene.set_background([0.05, 0.05, 0.08, 1.0])
|
||||
self._renderer.scene.set_background(_background_rgba01(self.mesh_background))
|
||||
if self.mesh_lighting is not None:
|
||||
apply_filament_sun_light(
|
||||
self._renderer,
|
||||
@@ -148,9 +164,19 @@ class _FilamentOffscreenBackend:
|
||||
self._material = _make_lit_material(self._o3d)
|
||||
self._mesh_added = False
|
||||
self._arrow_added = False
|
||||
self._flow_arrow_added = False
|
||||
self._apply_camera()
|
||||
|
||||
def render(self, *, flow=None, scalar_map=None, centroid=None, centroid_found=False, fnormal=0.0):
|
||||
def render(
|
||||
self,
|
||||
*,
|
||||
flow=None,
|
||||
scalar_map=None,
|
||||
centroid=None,
|
||||
centroid_found=False,
|
||||
fnormal=0.0,
|
||||
valid_mask=None,
|
||||
):
|
||||
o3d = self._o3d
|
||||
colors = _vertex_colors(
|
||||
self.mesh,
|
||||
@@ -185,6 +211,21 @@ class _FilamentOffscreenBackend:
|
||||
self._renderer.scene.remove_geometry("contact_arrow")
|
||||
self._arrow_added = False
|
||||
|
||||
flow_result = self._flow_arrow.compute(flow, valid_mask=valid_mask)
|
||||
if flow_result is not None and self._flow_arrow.arrow_mesh is not None:
|
||||
flow_vertices, flow_triangles, flow_colors = flow_result
|
||||
if len(flow_vertices) > 0:
|
||||
flow_mesh = _mesh_to_o3d(o3d, flow_vertices, flow_triangles, flow_colors)
|
||||
if not self._flow_arrow_added:
|
||||
self._renderer.scene.add_geometry("flow_arrows", flow_mesh, self._material)
|
||||
self._flow_arrow_added = True
|
||||
else:
|
||||
self._renderer.scene.remove_geometry("flow_arrows")
|
||||
self._renderer.scene.add_geometry("flow_arrows", flow_mesh, self._material)
|
||||
elif self._flow_arrow_added:
|
||||
self._renderer.scene.remove_geometry("flow_arrows")
|
||||
self._flow_arrow_added = False
|
||||
|
||||
return _numpy_o3d_image_to_rgb(self._renderer.render_to_image())
|
||||
|
||||
def close(self) -> None:
|
||||
@@ -208,7 +249,9 @@ class _HiddenVisualizerBackend:
|
||||
lookat: np.ndarray,
|
||||
show_contact_arrow: bool,
|
||||
mesh_lighting=None,
|
||||
mesh_background: tuple[int, int, int] = (0, 0, 0),
|
||||
contact_arrow_style=None,
|
||||
flow_arrow_style=None,
|
||||
):
|
||||
import open3d as o3d
|
||||
|
||||
@@ -223,6 +266,7 @@ class _HiddenVisualizerBackend:
|
||||
self.world_to_cam = world_to_cam
|
||||
self.lookat = lookat
|
||||
self.mesh_lighting = mesh_lighting
|
||||
self.mesh_background = mesh_background
|
||||
self._shade_factors = (
|
||||
precompute_shade_factors(mesh.rest_vertices, mesh.triangles, mesh_lighting)
|
||||
if mesh_lighting is not None
|
||||
@@ -233,6 +277,7 @@ class _HiddenVisualizerBackend:
|
||||
enabled=show_contact_arrow,
|
||||
style=contact_arrow_style,
|
||||
)
|
||||
self._flow_arrow = FlowArrowOverlay(mesh, style=flow_arrow_style)
|
||||
self.vis = None
|
||||
self.tri_mesh = None
|
||||
self._create_window()
|
||||
@@ -268,9 +313,12 @@ class _HiddenVisualizerBackend:
|
||||
if self._contact_arrow.arrow_mesh is not None:
|
||||
self.vis.add_geometry(self._contact_arrow.arrow_mesh)
|
||||
|
||||
if self._flow_arrow.enabled and self._flow_arrow.arrow_mesh is not None:
|
||||
self.vis.add_geometry(self._flow_arrow.arrow_mesh)
|
||||
|
||||
render_option = self.vis.get_render_option()
|
||||
render_option.mesh_show_back_face = True
|
||||
render_option.background_color = np.array([0.05, 0.05, 0.08])
|
||||
render_option.background_color = _background_rgb01(self.mesh_background)
|
||||
if hasattr(render_option, "light_on"):
|
||||
render_option.light_on = False
|
||||
|
||||
@@ -298,7 +346,16 @@ class _HiddenVisualizerBackend:
|
||||
self.height = height
|
||||
self._create_window()
|
||||
|
||||
def render(self, *, flow=None, scalar_map=None, centroid=None, centroid_found=False, fnormal=0.0):
|
||||
def render(
|
||||
self,
|
||||
*,
|
||||
flow=None,
|
||||
scalar_map=None,
|
||||
centroid=None,
|
||||
centroid_found=False,
|
||||
fnormal=0.0,
|
||||
valid_mask=None,
|
||||
):
|
||||
o3d = self._o3d
|
||||
colors = _vertex_colors(
|
||||
self.mesh,
|
||||
@@ -320,6 +377,12 @@ class _HiddenVisualizerBackend:
|
||||
self._contact_arrow.apply(arrow_vertices, arrow_colors)
|
||||
self.vis.update_geometry(self._contact_arrow.arrow_mesh)
|
||||
|
||||
flow_result = self._flow_arrow.compute(flow, valid_mask=valid_mask)
|
||||
if flow_result is not None and self._flow_arrow.arrow_mesh is not None:
|
||||
flow_vertices, flow_triangles, flow_colors = flow_result
|
||||
self._flow_arrow.apply(flow_vertices, flow_triangles, flow_colors)
|
||||
self.vis.update_geometry(self._flow_arrow.arrow_mesh)
|
||||
|
||||
self.vis.poll_events()
|
||||
self.vis.update_renderer()
|
||||
return _numpy_o3d_image_to_rgb(self.vis.capture_screen_float_buffer(do_render=False))
|
||||
@@ -340,7 +403,7 @@ def _create_backend(mesh: UVSurfaceMesh, **kwargs):
|
||||
return _HiddenVisualizerBackend(mesh, **kwargs)
|
||||
|
||||
class OffscreenFingerMeshRenderer:
|
||||
"""Render finger UV mesh + contact arrow to an RGB image for Qt embedding."""
|
||||
"""Render finger UV mesh + contact/flow arrows to an RGB image for Qt embedding."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -356,7 +419,9 @@ class OffscreenFingerMeshRenderer:
|
||||
lookat: np.ndarray | None = None,
|
||||
show_contact_arrow: bool = True,
|
||||
mesh_lighting=None,
|
||||
mesh_background: tuple[int, int, int] = (0, 0, 0),
|
||||
contact_arrow_style=None,
|
||||
flow_arrow_style=None,
|
||||
):
|
||||
lookat = lookat if lookat is not None else mesh.rest_vertices.mean(axis=0)
|
||||
self._backend = _create_backend(
|
||||
@@ -371,7 +436,9 @@ class OffscreenFingerMeshRenderer:
|
||||
lookat=lookat,
|
||||
show_contact_arrow=show_contact_arrow,
|
||||
mesh_lighting=mesh_lighting,
|
||||
mesh_background=mesh_background,
|
||||
contact_arrow_style=contact_arrow_style,
|
||||
flow_arrow_style=flow_arrow_style,
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -393,6 +460,7 @@ class OffscreenFingerMeshRenderer:
|
||||
centroid=None,
|
||||
centroid_found: bool = False,
|
||||
fnormal: float = 0.0,
|
||||
valid_mask=None,
|
||||
) -> np.ndarray:
|
||||
return self._backend.render(
|
||||
flow=flow,
|
||||
@@ -400,6 +468,7 @@ class OffscreenFingerMeshRenderer:
|
||||
centroid=centroid,
|
||||
centroid_found=centroid_found,
|
||||
fnormal=fnormal,
|
||||
valid_mask=valid_mask,
|
||||
)
|
||||
|
||||
def close(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user