OpenMontage 数学动画实战:用 ManimGL 构建 3D 视差星场(Parallax Starfield)教学动画
【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage
本文基于 OpenMontage 仓库中 manimgl-best-practices 技能包内的 parallax_starfield.md 参考指南及其配套示例源码撰写。文中所有代码、参数与命令均可在仓库内找到原始依据,读者可据此直接复现一整套「视差原理」可视化教学场景。
本文是一篇面向 ManimGL(3Blue1Brown 版 manim)开发者的深度实战指南,主题是用一个**3D 视差星场(Parallax Starfield)**把天文学中「视差测距」这一抽象概念做成可视化教学动画。通过精读参考指南与完整的场景源码,读者将掌握:如何用GlowDots高效渲染上百颗带辉光效果的星点、如何通过frame.reorient()与set_floor_plane()完成 3D 相机重定向、如何让观察者在 Z 轴上下运动以凸显近远星体位移差,以及如何进一步衍生出第一人称视角与显式分层三个教学变体。这套设计方法同样适用于 OpenMontage 中「数学/科学可视化」类内容生产场景。
一、文档定位:技能包里的「场景级」参考指南
在 OpenMontage 中,ManimGL 最佳实践并不是以零散代码片段形式散落的,而是被组织成结构化技能包:入口 SKILL.md 负责路由(当用户提及manimgl、代码中出现from manimlib import *、或运行manimglCLI 时触发),其下再拆分为三类资产:
- rules/:18 个语言级规则文件,覆盖场景结构、3D 与相机、样式、CLI、交互式开发等通用知识点;
- references/:8 篇「场景级」参考指南,每篇围绕一个完整教学场景展开,parallax_starfield.md 就是其中之一;
- examples/:与 references 一一对应的、可直接运行的示例脚本,本主题对应 examples/parallax_starfield.py(文首注释明确标注其改编自 3b1b 的 cosmic_distance 视频)。
在 OpenMontage 的技能编排体系里,这类数学可视化能力被登记在数学动画(Math Animation)目录下,与manimce-best-practices、manim-composer并列(见 skills/INDEX.md),并被 animation-runtime-selector.md 等运行时选择器用于「数学/科学可视化」这一类任务的运行时路由决策。
二、场景背后的科学概念与用户诉求
这份参考指南瞄准的不是「画个星空」,而是一组具体的用户提问模式:
- 如何用星星演示视差(parallax)是如何工作的?
- 如何创建一个能演示深度感知的 3D 场景?
- 如何动画化一个观察者在星场中穿行的过程?
- 如何用视觉方式解释「恒星视差」?
- 如何展示「当你移动时,近处的物体比远处的物体移动得更多」?
回答这些问题的核心概念是视差:当观察者发生移动时,近处的物体相对背景的位移看起来比远处物体更大。天文学家正是利用这一效应测量附近恒星的距离。该示例的可视化策略是「以星星为媒介」——因为天体天然分布在远近不同的距离上,观察者的横向(或纵向)移动会自然引发不同大小的视差位移,从而把抽象原理还原为肉眼可感知的运动差。
三、3b1b 风格的设计决策推演
参考指南按 3Blue1Brown 的创作方法,给出了场景设计的完整思考链,这正是该文档区别于普通 API 教程的价值所在。
3.1 为什么用星星/光点而不是复杂物体
- 星星天然分布在不同的距离层上,不需要额外构造几何关系;
- 点状物在计算上极其高效,
GlowDots处理 200+ 个点毫无压力(下方源码默认n_stars = 200); - 效果清晰,不会被物体形状抢走注意力,观众能直接聚焦于「位移量」本身。
3.2 为什么需要一个参考立方体
- 为 3D 空间提供空间语境,让观众意识到星群是分布在一个体积里而非一张平面图上;
- 蓝色线框(
set_fill(opacity=0)+set_stroke(BLUE, 2))不会遮挡星点,却能框出星场的边界。
3.3 为什么需要一个观察者角色
- 让场景「有人情味」——观众看到的是「某个人在观察」,而非抽象坐标系在动;
- 观察者的运动方向直观易懂,观众能自然地把自身的移动经验映射到画面中。
四、技术实现拆解(对照源码)
下面结合 examples/parallax_starfield.py 的ParallaxStarfield场景,逐段解析参考指南中的技术要点。
4.1 用 GlowDots 高效渲染星空
from manimlib import * import numpy as np class ParallaxStarfield(InteractiveScene): def construct(self): # Setup 3D environment frame = self.frame self.set_floor_plane("xz") # Set z as vertical axis # Create a reference cube to help visualize 3D space height = 4 cube = VCube(height) cube.set_fill(opacity=0) cube.set_stroke(BLUE, 2) # Create stars as GlowDots - efficient for many point lights n_stars = 200 # Random positions in a cube star_positions = np.random.uniform(-1, 1, (n_stars, 3)) stars = GlowDots(star_positions) stars.scale(height / 2) # Scale to fit within our cube stars.set_color(WHITE) stars.set_glow_factor(2) # Vary star sizes for visual interest stars.set_radii(np.random.uniform(0, 0.075, n_stars)) self.add(cube) self.add(stars)要点说明:
GlowDots接收一个(n, 3)的 NumPy 数组作为 3D 坐标集,一次性生成整片星群。参考指南特别强调:对于 200+ 个点,逐颗创建Dot对象是不可取的,GlowDots是唯一可行的方案——这正是它的设计目的。set_glow_factor(2)开启柔和辉光(bloom)效果,让白点呈现「星芒感」;set_radii(np.random.uniform(0, 0.075, n_stars))让每颗星半径随机,避免机械的等大网格感;- 坐标先生成在
(-1, 1)的归一化立方体内,再用stars.scale(height / 2)放大适配到边长 4 的参考立方体内部。
4.2 3D 相机控制与坐标系重定向
# Add an observer (using a simple 3D sphere) observer = Sphere(radius=0.3) observer.set_color(BLUE_E) observer.set_shading(0.5, 0.5, 0.5) observer.next_to(cube, LEFT, buff=1) # Add an arrow to show viewing direction eye_arrow = Arrow( observer.get_center(), observer.get_center() + 1.5 * RIGHT, buff=0, stroke_color=YELLOW, stroke_width=4, ) eye_arrow.add_updater(lambda m: m.put_start_and_end_on( observer.get_center(), observer.get_center() + 1.5 * RIGHT )) # Rotate camera for better 3D view self.play(frame.animate.reorient(-40, -26, 0), run_time=2)这里有两个承上启下的 ManimGL 关键点:
self.set_floor_plane("xz"):在天文可视化中通常希望 Z 轴竖直(对应深度/视线方向),此调用会把坐标系重排为「Z 为竖直轴」,这也是后续观察者用dy * IN沿 Z(视线方向)移动能够制造纵深位移的前提。其中IN在 ManimGL 中表示「指向屏幕内」,即 Z 轴正方向。frame.reorient()的签名与作用:reorient(theta, phi, gamma=0, center=ORIGIN, height=8),其中theta为绕 Z 轴的方位角、phi为相对 Z 轴的极角、gamma为翻滚角,后两个可选参数分别是相机注视点与画面高度。frame.animate.reorient(-40, -26, 0)将相机平滑转到能同时看清星群体积与观察者的斜侧视角。完整的相机角度语义可参考技能包内的 camera.md 与 3d.md。
此外,eye_arrow通过add_updater每帧把箭头起点与终点锁定到观察者球体中心,保证后续观察者移动时指示箭头始终「跟嘴」指向视线方向——这是 ManimGL 中「让装饰对象持续跟随运动主体」的典型写法。
4.3 观察者运动模式与视差显现
# Key demonstration: Move observer up and down # Watch how nearby stars shift more than distant ones for dy in [1.5, -3, 3, -3, 1.5]: self.play( observer.animate.shift(dy * IN), # IN = into screen = Z axis run_time=3 )参考指南解释了这个位移序列[1.5, -3, 3, -3, 1.5]的设计意图:
- 它构成「上 → 下 → 上 → 下 → 回中」的对称运动轨迹;
- 让观众看到视差位移的完整范围(正向与反向);
- 最终回到起点,如需循环播放可无缝衔接。
在透视投影下,同一段观察者位移会让距离近的星星在屏幕上「跑」得更多、远的星星几乎不动,于是视差原理被直观呈现。run_time=3保证了每段位移有足够慢的节奏供观众追踪特定星点。
4.4 场景构建顺序小结
整体渲染顺序为:初始化 3D 环境与坐标系 → 生成线框立方体与星群 →ShowCreation星群渐显 → 淡入观察者并勾勒视线箭头 → 相机重定向到斜侧视角 → 观察者沿 Z 轴往复移动 →self.wait()定格。这个「先搭空间语境、再造主体、最后动起来」的顺序本身就是 3b1b 式场景叙事节奏的体现。
五、三个场景变体:由浅入深的渐进式教学
参考指南给出了三个渐进复杂度的场景变体,对应源码中三个继承InteractiveScene的类:
| 场景类 | 视角 | 目的 | 适用教学时刻 |
|---|---|---|---|
ParallaxStarfield | 第三人称斜视角 | 展示基本视差效果与场景全貌 | 一般性原理讲解 |
ParallaxFromObserverPOV | 第一人称视角 | 回答「作为观察者你实际会看到什么?」 | 代入式体验 |
LayeredParallax | 第三人称 + 显式距离分层 | 用颜色与标签把距离概念讲透 | 概念澄清与课堂讲授 |
5.1 第一人称变体:相机跟随观察者
ParallaxFromObserverPOV复用了相同的星场构造逻辑,区别在于后续处理:
# Move camera to observer's perspective self.play( frame.animate.reorient(-89, -4, 0, (0.01, 0.21, 0.0), 3.05), observer.animate.set_opacity(0), cube.animate.set_stroke(width=5).set_anti_alias_width(10), run_time=3, ) # Camera follows observer's z position frame.always.match_z(observer) # Move observer - camera follows, showing parallax from their view for dy in [1.5, -3, 3, -3, 1.5]: self.play(observer.animate.shift(dy * IN), run_time=4)这里的关键 API 是frame.always.match_z(observer):相机帧的 Z 坐标被注册为持续同步观察者的 Z 坐标。由于相机 X/Y 保持原位,观众看到的画面正是观察者「转头看向星场并沿视线移动」时会看到的景象——不同距离的星点产生肉眼可见的位移差。同时观察者本体被淡出(set_opacity(0)),避免第一人称画面中出现自己的「后脑勺」。参考指南将此列为第一个核心模式:
Pattern:Frame Following an Object——
frame.always.match_z(observer),相机 Z 位置持续匹配观察者,从而构造第一人称视角。
5.2 分层变体:用显式距离层强化教学
LayeredParallax把「连续距离分布」替换为「三层离散距离」,让教学意图无可辩驳:
colors = [RED, YELLOW, BLUE] distances = [2, 5, 10] # Distance from origin n_stars_per_layer = 50 for color, dist in zip(colors, distances): # Create stars in an XY plane at distance Z positions = np.random.uniform(-3, 3, (n_stars_per_layer, 3)) positions[:, 2] = dist # Set all Z to this layer's distance layer = GlowDots(positions) layer.set_color(color) layer.set_glow_factor(1.5) layer.set_radii(np.full(n_stars_per_layer, 0.05))三组星点分别被钉在z = 2 / 5 / 10三个距离平面上(positions[:, 2] = dist强制该层所有 Z 坐标一致),并配上红/黄/蓝三色与同色距离标签文本:
label = Text(f"{dist} units away", color=color, font_size=24) label.to_corner(UL) label.shift(DOWN * (distances.index(dist) * 0.5))随后相机先整体拉远到能容纳全部三层(frame.set_height(12)),再让绿色观察者小球做横向(X 方向)往复运动:
# Move observer laterally - watch the layers shift differently for dx in [2, -4, 4, -2]: self.play( observer.animate.shift(dx * RIGHT), run_time=3, rate_func=smooth )参考指南将这一设计归纳为第二个核心模式:
Pattern:Layered Depth for Clarity—— 用不同颜色(RED/YELLOW/BLUE)绑定不同距离(2/5/10),使教学场景中的视差效果「不言自明」。
Pattern:Smooth Lateral Movement—— 慢速平滑移动(
run_time=3搭配rate_func=smooth),让观众能逐个追踪星点、从容观察位移差异。
六、高频自定义扩展
参考指南末尾提供了三个即改即用的扩展方向,方便读者在复刻示例后快速注入个人风格。
6.1 增加星数并压缩星径
n_stars = 500 # Increase count stars.set_radii(np.random.uniform(0, 0.05, n_stars)) # Smaller radii for density更多、更小的星点能营造更致密的星场;GlowDots对 500 颗点的处理依旧流畅(这是它相对逐点Dot的根本优势)。
6.2 按恒星温度着色
# Temperature-based star colors colors = [RED, ORANGE, YELLOW, WHITE, BLUE_A] for i, star in enumerate(stars): star.set_color(random.choice(colors))把白星换成从红到蓝白的温度色系后,星场在传达视差之余还捎带普及了「恒星颜色反映表面温度」的天文常识,画面层次也更丰富。
6.3 叠加远景银河背景
background = ImageMobject("milky_way.png") background.set_height(20) background.shift(50 * OUT) # Far behind stars self.add(background)将银河图钉在50 * OUT(远离观察者的 Z 负方向),使它相对观察者位移几乎为零,反而充当了「无穷远参照系」,让前景星点的视差位移愈发醒目。
七、渲染输出与运行命令
7.1 预期输出
渲染完成后你会得到(以ParallaxStarfield为例):
- 一个置于蓝色线框立方体内的 3D 星场;
- 一个沿视线方向上下往复移动的蓝色球体观察者(Randolph 式角色);
- 星星因距离不同而产生不同的视差位移;
- 完整演示视差原理的动态过程。
7.2 运行命令
# Full render manimgl parallax_starfield.py ParallaxStarfield -w # Preview (no file output) manimgl parallax_starfield.py ParallaxStarfield -p # All three scenes manimgl parallax_starfield.py ParallaxStarfield ParallaxFromObserverPOV LayeredParallax -w7.3 渲染相关的 CLI 速查
配合技能包 cli.md 中的规则,可针对不同开发阶段组合常用旗标:
| 阶段 | 命令 | 说明 |
|---|---|---|
| 快速迭代 | manimgl parallax_starfield.py ParallaxStarfield -l | 低画质(480p/15fps),渲染最快 |
| 交互式调试 | manimgl parallax_starfield.py ParallaxStarfield -se 28 | 运行到第 28 行后坠入 IPython shell |
| 检查静帧 | manimgl parallax_starfield.py ParallaxStarfield -s | 只输出并展示最后一帧 |
| 正式出片 | manimgl parallax_starfield.py ParallaxStarfield -h -o | 1080p/60fps 渲染并自动打开 |
| 自定义分辨率 | manimgl parallax_starfield.py ParallaxStarfield --resolution 2560,1440 | 覆盖默认画质 |
特别值得强调的是-se(skip and embed)交互模式:场景会执行到指定行后停下来,之后你就可以在 shell 里用checkpoint_paste()(带回放)、checkpoint_paste(skip=True)(瞬时执行)或checkpoint_paste(record=True)(录制)粘贴调试代码,配合touch()以鼠标/滚轮实时调整相机。整套工作流细节见 interactive.md 与 scenes.md,是调整星场构图的最高效路径。
八、与本技能包其他规则、以及 OpenMontage 的衔接
这套参考指南并非孤立存在,写作与调优时可横向参考技能包内这些配套规则文件:
- rules/3d.md:3D 相机
reorient()语义、CameraFrame角度系统、3D 原语与光照; - rules/camera.md:
frame的移动/缩放/欧拉角/fix_in_frame()/轨道旋转等相机专项; - rules/styling.md:辉光、填充/描边/透明度、
set_shading与视觉特效; - rules/scenes.md:
InteractiveScene基类与construct生命周期; - templates/3d_scene.py:含
frame.reorient()的 3D 场景脚手架模板。
需特别留意 ManimGL 与 Manim Community Edition 的差异(详见 SKILL.md 中的对照表):ManimGL 用from manimlib import *+manimglCLI +Tex(R"...")+ShowCreation+self.frame,与 ManimCE 的manim体系并不互通,切勿混用。
在 OpenMontage 的内容生产链路中,这类 ManimGL 场景通常被 animation-runtime-selector.md 等运行时选择器指派给「数学 / 科学可视化」类镜头,由 asset-director.md 之类的导演角色决定何时调用;本示例所演示的「近远位移差」镜头语言,正是从数学/物理教学镜头到广义数据叙事的通用技法。
九、结论与延伸练习
parallax_starfield是一份「小而全」的场景模板:它同时覆盖了 ManimGL 3D 场景中最常复用的三类能力——批量点光源渲染(GlowDots)、相机姿态控制(reorient/set_floor_plane/always.match_z)、以及与教学内容强绑定的分层构图设计。如果你希望进一步巩固,可以沿以下方向自行练习:
- 在
ParallaxFromObserverPOV基础上,让观察者同时做 X/Y/Z 三维漂移,验证相机跟随逻辑的鲁棒性; - 仿照
LayeredParallax,把距离标签改成实时读数(例如随帧更新的Text+add_updater); - 把星场替换为随机球壳分布,观察「均匀星场」与「分层星场」在视觉教学上的差异;
- 对照 three_d_surfaces.md、vector_fields.md 等同类参考指南,体会 3b1b 风格「先概念、再构图、后代码」的通用创作套路。
【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考