fix: update pygfx integration for current API
- Use rendercanvas.qt.RenderCanvas instead of wgpu.gui.qt.WgpuCanvas - Fix camera position API: use camera.local.position instead of camera.position.set() - Fix light position API: use light.local.position - Fix PygfxRenderObject to properly inherit from RenderObject - Change add_mesh/add_wireframe/add_points/add_grid/add_axes to return string ID - Update base Renderer class to return str instead of RenderObject - Add custom compute_normals() function for mesh normals
This commit is contained in:
@@ -97,7 +97,7 @@ class Renderer(ABC):
|
||||
faces: np.ndarray,
|
||||
color: Tuple[float, float, float] = (0.2, 0.4, 0.8),
|
||||
name: Optional[str] = None,
|
||||
) -> RenderObject:
|
||||
) -> str:
|
||||
"""
|
||||
Add a mesh to the scene.
|
||||
|
||||
@@ -108,7 +108,7 @@ class Renderer(ABC):
|
||||
name: Optional name for the object
|
||||
|
||||
Returns:
|
||||
RenderObject representing the mesh
|
||||
String ID of the mesh
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -120,7 +120,7 @@ class Renderer(ABC):
|
||||
color: Tuple[float, float, float] = (1.0, 1.0, 1.0),
|
||||
line_width: float = 1.0,
|
||||
name: Optional[str] = None,
|
||||
) -> RenderObject:
|
||||
) -> str:
|
||||
"""
|
||||
Add a wireframe to the scene.
|
||||
|
||||
@@ -132,7 +132,7 @@ class Renderer(ABC):
|
||||
name: Optional name for the object
|
||||
|
||||
Returns:
|
||||
RenderObject representing the wireframe
|
||||
String ID of the wireframe
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -143,7 +143,7 @@ class Renderer(ABC):
|
||||
color: Tuple[float, float, float] = (1.0, 0.0, 0.0),
|
||||
size: float = 5.0,
|
||||
name: Optional[str] = None,
|
||||
) -> RenderObject:
|
||||
) -> str:
|
||||
"""
|
||||
Add points to the scene.
|
||||
|
||||
@@ -154,7 +154,7 @@ class Renderer(ABC):
|
||||
name: Optional name for the object
|
||||
|
||||
Returns:
|
||||
RenderObject representing the points
|
||||
String ID of the points
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -166,7 +166,7 @@ class Renderer(ABC):
|
||||
color: Tuple[float, float, float] = (1.0, 1.0, 1.0),
|
||||
line_width: float = 1.0,
|
||||
name: Optional[str] = None,
|
||||
) -> RenderObject:
|
||||
) -> str:
|
||||
"""
|
||||
Add line segments to the scene.
|
||||
|
||||
@@ -178,7 +178,7 @@ class Renderer(ABC):
|
||||
name: Optional name for the object
|
||||
|
||||
Returns:
|
||||
RenderObject representing the lines
|
||||
String ID of the lines
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -312,13 +312,13 @@ class Renderer(ABC):
|
||||
size: float = 100.0,
|
||||
divisions: int = 10,
|
||||
color: Tuple[float, float, float] = (0.3, 0.3, 0.3),
|
||||
) -> RenderObject:
|
||||
"""Add a reference grid."""
|
||||
) -> str:
|
||||
"""Add a reference grid. Returns the grid ID."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def add_axes(self, size: float = 10.0, visible: bool = True) -> RenderObject:
|
||||
"""Add coordinate axes."""
|
||||
def add_axes(self, size: float = 10.0, visible: bool = True) -> str:
|
||||
"""Add coordinate axes. Returns the axes ID."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
|
||||
@@ -55,9 +55,17 @@ class PygfxRenderObject(RenderObject):
|
||||
geometry: Any = None
|
||||
material: Any = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.scene_node is not None:
|
||||
self._scene_node = self.scene_node
|
||||
def __init__(
|
||||
self,
|
||||
scene_node: Any = None,
|
||||
geometry: Any = None,
|
||||
material: Any = None,
|
||||
name: Optional[str] = None,
|
||||
):
|
||||
super().__init__(name=name)
|
||||
self.scene_node = scene_node
|
||||
self.geometry = geometry
|
||||
self.material = material
|
||||
|
||||
|
||||
class PygfxRenderer(Renderer):
|
||||
@@ -84,15 +92,15 @@ class PygfxRenderer(Renderer):
|
||||
"""Initialize pygfx with Qt widget."""
|
||||
try:
|
||||
import pygfx as gfx
|
||||
from wgpu.gui.qt import WgpuCanvas
|
||||
from rendercanvas.qt import RenderCanvas
|
||||
from PySide6.QtWidgets import QVBoxLayout
|
||||
|
||||
self._canvas = WgpuCanvas(parent=parent_widget)
|
||||
self._canvas = RenderCanvas(parent=parent_widget)
|
||||
self._renderer = gfx.renderers.WgpuRenderer(self._canvas)
|
||||
self._scene = gfx.Scene()
|
||||
|
||||
self._camera = gfx.PerspectiveCamera(50, 16 / 9)
|
||||
self._camera.position.set(100, 100, 100)
|
||||
self._camera.local.position = (100, 100, 100)
|
||||
|
||||
self._controller = gfx.OrbitController(self._camera, register_events=self._renderer)
|
||||
|
||||
@@ -110,6 +118,9 @@ class PygfxRenderer(Renderer):
|
||||
|
||||
except Exception as e:
|
||||
print(f"Failed to initialize pygfx: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
def _setup_lighting(self) -> None:
|
||||
@@ -120,11 +131,11 @@ class PygfxRenderer(Renderer):
|
||||
self._scene.add(ambient)
|
||||
|
||||
directional = gfx.DirectionalLight(intensity=1.0)
|
||||
directional.position.set(100, 100, 100)
|
||||
directional.local.position = (100, 100, 100)
|
||||
self._scene.add(directional)
|
||||
|
||||
fill = gfx.DirectionalLight(intensity=0.5)
|
||||
fill.position.set(-100, 50, 50)
|
||||
fill.local.position = (-100, 50, 50)
|
||||
self._scene.add(fill)
|
||||
|
||||
def _add_grid(self) -> None:
|
||||
@@ -151,9 +162,10 @@ class PygfxRenderer(Renderer):
|
||||
faces: np.ndarray,
|
||||
color: Tuple[float, float, float] = (0.2, 0.4, 0.8),
|
||||
name: Optional[str] = None,
|
||||
) -> PygfxRenderObject:
|
||||
"""Add a mesh to the scene."""
|
||||
) -> str:
|
||||
"""Add a mesh to the scene. Returns the mesh ID."""
|
||||
import pygfx as gfx
|
||||
import uuid
|
||||
|
||||
vertices = np.asarray(vertices, dtype=np.float32)
|
||||
faces = np.asarray(faces, dtype=np.int32)
|
||||
@@ -167,11 +179,12 @@ class PygfxRenderer(Renderer):
|
||||
mesh = gfx.Mesh(geometry, material)
|
||||
self._scene.add(mesh)
|
||||
|
||||
obj = PygfxRenderObject(name=name, scene_node=mesh, geometry=geometry, material=material)
|
||||
mesh_id = name or f"mesh_{uuid.uuid4().hex[:8]}"
|
||||
obj = PygfxRenderObject(name=mesh_id, scene_node=mesh, geometry=geometry, material=material)
|
||||
obj.color = RenderColor(*color)
|
||||
self._objects.append(obj)
|
||||
|
||||
return obj
|
||||
return mesh_id
|
||||
|
||||
def add_wireframe(
|
||||
self,
|
||||
@@ -180,9 +193,10 @@ class PygfxRenderer(Renderer):
|
||||
color: Tuple[float, float, float] = (1.0, 1.0, 1.0),
|
||||
line_width: float = 1.0,
|
||||
name: Optional[str] = None,
|
||||
) -> PygfxRenderObject:
|
||||
"""Add a wireframe to the scene."""
|
||||
) -> str:
|
||||
"""Add a wireframe to the scene. Returns the wireframe ID."""
|
||||
import pygfx as gfx
|
||||
import uuid
|
||||
|
||||
positions: List[List[float]] = []
|
||||
for edge in edges:
|
||||
@@ -197,11 +211,14 @@ class PygfxRenderer(Renderer):
|
||||
lines = gfx.Line(geometry, material)
|
||||
self._scene.add(lines)
|
||||
|
||||
obj = PygfxRenderObject(name=name, scene_node=lines, geometry=geometry, material=material)
|
||||
wireframe_id = name or f"wireframe_{uuid.uuid4().hex[:8]}"
|
||||
obj = PygfxRenderObject(
|
||||
name=wireframe_id, scene_node=lines, geometry=geometry, material=material
|
||||
)
|
||||
obj.color = RenderColor(*color)
|
||||
self._objects.append(obj)
|
||||
|
||||
return obj
|
||||
return wireframe_id
|
||||
|
||||
def add_points(
|
||||
self,
|
||||
@@ -209,9 +226,10 @@ class PygfxRenderer(Renderer):
|
||||
color: Tuple[float, float, float] = (1.0, 0.0, 0.0),
|
||||
size: float = 5.0,
|
||||
name: Optional[str] = None,
|
||||
) -> PygfxRenderObject:
|
||||
"""Add points to the scene."""
|
||||
) -> str:
|
||||
"""Add points to the scene. Returns the points ID."""
|
||||
import pygfx as gfx
|
||||
import uuid
|
||||
|
||||
points_arr = np.asarray(points, dtype=np.float32)
|
||||
|
||||
@@ -221,13 +239,14 @@ class PygfxRenderer(Renderer):
|
||||
points_obj = gfx.Points(geometry, material)
|
||||
self._scene.add(points_obj)
|
||||
|
||||
points_id = name or f"points_{uuid.uuid4().hex[:8]}"
|
||||
obj = PygfxRenderObject(
|
||||
name=name, scene_node=points_obj, geometry=geometry, material=material
|
||||
name=points_id, scene_node=points_obj, geometry=geometry, material=material
|
||||
)
|
||||
obj.color = RenderColor(*color)
|
||||
self._objects.append(obj)
|
||||
|
||||
return obj
|
||||
return points_id
|
||||
|
||||
def add_lines(
|
||||
self,
|
||||
@@ -236,9 +255,10 @@ class PygfxRenderer(Renderer):
|
||||
color: Tuple[float, float, float] = (1.0, 1.0, 1.0),
|
||||
line_width: float = 1.0,
|
||||
name: Optional[str] = None,
|
||||
) -> PygfxRenderObject:
|
||||
"""Add line segments to the scene."""
|
||||
) -> str:
|
||||
"""Add line segments to the scene. Returns the lines ID."""
|
||||
import pygfx as gfx
|
||||
import uuid
|
||||
|
||||
positions = np.hstack([start_points, end_points]).flatten()
|
||||
positions = positions.reshape(-1, 3).astype(np.float32)
|
||||
@@ -249,11 +269,14 @@ class PygfxRenderer(Renderer):
|
||||
lines = gfx.Line(geometry, material)
|
||||
self._scene.add(lines)
|
||||
|
||||
obj = PygfxRenderObject(name=name, scene_node=lines, geometry=geometry, material=material)
|
||||
lines_id = name or f"lines_{uuid.uuid4().hex[:8]}"
|
||||
obj = PygfxRenderObject(
|
||||
name=lines_id, scene_node=lines, geometry=geometry, material=material
|
||||
)
|
||||
obj.color = RenderColor(*color)
|
||||
self._objects.append(obj)
|
||||
|
||||
return obj
|
||||
return lines_id
|
||||
|
||||
def remove_object(self, obj: RenderObject) -> bool:
|
||||
"""Remove an object from the scene."""
|
||||
@@ -319,15 +342,14 @@ class PygfxRenderer(Renderer):
|
||||
up: Tuple[float, float, float] = (0, 0, 1),
|
||||
) -> None:
|
||||
"""Set camera position and orientation."""
|
||||
self._camera.position.set(*position)
|
||||
self._camera.look_at(*target)
|
||||
self._camera.up.set(*up)
|
||||
self._camera.local.position = position
|
||||
self._camera.look_at(target)
|
||||
|
||||
def get_camera_position(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
||||
"""Get camera position, target, and up vector."""
|
||||
pos = np.array(self._camera.position.to_array())
|
||||
pos = np.array(self._camera.local.position)
|
||||
target = np.array([0, 0, 0])
|
||||
up = np.array(self._camera.up.to_array())
|
||||
up = np.array(self._camera.local.up)
|
||||
return pos, target, up
|
||||
|
||||
def fit_camera(self, padding: float = 1.1) -> None:
|
||||
@@ -348,8 +370,8 @@ class PygfxRenderer(Renderer):
|
||||
center = (min_pos + max_pos) / 2
|
||||
size = np.linalg.norm(max_pos - min_pos) * padding
|
||||
|
||||
self._camera.position.set(center[0] + size, center[1] + size, center[2] + size)
|
||||
self._camera.look_at(*center)
|
||||
self._camera.local.position = (center[0] + size, center[1] + size, center[2] + size)
|
||||
self._camera.look_at(tuple(center))
|
||||
|
||||
def set_camera_perspective(
|
||||
self, fov: float = 50.0, near: float = 0.1, far: float = 10000.0
|
||||
@@ -392,8 +414,8 @@ class PygfxRenderer(Renderer):
|
||||
size: float = 100.0,
|
||||
divisions: int = 10,
|
||||
color: Tuple[float, float, float] = (0.3, 0.3, 0.3),
|
||||
) -> PygfxRenderObject:
|
||||
"""Add a reference grid."""
|
||||
) -> str:
|
||||
"""Add a reference grid. Returns the grid ID."""
|
||||
import pygfx as gfx
|
||||
|
||||
grid = gfx.GridHelper(
|
||||
@@ -402,10 +424,11 @@ class PygfxRenderer(Renderer):
|
||||
self._scene.add(grid)
|
||||
|
||||
obj = PygfxRenderObject(name="grid", scene_node=grid)
|
||||
return obj
|
||||
self._objects.append(obj)
|
||||
return "grid"
|
||||
|
||||
def add_axes(self, size: float = 10.0, visible: bool = True) -> PygfxRenderObject:
|
||||
"""Add coordinate axes."""
|
||||
def add_axes(self, size: float = 10.0, visible: bool = True) -> str:
|
||||
"""Add coordinate axes. Returns the axes ID."""
|
||||
import pygfx as gfx
|
||||
|
||||
axes = gfx.AxesHelper(size=size)
|
||||
@@ -413,7 +436,8 @@ class PygfxRenderer(Renderer):
|
||||
self._scene.add(axes)
|
||||
|
||||
obj = PygfxRenderObject(name="axes", scene_node=axes)
|
||||
return obj
|
||||
self._objects.append(obj)
|
||||
return "axes"
|
||||
|
||||
def get_screen_size(self) -> Tuple[int, int]:
|
||||
"""Get the screen size in pixels."""
|
||||
|
||||
Reference in New Issue
Block a user