从 PyVista 到课程渲染引擎
本节先认识 PyVista 的三维渲染能力,再结合 Python 中“类型”的定义,把视口配置封装成 `RenderEngine`,最后用它统一渲染点、线、面和实体。
本节先认识 PyVista 的三维渲染能力,再结合 Python 中“类型”的定义,把视口配置封装成 `RenderEngine`,最后用它统一渲染点、线、面和实体。
点、向量、线、面、体如果只停留在数字里,学生很难判断几何关系是否正确。渲染引擎让工程对象进入可检查的三维视口。
PyVista 是 VTK 的 Python 友好封装。对本课程最重要的是:它能渲染点、线、面片、网格实体,并提供可旋转、可缩放、可截图的三维视口。
用 `PolyData` 或点云显示坐标位置。
用 `Line` 或 polyline 表达路径和边。
用 `Plane`、网格面片表达平面区域。
用 `Cube`、STL、mesh 显示构件外形。
如果 `import pyvista` 失败,后面的渲染代码都无法运行。安装后先打印版本,再创建一个最小窗口。
# 安装
pip install pyvista
# 验证
import pyvista as pv
print(pv.__version__)
cube = pv.Cube()
print(cube.n_points, cube.n_cells)
`pv.Plotter()` 是 PyVista 的视口对象。它负责接收几何数据、设置显示样式、控制相机,并打开可交互窗口。
在封装引擎之前,先看 PyVista 原生写法。问题是:如果每节课都重复这些配置,代码会越来越散。
import pyvista as pv
point = pv.PolyData([(0, 0, 0)])
line = pv.Line((0, 0, 0), (6000, 0, 0))
plane = pv.Plane(i_size=6000, j_size=3000)
solid = pv.Cube(x_length=6000, y_length=300, z_length=600)
plotter = pv.Plotter()
plotter.add_mesh(point, color="coral", point_size=14)
plotter.add_mesh(line, color="steelblue", line_width=5)
plotter.add_mesh(plane, color="lightblue", opacity=0.35)
plotter.add_mesh(solid, color="tan", show_edges=True)
plotter.add_axes()
plotter.show()
背景色、窗口大小、坐标轴、网格、相机位置都应该统一。这样每节课的截图、演示和几何判断有一致的视觉语境。
plotter = pv.Plotter(window_size=(1200, 800))
plotter.set_background("white")
plotter.add_axes()
plotter.show_grid(
color="lightgray",
grid="back",
location="outer",
)
plotter.camera_position = "iso"
在 Python 中,`class` 用来定义类型。类型把“数据”和“能做的动作”放在一起:数据叫属性,动作叫方法。
`self.plotter` 保存 PyVista 视口。
`render_point()`、`add_mesh()` 执行渲染动作。
`engine = RenderEngine()` 得到一个可使用的引擎。
这个类型不负责计算几何,也不负责生成构件。它只把 PyVista 的视口配置、鼠标操作、对象加入和窗口显示封装起来。
`__init__()` 会在创建对象时自动运行。这里把窗口大小、背景、坐标轴、网格、相机和鼠标操作一次性配置好。
import pyvista as pv
class RenderEngine:
def __init__(
self,
window_size: tuple[int, int] = (1200, 800),
background: str = "white",
) -> None:
self.plotter = pv.Plotter(window_size=window_size)
self.plotter.set_background(background)
self.plotter.add_axes()
self.plotter.show_grid(color="lightgray")
self.plotter.camera_position = "iso"
self.plotter.enable_trackball_style()
方法的第一个参数通常是 `self`。它代表当前这个引擎对象,因此方法可以直接使用 `self.plotter` 把几何数据放入同一个视口。
class RenderEngine:
...
def add_mesh(
self,
mesh: pv.DataSet,
color: str = "tan",
show_edges: bool = True,
opacity: float = 1.0,
) -> None:
self.plotter.add_mesh(
mesh,
color=color,
show_edges=show_edges,
opacity=opacity,
)
def show(self) -> None:
self.plotter.reset_camera()
self.plotter.show()
点用坐标三元组表示,线可以用两个端点或多个点组成的折线表示。封装后,学生只需要关注几何数据本身。
class RenderEngine:
...
def render_point(self, point, color="coral") -> None:
cloud = pv.PolyData([point])
self.plotter.add_mesh(
cloud,
color=color,
point_size=14,
render_points_as_spheres=True,
)
def render_curve(self, points, color="steelblue") -> None:
polyline = pv.PolyData(points)
polyline.lines = [len(points), *range(len(points))]
self.plotter.add_mesh(polyline, color=color, line_width=5)
PyVista 中的 `Plane`、`Cube`、STL 读取结果都可以作为 mesh 处理。课程引擎只需要提供稳定的 `add_mesh()` 入口。
engine = RenderEngine()
surface = pv.Plane(
center=(3000, 0, 0),
i_size=6000,
j_size=3000,
)
solid = pv.Cube(
center=(3000, 0, 300),
x_length=6000,
y_length=300,
z_length=600,
)
engine.add_mesh(surface, color="lightblue", opacity=0.35)
engine.add_mesh(solid, color="tan", show_edges=True)
engine.show()
最终课堂目标不是记住 PyVista 的每个细节,而是形成稳定调用方式:创建引擎,准备几何数据,把对象加入视口,然后观察。
engine = RenderEngine()
engine.render_point((0, 0, 0), color="coral")
engine.render_curve([
(0, 0, 0),
(3000, 0, 0),
(6000, 1200, 0),
])
engine.add_mesh(surface, color="lightblue", opacity=0.35)
engine.add_mesh(solid, color="tan", show_edges=True)
engine.show()
PyVista 的 trackball camera 是默认交互风格,也可以显式启用。它让鼠标移动的是相机,几何对象本身保持不变。
class RenderEngine:
def configure_mouse(self) -> None:
self.plotter.enable_trackball_style()
def show_controls(self) -> None:
print("Left drag: rotate")
print("Middle drag / Shift+Left: pan")
print("Wheel / Right drag: zoom")
engine = RenderEngine()
engine.show_controls()
三维渲染依赖图形环境。如果窗口黑屏、打不开或卡住,先确认 PyVista 安装、显卡驱动、远程环境和是否需要离屏渲染。
本节完成了 PyVista 的基本接入,并借此引入类型、对象、方法和类型标注。下一步就可以把点、线、面、实体放进这个统一视口中观察。