04.01 接入渲染引擎

从 PyVista 到课程渲染引擎

本节先认识 PyVista 的三维渲染能力,再结合 Python 中“类型”的定义,把视口配置封装成 `RenderEngine`,最后用它统一渲染点、线、面和实体。

PyVista Plotter 视口控制 Python 类型 点线面体
为什么需要渲染引擎

几何计算必须能被看见

点、向量、线、面、体如果只停留在数字里,学生很难判断几何关系是否正确。渲染引擎让工程对象进入可检查的三维视口。

后续坐标系、投影、相交、布尔和碰撞检测,都需要一个统一的观察窗口。
Camera
X / Y / Z 坐标轴
工程构件
观察视角
PyVista 的渲染功能

它能把几何数据变成可观察的三维画面

PyVista 是 VTK 的 Python 友好封装。对本课程最重要的是:它能渲染点、线、面片、网格实体,并提供可旋转、可缩放、可截图的三维视口。

用 `PolyData` 或点云显示坐标位置。

线

用 `Line` 或 polyline 表达路径和边。

用 `Plane`、网格面片表达平面区域。

实体

用 `Cube`、STL、mesh 显示构件外形。

安装与验证

先确认 PyVista 能正常导入

如果 `import pyvista` 失败,后面的渲染代码都无法运行。安装后先打印版本,再创建一个最小窗口。

# 安装
pip install pyvista

# 验证
import pyvista as pv

print(pv.__version__)
cube = pv.Cube()
print(cube.n_points, cube.n_cells)
PyVista 渲染流程

先有几何数据,再交给 Plotter 显示

`pv.Plotter()` 是 PyVista 的视口对象。它负责接收几何数据、设置显示样式、控制相机,并打开可交互窗口。

1创建点、线、面或实体数据
2调用 `plotter.add_mesh()` 加入视口
3配置背景、坐标轴、网格和相机
4调用 `plotter.show()` 打开交互窗口
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 类型

类型是一种对象模板

在 Python 中,`class` 用来定义类型。类型把“数据”和“能做的动作”放在一起:数据叫属性,动作叫方法。

渲染引擎需要保存一个视口,并持续向这个视口添加对象,所以它适合定义成一个类型。

属性

`self.plotter` 保存 PyVista 视口。

方法

`render_point()`、`add_mesh()` 执行渲染动作。

对象

`engine = RenderEngine()` 得到一个可使用的引擎。

类型职责

RenderEngine 只负责一件事:管理课程视口

这个类型不负责计算几何,也不负责生成构件。它只把 PyVista 的视口配置、鼠标操作、对象加入和窗口显示封装起来。

1`__init__` 创建并配置 `pv.Plotter`
2`render_point()` 渲染坐标点
3`render_curve()` 渲染线或折线
4`add_mesh()` 接收面、实体和其他 mesh
定义 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)
渲染面和实体

面和实体统一按 mesh 加入视口

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 是默认交互风格,也可以显式启用。它让鼠标移动的是相机,几何对象本身保持不变。

左键旋转,滚轮或右键缩放,中键或 Shift+左键平移。
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 安装、显卡驱动、远程环境和是否需要离屏渲染。

排查顺序

  1. `import pyvista as pv` 是否成功。
  2. `pv.Cube()` 是否能创建对象。
  3. 本机是否支持 OpenGL 图形窗口。
  4. 远程服务器上是否需要 `off_screen=True`。
  5. 先用截图输出替代交互窗口。
本节收束

渲染引擎是后续几何课程的观察窗口

本节完成了 PyVista 的基本接入,并借此引入类型、对象、方法和类型标注。下一步就可以把点、线、面、实体放进这个统一视口中观察。

课堂练习:用 `RenderEngine` 同时加入一个柱、一个梁、一个点和一条曲线。

最小作业

  • 运行 `import pyvista as pv`。
  • 创建 `RenderEngine` 类型。
  • 渲染一个 `pv.Plane()` 和一个 `pv.Cube()`。
  • 调用 `render_point()`、`render_curve()` 和 `add_mesh()`。
  • 用鼠标旋转、平移、缩放视口。