3D 场景¶
影片代码
import manimgx as m
import numpy as np
class ThreeDScenesHero(m.ThreeDScene):
def construct(self) -> None:
axes = m.ThreeDAxes(
x_range=[-3, 3],
y_range=[-3, 3],
z_range=[0, 2],
x_length=7,
y_length=7,
z_length=3,
)
def height(u: float, v: float) -> np.ndarray:
return axes.c2p(u, v, 2 * np.exp(-(u**2 + v**2) / 2))
hill = m.Surface(height, u_range=[-2.5, 2.5], v_range=[-2.5, 2.5])
title = m.Text("A hill", font_size=40).to_corner(m.UL)
self.add_fixed_in_frame_mobjects(title)
self.add(axes, hill)
self.move_camera(phi=65 * m.DEGREES, theta=-45 * m.DEGREES, run_time=2)
self.begin_ambient_camera_rotation(rate=0.3)
self.wait(3)
3D 场景是相机从某个角度观察画框的场景。两个角度决定它:phi,自正上方度量(0 为正下方
俯视,如同平面场景),以及 theta,绕垂直轴度量。相机始终对准画框中心;它以透视方式显示
场景,近处物体遮挡远处物体。
ThreeDScene
¶

代码
import numpy as np
import manimgx as m
class ThreeDSceneExample(m.ThreeDScene):
def construct(self) -> None:
self.set_camera_orientation(
phi=65 * m.DEGREES, theta=-50 * m.DEGREES, zoom=0.6
)
axes = m.ThreeDAxes(x_range=(-3, 3), y_range=(-3, 3), z_range=(-2, 2))
surface = m.Surface(
lambda u, v: axes.c2p(u, v, np.sin(u) * np.cos(v)),
u_range=(-3, 3),
v_range=(-3, 3),
resolution=(24, 24),
).set_fill_by_checkerboard(m.BLUE_D, m.TEAL, opacity=0.9)
title = m.MathTex(r"z = \sin x \cos y", font_size=64).to_corner(m.UL)
self.add_fixed_in_frame_mobjects(title)
self.add(axes, surface)
以三维方式观察的场景:相机绕其轨道运动,带透视与深度。
相机从角度 phi(自 z 轴起,0 表示从正上方俯视 xy 平面)与 theta(绕
z 轴,默认 −90°,使 x 指向右方)观察其帧的中心;gamma 使其绕视线转动,
zoom 放大,focal_distance 为其与所观察点的距离。每个都是
相机 的值跟踪器,因此像任何
mobject 一样移动:move_camera 为其添加
动画,环境旋转使其持续转动。较近的表面遮挡较远者;固定在帧中的 mobject
平铺绘制在屏幕上,位于一切之上。
源码
manimgx\scene.py
set_camera_orientation
¶
立即设置相机观察位置:每个给定设置;其余保持不变。
phi相机视线与 z 轴之间的夹角,以弧度表示:0 表示从正上方俯视 xy 平面。
theta相机绕 z 轴的角度,以弧度表示,从 x 轴逆时针方向计量:在 −90° 时从 y 轴负侧观察,使 x 轴指向右方。
gamma相机绕自身视线转动的角度,以弧度表示。
zoom相机的放大倍数:2 表示将一切放大两倍显示。
focal_distance相机与所观察点的距离,以场景单位表示:越近, 透视越强。
frame_center相机所观察的点,或其中心为该点的 mobject:相机的帧 移动到该处。
源码
manimgx\scene.py
begin_ambient_camera_rotation
¶
代码
import manimgx as m
class ThreeDSceneAmbientRotationExample(m.ThreeDScene):
def construct(self) -> None:
self.set_camera_orientation(
phi=70 * m.DEGREES, theta=-45 * m.DEGREES
)
torus = m.Torus(major_radius=2.5, minor_radius=0.8)
self.add(m.ThreeDAxes(), torus.set_color(m.TEAL))
self.begin_ambient_camera_rotation(rate=m.PI / 4) # 45° a second
self.wait(4)
开始稳定转动相机,贯穿 play 与 wait,直到
stop_ambient_camera_rotation。
相机的一个角度以稳定速率增长:其跟踪器获得一个更新器 (一个 flow)并加入场景。
rate角度增长速率,以弧度每秒表示;负值反方向转动。
about该角度:"theta"(绕 z 轴)、"phi" 或 "gamma",任意大小写。
源码
manimgx\scene.py
stop_ambient_camera_rotation
¶
停止转动相机:移除该角度跟踪器的每个更新器,跟踪器离开场景。相机 停留在其转到的位置。
about该角度:"theta"、"phi" 或 "gamma",任意大小写。
源码
manimgx\scene.py
begin_3dillusion_camera_rotation
¶
开始使相机绕其朝向摇摆,以产生深度错觉,贯穿 play 与 wait,直到
stop_3dillusion_camera_rotation。
相机小幅环绕:theta 在 origin_theta 两侧各 0.2 弧度间摆动,
phi 在 origin_phi 与少 0.2 弧度之间,二者相差四分之一周期。两个
角度的跟踪器获得更新器(flow)并加入场景。
rate摇摆速度,以每秒其周期的弧度表示:一个周期耗时 2π /
rate秒。origin_phi摇摆起自的
phi;None 表示相机当前值。origin_theta摇摆所绕的
theta;None 表示相机当前值。
源码
manimgx\scene.py
stop_3dillusion_camera_rotation
¶
停止摇摆相机:移除 theta 与 phi 跟踪器的每个更新器,它们离开
场景。相机停留在摇摆所留位置。
move_camera
¶
代码
import manimgx as m
class ThreeDSceneMoveCameraExample(m.ThreeDScene):
def construct(self) -> None:
cube = m.Cube(side_length=2.5, fill_opacity=0.8, fill_color=m.BLUE)
self.add(m.ThreeDAxes(), cube)
self.move_camera(
phi=70 * m.DEGREES, theta=-45 * m.DEGREES, run_time=2
)
self.move_camera(theta=45 * m.DEGREES, zoom=1.5, run_time=2)
在一次 play 中为相机添加动画到新朝向:每个给定设置;其余保持不变。
每个设置从其值稳定移动到新值,由速率函数缓动,因此大 2π 的 theta
使相机绕一周。帧在给定 frame_center 时移动到该处,added_anims 一同
播放。
phi相机视线与 z 轴之间的夹角,以弧度表示:0 表示从正上方俯视 xy 平面。
theta相机绕 z 轴的角度,以弧度表示,从 x 轴逆时针方向计量。
gamma相机绕自身视线转动的角度,以弧度表示。
zoom相机的放大倍数:2 表示将一切放大两倍显示。
focal_distance相机与所观察点的距离,以场景单位表示。
frame_center相机要观察的点,或其中心为该点的 mobject。
added_anims一同播放的动画。
run_time动画播放时长,以秒为单位(默认 1)。
lag_ratiomobject 各部分如何交错:每个部分在其前一个部分开始后,经过其运行时长的该分数比例后开始 (默认 0:全部同时;1:一个接一个)。
rate_func动画进度如何随时间运行:一个从 [0, 1] 到 [0, 1] 的函数 (默认为
smooth;参见 rate functions)。reverse_rate_function是否反向运行动画(默认 False)。
name动画的名称。
remover动画结束时 mobject 是否离开场景 (默认 False)。
suspend_mobject_updating动画期间 mobject 的更新器是否在其下运行(默认 True):它们 持续作用于 mobject,每一帧显示动画应用于其结果。 若为 False,则它们作用于被动画的 mobject 本身。
introducer动画开始时 mobject 是否加入场景(默认 False); 否则若场景缺少它,play 在其开始时将其带入。
use_override若某 mobject 的类用另一个动画代替此动画播放,是否如此执行 (默认 True)。
还接受 变换关键字。
源码
manimgx\scene.py
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 | |
add_fixed_in_frame_mobjects
¶
添加固定到屏幕的 mobject:每个按其点所在位置绘制,如同在以原点为中心的 二维视图中,绘制在一切之上。
它们被添加到场景,无论相机的角度、缩放与中心如何都保持在屏幕上的位置:
用 to_corner 放置的标题停留在其角落。其中的一切现在及以后都被固定:
之后添加的成员(一个数字的新数位、更新器或 Transform 产生的部分)也
被固定。
源码
manimgx\scene.py