update exe GUI build

This commit is contained in:
ykcheungab
2026-06-21 12:01:34 +08:00
parent 258948bcb7
commit 7feae9550e
18 changed files with 862 additions and 173 deletions
+105 -35
View File
@@ -10,12 +10,21 @@ 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 .flow_arrow import (
FlowArrowFilamentSlot,
FlowArrowHiddenSlot,
FlowArrowOverlay,
ensure_flow_arrow_in_hidden_vis,
update_flow_arrows_filament,
update_flow_arrows_hidden,
)
from .mesh_camera import (
apply_filament_sun_light,
apply_shade_factors,
apply_view_from_world_to_cam,
camera_look_at_from_world_to_cam,
default_look_at_view,
orbit_eye_about_target,
precompute_shade_factors,
)
@@ -132,19 +141,35 @@ class _FilamentOffscreenBackend:
self._material = _make_lit_material(o3d)
self._mesh_added = False
self._arrow_added = False
self._flow_arrow_added = False
self._flow_arrow_slot = FlowArrowFilamentSlot()
self._reset_view_state()
self._apply_camera()
def _apply_camera(self) -> None:
def _reset_view_state(self) -> None:
if self.world_to_cam is not None:
center, eye, up = camera_look_at_from_world_to_cam(self.world_to_cam, lookat=self.lookat)
else:
center = self.lookat.astype(np.float64)
extent = np.ptp(self.mesh.rest_vertices, axis=0)
span = float(np.max(extent))
eye = center + np.array([0.0, 0.0, span * 2.0], dtype=np.float64)
up = np.array([0.0, 1.0, 0.0], dtype=np.float64)
self._renderer.scene.camera.look_at(center, eye, up)
center, eye, up = default_look_at_view(self.mesh.rest_vertices, self.lookat)
self._view_center = center
self._view_eye = eye
self._view_up = up
def _apply_camera(self) -> None:
self._renderer.scene.camera.look_at(self._view_center, self._view_eye, self._view_up)
def rotate_view(self, dx: float, dy: float) -> None:
self._view_eye, self._view_up = orbit_eye_about_target(
self._view_center,
self._view_eye,
self._view_up,
dx,
dy,
)
self._apply_camera()
def reset_view(self) -> None:
self._reset_view_state()
self._apply_camera()
def resize(self, width: int, height: int) -> None:
width = max(int(width), 64)
@@ -164,7 +189,18 @@ class _FilamentOffscreenBackend:
self._material = _make_lit_material(self._o3d)
self._mesh_added = False
self._arrow_added = False
self._flow_arrow_added = False
self._flow_arrow_slot = FlowArrowFilamentSlot()
center, eye, up = self._view_center, self._view_eye, self._view_up
self._renderer = self._o3d.visualization.rendering.OffscreenRenderer(self.width, self.height)
self._renderer.scene.set_background(_background_rgba01(self.mesh_background))
if self.mesh_lighting is not None:
apply_filament_sun_light(
self._renderer,
direction=self.mesh_lighting.direction,
intensity=self.mesh_lighting.intensity,
)
self._material = _make_lit_material(self._o3d)
self._view_center, self._view_eye, self._view_up = center, eye, up
self._apply_camera()
def render(
@@ -211,20 +247,15 @@ 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
update_flow_arrows_filament(
self._flow_arrow,
flow,
valid_mask,
scene=self._renderer.scene,
material=self._material,
slot=self._flow_arrow_slot,
mesh_to_o3d=lambda v, t, c: _mesh_to_o3d(o3d, v, t, c),
)
return _numpy_o3d_image_to_rgb(self._renderer.render_to_image())
@@ -280,6 +311,7 @@ class _HiddenVisualizerBackend:
self._flow_arrow = FlowArrowOverlay(mesh, style=flow_arrow_style)
self.vis = None
self.tri_mesh = None
self._flow_arrow_slot = FlowArrowHiddenSlot()
self._create_window()
def _create_window(self) -> None:
@@ -313,8 +345,7 @@ 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)
ensure_flow_arrow_in_hidden_vis(self._flow_arrow, self.vis, self._flow_arrow_slot)
render_option = self.vis.get_render_option()
render_option.mesh_show_back_face = True
@@ -322,21 +353,44 @@ class _HiddenVisualizerBackend:
if hasattr(render_option, "light_on"):
render_option.light_on = False
self._apply_default_view()
def _apply_default_view(self) -> None:
if self.vis is None:
return
if self.world_to_cam is not None:
apply_view_from_world_to_cam(self.vis, self.world_to_cam, lookat=self.lookat)
else:
view_control = self.vis.get_view_control()
center = self.lookat.astype(np.float64)
center, eye, up = default_look_at_view(self.mesh.rest_vertices, self.lookat)
view_control.set_lookat(center)
front = center - eye
front_norm = float(np.linalg.norm(front))
if front_norm > 1e-9:
front = front / front_norm
else:
front = np.array([0.0, 0.0, -1.0], dtype=np.float64)
view_control.set_front(front)
view_control.set_up(up)
extent = np.ptp(self.mesh.rest_vertices, axis=0)
span = float(np.max(extent))
view_control.set_lookat(center)
view_control.set_front(np.array([0.0, 0.0, -1.0]))
view_control.set_up(np.array([0.0, 1.0, 0.0]))
view_control.set_zoom(0.5 if span > 0 else 0.7)
self.vis.poll_events()
self.vis.update_renderer()
def rotate_view(self, dx: float, dy: float) -> None:
if self.vis is None:
return
self.vis.get_view_control().rotate(float(dx), float(dy))
self.vis.poll_events()
self.vis.update_renderer()
def reset_view(self) -> None:
if self.vis is None:
return
self._apply_default_view()
def resize(self, width: int, height: int) -> None:
width = max(int(width), 64)
height = max(int(height), 64)
@@ -377,11 +431,13 @@ 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)
update_flow_arrows_hidden(
self._flow_arrow,
flow,
valid_mask,
vis=self.vis,
slot=self._flow_arrow_slot,
)
self.vis.poll_events()
self.vis.update_renderer()
@@ -452,6 +508,20 @@ class OffscreenFingerMeshRenderer:
def resize(self, width: int, height: int) -> None:
self._backend.resize(width, height)
def rotate_view(self, dx: float, dy: float) -> None:
rotate = getattr(self._backend, "rotate_view", None)
if rotate is not None:
rotate(dx, dy)
def reset_view(self) -> None:
reset = getattr(self._backend, "reset_view", None)
if reset is not None:
reset()
@property
def flow_arrow(self) -> FlowArrowOverlay:
return self._backend._flow_arrow
def render(
self,
*,