多面体

多面体(Polyhedron)是 3D 几何的一个子家族:与 Surface 的参数化网格不同,多面体由顶点坐标 + 面索引显式定义,因此棱角分明、可以精确控制每个面。

Polyhedron

Polyhedron(vertex_coords, faces_list, faces_config={}, graph_config={}) 官方文档 ↗

多面体的通用基类:传入顶点列表和面列表即可构造任意凸多面体。

Polyhedron(
    vertex_coords: Point3DLike_Array,
    faces_list: list[list[int]],
    faces_config: dict[str, str | int | float | bool] = {},
    graph_config: dict[str, Any] = {},
)

digraph G { graph [rankdir=LR, bgcolor="transparent", nodesep="0.25", ranksep="0.35"]; node [shape=box, style="rounded,filled", fontname="Helvetica,sans-serif", fontsize=11, height=0.3, color="#8b93a1", fillcolor="#f2f4f7", fontcolor="#1f2733"]; edge [color="#a6adba", arrowsize=0.6, penwidth=1.1]; "Polyhedron" -> "VGroup"; "VGroup" -> "VMobject"; "VMobject" -> "Mobject"; }

name

type

default

desc

vertex_coords

Point3DLike_Array

—

顶点三维坐标数组

faces_list

list[list[int]]

—

每个面是顶点索引的列表

faces_config

dict

{}

传入每个面片的样式(fill_color、stroke_color 等)

graph_config

dict

{}

顶点/边图的样式配置

构造后可以通过 polyhedron.graph 访问顶点与边的 VGroup。一个手写四面体的例子:

tetra = Polyhedron(
    vertex_coords=[
        [1, 1, 1], [1, -1, -1],
        [-1, 1, -1], [-1, -1, 1],
    ],
    faces_list=[
        [0, 1, 2], [0, 1, 3],
        [0, 2, 3], [1, 2, 3],
    ],
)

实际使用中你很少需要手写坐标——四个正多面体子类直接用 edge_length 构造。

Tetrahedron

Tetrahedron(edge_length=1, **kwargs) 官方文档 ↗

正四面体(4 个面)。

Tetrahedron(edge_length: float = 1, **kwargs)

Octahedron

Octahedron(edge_length=1, **kwargs) 官方文档 ↗

正八面体(8 个面)。

Octahedron(edge_length: float = 1, **kwargs)

Icosahedron

Icosahedron(edge_length=1, **kwargs) 官方文档 ↗

正二十面体(20 个面)。

Icosahedron(edge_length: float = 1, **kwargs)

Dodecahedron

Dodecahedron(edge_length=1, **kwargs) 官方文档 ↗

正十二面体(12 个面)。

Dodecahedron(edge_length: float = 1, **kwargs)

四种正多面体排成一排并缓慢环绕。它们都只收一个 edge_length 参数,其余样式经 faces_config / graph_config 传入父类 Polyhedron。

查看源码 polyhedra_showcase.py
from manim import *


class PolyhedraShowcase(ThreeDScene):
    def construct(self):
        solids = VGroup(
            Tetrahedron(edge_length=1.4),
            Octahedron(edge_length=1.4),
            Icosahedron(edge_length=1.4),
            Dodecahedron(edge_length=1.2),
        )
        solids.arrange(RIGHT, buff=0.6)
        self.set_camera_orientation(phi=65 * DEGREES, theta=-45 * DEGREES)
        self.play(FadeIn(solids), run_time=2)
        self.begin_ambient_camera_rotation(rate=0.5)
        self.wait(2)
        self.stop_ambient_camera_rotation()

四种正多面体的对比:

类

面数

顶点数

构造参数

Tetrahedron

4

4

edge_length

Octahedron

8

6

edge_length

Icosahedron

20

12

edge_length

Dodecahedron

12

20

edge_length

提示

正多面体里没有“正方体”——立方体(6 个正方形面)在 Manim 中属于 3D 几何家族,直接用上一节的 Cube。

ConvexHull3D

ConvexHull3D(*points, tolerance=1e-05, **kwargs) 官方文档 ↗

凸包多面体:给一组 3D 点,自动计算凸包并生成对应的多面体。

ConvexHull3D(*points: Point3D, tolerance: float = 1e-5, **kwargs)

digraph G { graph [rankdir=LR, bgcolor="transparent", nodesep="0.25", ranksep="0.35"]; node [shape=box, style="rounded,filled", fontname="Helvetica,sans-serif", fontsize=11, height=0.3, color="#8b93a1", fillcolor="#f2f4f7", fontcolor="#1f2733"]; edge [color="#a6adba", arrowsize=0.6, penwidth=1.1]; "ConvexHull3D" -> "Polyhedron"; "Polyhedron" -> "VGroup"; }

name

type

default

desc

*points

Point3D

—

任意多个三维点(至少 4 个不共面点)

tolerance

float

1e-5

数值容差,决定多少个点被视为共面

12 个随机点先用 Dot3D 标出,ConvexHull3D(*points) 自动求出包住所有点的最小凸多面体。示例用 np.random.default_rng(0) 固定随机种子,保证每次渲染结果一致。

查看源码 convex_hull_3d.py
from manim import *


class ConvexHullDemo(ThreeDScene):
    def construct(self):
        rng = np.random.default_rng(0)
        points = [rng.uniform(-2.5, 2.5, 3) for _ in range(12)]
        dots = VGroup(*[Dot3D(p, radius=0.06, color=YELLOW) for p in points])
        hull = ConvexHull3D(*points)
        self.set_camera_orientation(phi=70 * DEGREES, theta=-60 * DEGREES)
        self.play(FadeIn(dots), run_time=1)
        self.play(Create(hull), run_time=2)
        self.wait(1)

常见错误与建议

常见错误

ConvexHull3D 要求点不全部共面;只给 3 个或更少的点、或所有点共面时会构造失败或得到退化结果。另外它求的是凸包——凹陷形状(如杯子)的轮廓会被凸包“填平”。

常见错误

faces_list 中的是顶点索引(从 0 起),不是坐标;索引越界或面没有按一致方向(逆时针/顺时针)给出时,面的法线与着色可能不符合预期。

提示

想高亮某个面,可在 faces_config 中传样式,或构造后直接操作多面体子对象;polyhedron.graph 里的点、边也都可以单独着色。

版本说明

本节签名基于 manim 0.21.0 本机 inspect 核实(ConvexHull3D(*points, tolerance=1e-5))。

自测

✏️ 练习

手头的点云可能包含噪声离群点,直接用 ConvexHull3D(*points) 会怎样?有什么简单的替代思路?

✅ 参考答案

凸包对离群点非常敏感:一个远离主体的点会把整个多面体拉扯变形。简单思路是先做去噪/筛选(例如去掉远离中心的点、限制 z 分数,或用 tolerance 调大容差合并近似共面的点),再求凸包。

✏️ 练习

想画一个“房子”形状(立方体 + 四棱锥屋顶)作为一个整体移动,有哪些做法?

✅ 参考答案

两种思路:一是把 Cube 与 Polyhedron(手写屋顶顶点/面)放进同一个 VGroup,统一变换;二是直接用 Polyhedron 手写完整顶点与面列表一次成型。前者更简单,后者在需要单一样式/单个整体多面体时更合适。

下一步

3D 内容到此为止。接下来回到摄像机本身:下一节讲 MovingCameraScene——在 2D 世界里平移、缩放摄像机的标准做法。