如何用Manim动画绘制单参数族参数曲面?以球变椭球为例
嘿,这个需求我太熟了!用Manim实现单参数族曲面的变形动画其实非常直观,我直接给你上可运行的代码+详细解释,你跟着做就能搞定~
核心思路
本质上就是把参数t作为动画的时间变量,让它从0平滑过渡到1,每一帧都根据当前的t值重新生成对应的曲面。Manim里用ValueTracker跟踪参数变化,配合UpdateFunc实时更新曲面,就能实现流畅的变形效果。
完整代码实现
直接运行这段代码就能看到球面变椭球面的完整过程:
from manim import * class SurfaceDeformation(ThreeDScene): def construct(self): # 初始化参数t的跟踪器,初始值0,目标值1 t_tracker = ValueTracker(0) # 定义曲面生成函数:输入当前t值,输出对应参数曲面 def get_surface(t): return ParametricSurface( lambda u, v: np.array([ (1 + t) * np.sin(u) * np.cos(v), (1 + 2*t) * np.sin(u) * np.sin(v), (1 + 3*t) * np.cos(u) ]), u_range=[0, PI], v_range=[0, 2*PI], resolution=(20, 20), # 控制曲面光滑度,数值越高越光滑 colors=[BLUE, GREEN, RED] # 颜色渐变,方便观察不同轴的变形 ) # 创建初始曲面(t=0时的标准球面) surface = get_surface(0) self.add(surface) # 设置3D视角,让曲面展示更清晰 self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) # 添加实时显示t值的标签(可选) t_label = DecimalNumber(0, num_decimal_places=2).to_corner(UR) t_label.add_updater(lambda m: m.set_value(t_tracker.get_value())) self.add(t_label) # 定义曲面更新函数:每一帧用当前t值生成新曲面替换旧曲面 def update_surface(mob): new_surface = get_surface(t_tracker.get_value()) mob.become(new_surface) # 启动动画:让t从0变到1,同时实时更新曲面 self.play( t_tracker.animate.set_value(1), UpdateFunc(surface, update_surface), run_time=5, # 动画总时长,可按需调整 rate_func=linear # 线性变化,也可以用smooth/ease_in_out等变速函数 ) # 停留2秒展示最终的椭球面 self.wait(2)
关键细节解释
ValueTracker:Manim中专门用来跟踪数值变化的工具,是实现参数动画的核心,能让t值平滑过渡。ParametricSurface:直接传入你的参数方程即可生成对应曲面,u_range和v_range对应参数的取值范围(这里是球面的标准参数范围)。UpdateFunc:会在动画的每一帧调用指定的更新函数,用新生成的曲面替换旧曲面,实现无缝变形。- 视角调整:
set_camera_orientation的phi和theta参数控制3D相机的角度,你可以根据自己的需求调整数值,找到最佳观察视角。
额外优化建议
- 如果觉得渲染速度慢,可以降低
resolution的数值(比如改成15x15);如果想要更光滑的曲面,就提高这个数值。 - 可以给曲面添加边框线,在
ParametricSurface里加上stroke_width=0.5参数,让曲面的轮廓更清晰。 - 可以尝试不同的
rate_func,比如rate_func=smooth会让动画的开始和结束阶段变慢,中间阶段变快,视觉效果更自然。
内容的提问来源于stack exchange,提问作者220284
相关产品推荐
相关产品推荐

