GUI for finger v1
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
"""Open3D camera helpers for finger mesh examples."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
DEFAULT_FINGER_VIZ_POSE = "assets/finger/visualization/world_to_cam.npy"
|
||||
|
||||
_CAMERA_X_ROT_90 = np.array(
|
||||
[
|
||||
[1.0, 0.0, 0.0],
|
||||
[0.0, 0.0, -1.0],
|
||||
[0.0, -1.0, 0.0],
|
||||
],
|
||||
dtype=np.float64,
|
||||
)
|
||||
|
||||
_CAMERA_Z_ROT_180 = np.array(
|
||||
[
|
||||
[1.0, 0.0, 0.0],
|
||||
[0.0, 1.0, -1],
|
||||
[0.0, 0.0, -1],
|
||||
],
|
||||
dtype=np.float64,
|
||||
)
|
||||
|
||||
|
||||
def resolve_viz_pose_path(path: str | Path | None = None) -> Path:
|
||||
"""Resolve world_to_cam.npy from cwd or packaged asset layout."""
|
||||
raw = Path(path or DEFAULT_FINGER_VIZ_POSE).expanduser()
|
||||
if raw.is_file():
|
||||
return raw.resolve()
|
||||
|
||||
here = Path(__file__).resolve()
|
||||
candidates = [
|
||||
Path.cwd() / raw,
|
||||
here.parents[2] / raw,
|
||||
]
|
||||
for candidate in candidates:
|
||||
if candidate.is_file():
|
||||
return candidate.resolve()
|
||||
|
||||
checked = ", ".join(str(p) for p in candidates)
|
||||
raise FileNotFoundError(f"Visualization pose file not found: {raw}. Checked: {checked}")
|
||||
|
||||
|
||||
def camera_look_at_from_world_to_cam(
|
||||
world_to_cam: np.ndarray,
|
||||
*,
|
||||
lookat: np.ndarray,
|
||||
distance_scale: float = 2.5,
|
||||
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
||||
"""Derive Open3D look_at(center, eye, up) from a Blender world_to_cam matrix."""
|
||||
world_to_cam = np.asarray(world_to_cam, dtype=np.float64)
|
||||
cam_to_world = np.linalg.inv(world_to_cam)
|
||||
rotation = cam_to_world[:3, :3] @ _CAMERA_X_ROT_90 @ _CAMERA_Z_ROT_180
|
||||
|
||||
front = rotation @ np.array([0.0, 0.0, -1.0])
|
||||
up = rotation @ np.array([0.0, 1.0, 0.0])
|
||||
front_norm = np.linalg.norm(front)
|
||||
up_norm = np.linalg.norm(up)
|
||||
if front_norm > 0:
|
||||
front = front / front_norm
|
||||
if up_norm > 0:
|
||||
up = up / up_norm
|
||||
|
||||
lookat = np.asarray(lookat, dtype=np.float64).reshape(3)
|
||||
extent = float(np.linalg.norm(lookat - cam_to_world[:3, 3]))
|
||||
if extent < 1e-6:
|
||||
extent = 1.0
|
||||
eye = lookat - front * (extent * distance_scale)
|
||||
return lookat, eye, up
|
||||
|
||||
|
||||
def apply_view_from_world_to_cam(vis, world_to_cam: np.ndarray, *, lookat: np.ndarray) -> None:
|
||||
"""Apply Blender-exported world_to_cam as the Open3D default view."""
|
||||
world_to_cam = np.asarray(world_to_cam, dtype=np.float64)
|
||||
cam_to_world = np.linalg.inv(world_to_cam)
|
||||
rotation = cam_to_world[:3, :3] @ _CAMERA_X_ROT_90 @ _CAMERA_Z_ROT_180
|
||||
|
||||
front = rotation @ np.array([0.0, 0.0, -1.0])
|
||||
up = rotation @ np.array([0.0, 1.0, 0.0])
|
||||
front_norm = np.linalg.norm(front)
|
||||
up_norm = np.linalg.norm(up)
|
||||
if front_norm > 0:
|
||||
front = front / front_norm
|
||||
if up_norm > 0:
|
||||
up = up / up_norm
|
||||
|
||||
view_control = vis.get_view_control()
|
||||
view_control.set_lookat(lookat.astype(np.float64))
|
||||
view_control.set_front(front.astype(np.float64))
|
||||
view_control.set_up(up.astype(np.float64))
|
||||
vis.update_renderer()
|
||||
|
||||
|
||||
def apply_mesh_lighting(vis) -> None:
|
||||
"""Enable shaded lighting so the tactile mesh reads as a 3D surface."""
|
||||
import open3d as o3d
|
||||
|
||||
render_option = vis.get_render_option()
|
||||
if hasattr(render_option, "light_on"):
|
||||
render_option.light_on = True
|
||||
if hasattr(render_option, "mesh_color_option"):
|
||||
render_option.mesh_color_option = o3d.visualization.MeshColorOption.Color
|
||||
if hasattr(render_option, "mesh_shade_option"):
|
||||
render_option.mesh_shade_option = o3d.visualization.MeshShadeOption.Color
|
||||
vis.update_renderer()
|
||||
Reference in New Issue
Block a user