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