VMobject¶
VMobject(Vectorized Mobject,矢量对象)在 Mobject 的基础上增加了矢量渲染所需的填充、描边与光泽等样式。绝大多数二维图形(圆、多边形、曲线、文字轮廓)都是它的子孙。
VMobject¶
VMobject(fill_color=None, fill_opacity=0.0, stroke_color=None, stroke_opacity=1.0, stroke_width=4, background_stroke_color=ManimColor('#000000'), background_stroke_opacity=1.0, background_stroke_width=0, sheen_factor=0.0, joint_type=None, sheen_direction=array([-1., 1., 0.]), close_new_points=False, pre_function_handle_to_anchor_scale_factor=0.01, make_smooth_after_applying_functions=False, background_image=None, shade_in_3d=False, tolerance_for_point_equality=1e-06, n_points_per_cubic_curve=4, cap_style=<CapStyleType.AUTO: 0>, **kwargs) 官方文档 ↗
VMobject 是矢量图形的基类:它用一系列三次贝塞尔曲线(锚点 + 控制点)描述轮廓,渲染时按**填充(fill)→ 背景描边(background stroke)→ 描边(stroke)**的顺序绘制。
VMobject(
fill_color=None, fill_opacity=0.0,
stroke_color=None, stroke_opacity=1.0, stroke_width=4,
background_stroke_color=BLACK, background_stroke_opacity=1.0,
background_stroke_width=0,
sheen_factor=0.0, sheen_direction=(-1, 1, 0),
close_new_points=False, cap_style=CapStyleType.AUTO,
**kwargs,
)
name |
type |
default |
desc |
|---|---|---|---|
|
ParsableManimColor | None |
None |
填充色;None 时跟随 |
|
float |
0.0 |
填充不透明度,默认 0 即不填充 |
|
ParsableManimColor | None |
None |
描边色;None 时跟随 |
|
float |
1.0 |
描边不透明度 |
|
float |
4 |
描边宽度 |
|
ParsableManimColor | None |
BLACK |
背景描边颜色(垫在填充下面) |
|
float |
1.0 |
背景描边不透明度 |
|
float |
0 |
背景描边宽度,默认 0 即关闭 |
|
float |
0.0 |
光泽强度:颜色向白色渐变的程度 |
|
Vector3DLike |
(-1, 1, 0) |
光泽渐变方向 |
|
bool |
False |
新增的点是否自动闭合成环 |
|
CapStyleType |
AUTO |
开放曲线端点的样式(AUTO/BUTT/ROUND/SQUARE) |
与 Mobject 相比,VMobject 增加了三个核心样式方法:
方法 |
签名 |
说明 |
|---|---|---|
|
|
设置填充色与不透明度; |
|
|
设置描边; |
|
|
同时设置填充与描边的不透明度 |
三个对象的填充/描边对比:
左:仅填充(描边宽 0);中:仅描边(填充透明);右:半透明填充 + 细描边。最后一帧整组 set_opacity(0.4) 一起变淡。
查看源码 vmobject_styles.py
from manim import *
class VMobjectStyles(Scene):
def construct(self):
fill_only = Square().set_fill(YELLOW, opacity=0.8).set_stroke(width=0)
stroke_only = Circle().set_fill(opacity=0).set_stroke(BLUE, width=8)
faded = RoundedRectangle().set_fill(RED, opacity=0.4).set_stroke(WHITE, width=2)
group = VGroup(fill_only, stroke_only, faded).arrange(RIGHT, buff=0.6)
self.play(FadeIn(group))
self.play(group.animate.set_opacity(0.4))
self.wait(0.5)
常见错误
set_fill(BLUE) 只会改颜色,不会让图形填上颜色——默认 fill_opacity 仍是 0。要看到填充必须给不透明度,如 set_fill(BLUE, opacity=0.7),或构造时传 fill_opacity=0.7。
提示
background_stroke 常用来给文字或细线在复杂背景上“描白边”垫底:设置 background_stroke_color=BLACK, background_stroke_width=8 即可。
DashedVMobject¶
DashedVMobject(vmobject, num_dashes=15, dashed_ratio=0.5, dash_offset=0, color=ManimColor('#FFFFFF'), equal_lengths=True, **kwargs) 官方文档 ↗
DashedVMobject 把任意 VMobject 转换成等长的虚线段集合,原对象不会被修改(内部使用拷贝)。
DashedVMobject(
vmobject: VMobject,
num_dashes: int = 15,
dashed_ratio: float = 0.5,
dash_offset: float = 0,
color: ManimColor = WHITE,
equal_lengths: bool = True,
**kwargs,
)
name |
type |
default |
desc |
|---|---|---|---|
|
VMobject |
— |
要虚线化的对象(必填) |
|
int |
15 |
虚线段数量 |
|
float |
0.5 |
虚线总长度占整个轮廓的比例(0~1) |
|
float |
0 |
虚线相位偏移(按 0~1 的周期比例) |
|
ManimColor |
WHITE |
虚线颜色 |
|
bool |
True |
是否强制每段等长;曲线弯折处建议保持 True |
上半部分:Circle 经 DashedVMobject 变成 20 段虚线;下半部分:CurvesAsSubmobjects 把正弦曲线拆成子对象后按蓝→红渐变着色。
查看源码 dashed_demo.py
from manim import *
class DashedDemo(Scene):
def construct(self):
circle = Circle()
dashed = DashedVMobject(
circle, num_dashes=20, dashed_ratio=0.4, color=YELLOW
).shift(1.5 * UP)
self.play(Create(dashed))
curve = ParametricFunction(
lambda t: [t, np.sin(2 * t), 0], t_range=[-PI, PI, 0.02]
).shift(1.8 * DOWN)
segments = CurvesAsSubmobjects(curve)
segments.set_color_by_gradient(BLUE, RED)
self.play(Create(segments))
self.wait(0.5)
常见错误
虚线化后想改段数,应重新构造 DashedVMobject(mob, num_dashes=30),而不是修改已生成对象的 num_dashes 属性——构造函数已经把曲线切成了固定段数。
CurvesAsSubmobjects¶
CurvesAsSubmobjects(vmobject, **kwargs) 官方文档 ↗
CurvesAsSubmobjects 把一条曲线的每一段曲线元素拆成独立子对象,从而可以对同一条曲线分段着色(例如整体渐变)。
CurvesAsSubmobjects(vmobject: VMobject, **kwargs)
name |
type |
default |
desc |
|---|---|---|---|
|
VMobject |
— |
要拆分的曲线(必填) |
|
— |
— |
转发给 |
典型用法:CurvesAsSubmobjects(curve).set_color_by_gradient(BLUE, RED)。若不拆分,set_color_by_gradient 只会按曲线上的位置插值,效果与拆分后不同;拆分成子对象后每个子对象取自己区间内的渐变色。
VectorizedPoint¶
VectorizedPoint(location=array([0., 0., 0.]), color=ManimColor('#000000'), fill_opacity=0, stroke_width=0, artificial_width=0.01, artificial_height=0.01, **kwargs) 官方文档 ↗
VectorizedPoint 是一个不可见的定位辅助点:默认填充、描边全为 0,画面上看不见,但它有 artificial_width / artificial_height,能正常参与 next_to、move_to 等布局计算。
VectorizedPoint(
location: Point3DLike = ORIGIN,
color: ManimColor = BLACK,
fill_opacity: float = 0,
stroke_width: float = 0,
artificial_width: float = 0.01,
artificial_height: float = 0.01,
**kwargs,
)
name |
type |
default |
desc |
|---|---|---|---|
|
Point3DLike |
ORIGIN |
点的位置 |
|
ManimColor |
BLACK |
颜色(默认不可见,改色也看不出) |
|
float |
0 |
填充不透明度 |
|
float |
0 |
描边宽度 |
|
float |
0.01 |
参与布局计算的“假宽度” |
|
float |
0.01 |
参与布局计算的“假高度” |
红色的 VectorizedPoint(2 * RIGHT) 在画面中不可见,但 Square().next_to(anchor, RIGHT) 以它为参照完成了定位。
查看源码 vectorized_point_demo.py
from manim import *
class VectorizedPointDemo(Scene):
def construct(self):
dot = Dot(color=RED)
self.play(FadeIn(dot))
anchor = VectorizedPoint(2 * RIGHT)
box = Square().next_to(anchor, RIGHT)
self.play(FadeIn(box))
self.play(dot.animate.move_to(anchor))
self.wait(0.5)
常见错误
VectorizedPoint 天生不可见——构造出来却“找不到它”不是 bug。它适合当隐藏的锚点;想要看得见的点请用 Dot。
自测¶
✏️ 练习
set_fill(RED) 之后图形仍然只有边框没有红色填充,为什么?
✅ 参考答案
set_fill 只设置了填充颜色,fill_opacity 仍是默认的 0(完全透明)。需要写成 set_fill(RED, opacity=0.7) 或 set_fill(RED, 0.7)。
✏️ 练习
如何给一条 ParametricFunction 曲线做出“从头到尾由蓝变红”的效果?为什么直接对原曲线 set_color_by_gradient 效果不理想?
✅ 参考答案
用 CurvesAsSubmobjects(curve) 把曲线拆成子对象,再 set_color_by_gradient(BLUE, RED)。拆分前曲线是单个子对象,渐变按整条曲线的位置插值;拆分后每个曲线段是独立子对象,各自取渐变中对应区间的颜色,分段效果更细腻。
下一步¶
学会了给图形上色,下一节看如何把它们组织起来:Group、VGroup 与键值容器 VDict。