3D 几何¶
Manim 的 3D 几何体全部可以用 Cairo 渲染器绘制(伪 3D 投影 + 着色),无需 OpenGL。它们分两个家族:由 Surface 参数化生成的曲面家族,以及由面片拼成的多面体家族(多面体在下一节专门介绍)。
先看最常用的六个实体:
六个基本实体一字排开:Cube、Sphere、Cone、Cylinder、Torus、Prism。默认角度下它们看起来像压扁的 2D 图形,配合 set_camera_orientation 才有立体感。
查看源码 three_d_solids.py
from manim import *
class ThreeDSolids(ThreeDScene):
def construct(self):
solids = VGroup(
Cube(),
Sphere(),
Cone(),
Cylinder(),
Torus(major_radius=1, minor_radius=0.35),
Prism(dimensions=[1.5, 1.0, 0.8]),
)
solids.arrange(RIGHT, buff=0.8)
self.set_camera_orientation(phi=70 * DEGREES, theta=-60 * DEGREES)
self.play(FadeIn(solids), run_time=2)
self.begin_ambient_camera_rotation(rate=0.4)
self.wait(2)
self.stop_ambient_camera_rotation()
Cone¶
Cone(base_radius=1, height=1, direction=array([0., 0., 1.]), show_base=False, v_range=(0, 6.283185307179586), u_min=0, checkerboard_colors=False, **kwargs) 官方文档 ↗
圆锥面(侧面为参数化曲面,默认无底面)。
Cone(
base_radius: float = 1,
height: float = 1,
direction: Vector3DLike = Z_AXIS,
show_base: bool = False,
v_range: tuple[float, float] = (0, 2*PI),
u_min: float = 0,
checkerboard_colors=False,
**kwargs,
)
name |
type |
default |
desc |
|---|---|---|---|
|
float |
1 |
底面半径 |
|
float |
1 |
高 |
|
Vector3DLike |
[0,0,1] |
锥体朝向,默认沿 Z 轴 |
|
bool |
False |
是否显示底面圆盘 |
Cube¶
Cube(side_length=2, fill_opacity=0.75, fill_color=ManimColor('#58C4DD'), stroke_width=0, **kwargs) 官方文档 ↗
立方体,由 6 个正方形面片组成(因此是 VGroup,见下文 Prism)。
Cube(
side_length: float = 2,
fill_opacity: float = 0.75,
fill_color: ParsableManimColor = "#58C4DD",
stroke_width: float = 0,
**kwargs,
)
Cylinder¶
Cylinder(radius=1, height=2, direction=array([0., 0., 1.]), v_range=(0, 6.283185307179586), show_ends=True, resolution=(24, 24), **kwargs) 官方文档 ↗
圆柱面。
Cylinder(
radius: float = 1,
height: float = 2,
direction: Vector3DLike = Z_AXIS,
v_range: tuple[float, float] = (0, 2*PI),
show_ends: bool = True,
resolution: int | tuple[int, int] = (24, 24),
**kwargs,
)
name |
type |
default |
desc |
|---|---|---|---|
|
float |
1 |
半径 |
|
float |
2 |
高 |
|
Vector3DLike |
[0,0,1] |
轴向 |
|
bool |
True |
是否封闭上下底 |
|
int | tuple |
(24, 24) |
网格分辨率 |
Sphere¶
Sphere(center=array([0., 0., 0.]), radius=1, resolution=None, u_range=(0, 6.283185307179586), v_range=(0, 3.141592653589793), **kwargs) 官方文档 ↗
球面。
Sphere(
center: Point3DLike = ORIGIN,
radius: float = 1,
resolution: int | Sequence[int] | None = None,
u_range: tuple[float, float] = (0, 2*PI),
v_range: tuple[float, float] = (0, PI),
**kwargs,
)
name |
type |
default |
desc |
|---|---|---|---|
|
Point3DLike |
ORIGIN |
球心 |
|
float |
1 |
半径 |
|
int | Sequence | None |
None |
网格分辨率,None 时取配置默认值 |
Torus¶
Torus(major_radius=3, minor_radius=1, u_range=(0, 6.283185307179586), v_range=(0, 6.283185307179586), resolution=None, **kwargs) 官方文档 ↗
圆环面(救生圈形状)。
Torus(
major_radius: float = 3,
minor_radius: float = 1,
u_range: tuple[float, float] = (0, 2*PI),
v_range: tuple[float, float] = (0, 2*PI),
resolution: int | tuple[int, int] | None = None,
**kwargs,
)
name |
type |
default |
desc |
|---|---|---|---|
|
float |
3 |
中心到管中心的距离 |
|
float |
1 |
管半径 |
提示
Torus 默认 major_radius=3,在小场景中显得很大,演示时通常显式传 Torus(major_radius=1, minor_radius=0.4) 之类的值。
Prism¶
Prism(dimensions=[3, 2, 1], **kwargs) 官方文档 ↗
长方体(矩形棱柱),继承 Cube。
Prism(dimensions: Vector3DLike = [3, 2, 1], **kwargs)
dimensions 是 [宽, 高, 深] 三个方向的长度。Prism([2, 2, 2]) 等价于 Cube(side_length=2)。
Dot3D¶
Dot3D(point=array([0., 0., 0.]), radius=0.08, color=ManimColor('#FFFFFF'), resolution=(8, 8), **kwargs) 官方文档 ↗
3D 点:一个极小的球。
Dot3D(
point: Point3D = ORIGIN,
radius: float = 0.08,
color: ParsableManimColor = WHITE,
resolution: int | tuple[int, int] | None = (8, 8),
**kwargs,
)
Line3D¶
Line3D(start=array([-1., 0., 0.]), end=array([1., 0., 0.]), thickness=0.02, color=None, resolution=24, **kwargs) 官方文档 ↗
3D 线段:一根很细的圆柱。
Line3D(
start: Point3DLike = [-1, 0, 0],
end: Point3DLike = [1, 0, 0],
thickness: float = 0.02,
color: ParsableManimColor | None = None,
resolution: int | tuple[int, int] = 24,
**kwargs,
)
Arrow3D¶
Arrow3D(start=array([-1., 0., 0.]), end=array([1., 0., 0.]), thickness=0.02, height=0.3, base_radius=0.08, color=ManimColor('#FFFFFF'), resolution=24, **kwargs) 官方文档 ↗
3D 箭头:细圆柱 + 圆锥头。
Arrow3D(
start: Point3DLike = [-1, 0, 0],
end: Point3DLike = [1, 0, 0],
thickness: float = 0.02,
height: float = 0.3,
base_radius: float = 0.08,
color: ParsableManimColor = WHITE,
resolution: int | tuple[int, int] = 24,
**kwargs,
)
下面这个示例把 Line3D、Arrow3D、Dot3D 和自定义 Surface 放在一起:
saddle(u, v) 返回 [u, v, 0.5*u*v] 定义一张马鞍面;Line3D/Arrow3D 本质上是细圆柱,所以它们继承 Cylinder 的参数。
查看源码 three_d_lines_surface.py
from manim import *
class ThreeDLinesAndSurface(ThreeDScene):
def construct(self):
line = Line3D(ORIGIN, [2, 2, 2])
arrow = Arrow3D([-2.5, 0, 0], [-2.5, 0, 2])
dot = Dot3D([2, -1.5, 1], color=YELLOW)
def saddle(u, v):
return np.array([u, v, 0.5 * u * v])
surface = Surface(
saddle,
u_range=(-2, 2),
v_range=(-2, 2),
resolution=(16, 16),
)
self.set_camera_orientation(phi=60 * DEGREES, theta=-45 * DEGREES)
self.play(Create(line), Create(arrow), FadeIn(dot), run_time=1)
self.play(Create(surface), run_time=2)
self.wait(0.5)
self.move_camera(theta=20 * DEGREES, run_time=1)
Surface¶
Surface(func, u_range=(0, 1), v_range=(0, 1), resolution=32, surface_piece_config={}, fill_color=ManimColor('#29ABCA'), fill_opacity=1.0, checkerboard_colors=[ManimColor('#29ABCA'…, stroke_color=ManimColor('#BBBBBB'), stroke_width=0.5, should_make_jagged=False, pre_function_handle_to_anchor_scale_factor=1e-05, **kwargs) 官方文档 ↗
一切参数化 3D 曲面的基类:给一个 (u, v) -> [x, y, z] 函数,再指定参数范围和网格分辨率,Manim 把它切成小面片拼出来。
Surface(
func: Callable[[float, float], np.ndarray],
u_range: tuple[float, float] = (0, 1),
v_range: tuple[float, float] = (0, 1),
resolution: int | Sequence[int] = 32,
surface_piece_config: dict = {},
fill_color: ParsableManimColor = BLUE_D,
fill_opacity: float = 1.0,
checkerboard_colors=[BLUE_D, BLUE_E],
stroke_color: ParsableManimColor = LIGHT_GREY,
stroke_width: float = 0.5,
should_make_jagged: bool = False,
pre_function_handle_to_anchor_scale_factor: float = 1e-5,
**kwargs,
)
name |
type |
default |
desc |
|---|---|---|---|
|
Callable |
— |
参数化函数 |
|
tuple[float, float] |
(0, 1) |
u 参数范围 |
|
tuple[float, float] |
(0, 1) |
v 参数范围 |
|
int | Sequence |
32 |
每维网格份数,越高越平滑越慢 |
|
Iterable | False |
[BLUE_D, BLUE_E] |
棋盘格双色;传 False 关闭 |
|
bool |
False |
是否让面片边缘锯齿化(着色更硬) |
注意继承关系:Surface 不是 VMobject 的直接子类,而是 VGroup——每个小面片是 ThreeDVMobject,整个曲面是面片的组合。因此可以用 VGroup 的所有方法(arrange、scale 等)操作曲面。
ThreeDVMobject¶
ThreeDVMobject(shade_in_3d=True, **kwargs) 官方文档 ↗
单个 3D 面片(Surface 的内部组成单元),也可单独用于自定义 3D 图形。
ThreeDVMobject(shade_in_3d: bool = True, **kwargs)
shade_in_3d=True 时按 3D 法线方向参与光照着色;设 False 则按普通 2D 图形平涂。
常用类对比¶
类 |
继承 |
一句话用途 |
关键参数 |
|---|---|---|---|
|
Surface → VGroup |
球面 |
|
|
Surface → VGroup |
圆锥 |
|
|
Surface → VGroup |
圆柱 |
|
|
Surface → VGroup |
圆环 |
|
|
VGroup |
立方体 |
|
|
Cube → VGroup |
长方体 |
|
|
Sphere → Surface |
3D 点 |
|
|
Cylinder → Surface |
3D 线段 |
|
|
Line3D → Cylinder |
3D 箭头 |
|
常见错误与建议¶
常见错误
不要用 2D 的 Line/Arrow 在 3D 场景里连接两个 z 坐标不同的点——它们只画 XY 平面的投影。跨深度的连线请用 Line3D/Arrow3D。
常见错误
Surface 的 func 必须返回长度为 3 的 np.ndarray(如 np.array([u, v, u*v]))。返回 list 或形状不对会在构造时直接报错。
提示
resolution 是渲染速度的主要开关。-ql 下调低分辨率(如 (8, 8))调试,出正式片再恢复 (32, 32) 或更高。
版本说明
本节签名与默认值均基于 manim 0.21.0 本机 inspect 核实(如 Sphere 有 center 参数、Surface 直接继承 VGroup)。
自测¶
✏️ 练习
想画一张高度为 z = sin(x) + cos(y)、范围 x,y∈[-2,2] 的曲面,该怎么写?
✅ 参考答案
用 Surface 显式写出参数化函数:
def func(u, v):
return np.array([u, v, np.sin(u) + np.cos(v)])
surface = Surface(func, u_range=(-2, 2), v_range=(-2, 2), resolution=(24, 24))
✏️ 练习
Cube 是 VMobject 吗?solids.arrange(RIGHT) 为什么能直接用在六个不同类型的实体组合上?
✅ 参考答案
Cube 直接继承 VGroup(再由 VGroup → VMobject),而 Cone/Sphere 等经 Surface 也继承 VGroup。因此所有 3D 实体都具有 VGroup/Mobject 的变换与布局方法,可以放进同一个 VGroup 后统一 arrange。
下一步¶
基本 3D 几何体已经齐备。下一节看多面体家族:正多面体、任意自定义多面体,以及从点集自动求凸包的 ConvexHull3D。