
MATLAB动画制作完全指南:从基础的实时图形更新到专业视频制作,掌握drawnow、getframe、VideoWriter等核心技术,轻松创建流畅的三维旋转动画和科学可视化视频。
文章目录
实时更新图形 - drawnow 与 pause
基本语法
drawnow % 立即更新图形
drawnow limitrate % 限制更新速率
pause(t) % 暂停t秒
pause % 暂停直到按键
使用场景
- drawnow: 强制MATLAB立即更新图形显示
- pause: 控制动画播放速度
- 创建流畅的实时动画效果
简单示例
% 简单的动态正弦波
figure;
x = 0:0.1:4*pi;
h = plot(x, sin(x), 'b-', 'LineWidth', 2);
xlabel('X'); ylabel('Y'); title('动态正弦波');
grid on;
% 动态改变相位
for phase = 0:0.2:4*pi
y = sin(x + phase);
set(h, 'YData', y);
title(sprintf('动态正弦波 (相位: %.1f)', phase));
drawnow; % 立即更新图形
pause(0.1); % 暂停0.1秒
end

进阶示例
% 多条动态曲线
figure;
x = 0:0.1:4*pi;
colors = ['r', 'g', 'b', 'm'];
h = [];
% 初始化多条曲线
for i = 1:4
y = sin(x + (i-1)*pi/2);
h(i) = plot(x, y, colors(i), 'LineWidth', 2);
hold on;
end
xlabel('X'); ylabel('Y'); title('多波动态叠加');
grid on; legend('波1', '波2', '波3', '波4');
% 动态更新所有曲线
for t = 0:0.1:6*pi
for i = 1:4
y = sin(x + t + (i-1)*pi/2) .* exp(-0.1*t); % 衰减波
set(h(i), 'YData', y);
end
title(sprintf('衰减波动画 (t = %.1f)', t));
drawnow limitrate; % 限制更新速率提高性能
pause(0.05);
end

帧捕获 - getframe 命令
基本语法
F = getframe % 捕获当前图形
F = getframe(gcf) % 捕获指定图形
F = getframe(gca) % 捕获当前坐标轴
F = getframe(h, rect) % 捕获指定区域
使用场景
- 将动画的每一帧保存为图像
- 创建动画文件的原始数据
- 后期视频编辑和处理
示例
简单示例:
% 捕获简单动画帧
figure;
[X, Y] = meshgrid(-2:0.2:2, -2:0.2:2);
frames = []; % 存储帧数据
for t = 1:20
Z = sin(sqrt(X.^2 + Y.^2) - t*0.3);
surf(X, Y, Z);
shading interp;
axis([-2 2 -2 2 -1 1]);
title(sprintf('波动动画 帧 %d', t));
frames(t) = getframe(gcf); % 捕获当前帧
pause(0.1);
end
% 显示捕获的帧信息
fprintf('捕获了 %d 帧动画\n', length(frames));
fprintf('帧大小: %d x %d\n', size(frames(1).cdata, 1), size(frames(1).cdata, 2));
进阶示例
% 高质量帧捕获设置
figure;
[X, Y, Z] = sphere(50);
frames = [];
% 设置高质量渲染
set(gcf, 'Renderer', 'opengl');
set(gca, 'NextPlot', 'replacechildren');
for angle = 0:10:360
% 绘制旋转的球体
surf(X, Y, Z);
shading interp;
material('shiny');
light('Position', [2, 2, 3]);
colormap('jet');
% 设置视角
view(angle, 30);
axis equal; axis off;
title(sprintf('旋转球体 (角度: %d°)', angle));
% 捕获高质量帧
drawnow;
frames(end+1) = getframe(gcf);
pause(0.05);
end
fprintf('捕获了 %d 帧高质量动画\n', length(frames));
运行结果:

视频制作 - VideoWriter 命令
基本语法
v = VideoWriter(filename) % 创建视频对象
v = VideoWriter(filename, profile) % 指定编码格式
open(v) % 打开视频文件
writeVideo(v, frame) % 写入帧
close(v) % 关闭视频文件
常用视频格式
- ‘MPEG-4’: 高质量,文件较大
- ‘Motion JPEG AVI’: 兼容性好
- ‘Uncompressed AVI’: 最高质量,文件很大
示例
简单示例
% 制作简单的视频文件
v = VideoWriter('simple_animation.mp4', 'MPEG-4');
v.FrameRate = 10; % 设置帧率
open(v);
figure;
[X, Y] = meshgrid(-2:0.1:2, -2:0.1:2);
% 生成并写入视频帧
for t = 1:50
Z = sin(sqrt(X.^2 + Y.^2) - t*0.2);
surf(X, Y, Z);
shading interp;
colormap('jet');
axis([-2 2 -2 2 -1 1]);
title(sprintf('波动动画 帧 %d/50', t));
frame = getframe(gcf);
writeVideo(v, frame); % 写入当前帧
pause(0.05);
end
close(v);
fprintf('视频已保存为: simple_animation.mp4\n');
运行结果:

视频如下:
simple_animation
进阶示例
figure;
% 制作高质量旋转动画视频
v = VideoWriter('rotating_surface.mp4', 'MPEG-4');
v.FrameRate = 30; % 高帧率
v.Quality = 95; % 高质量
open(v);
figure;
set(gcf, 'Color', 'white'); % 白色背景
% 创建复杂曲面
[X, Y] = meshgrid(-3:0.1:3, -3:0.1:3);
Z = peaks(X, Y);
for angle = 0:2:720 % 两圈旋转
surf(X, Y, Z);
shading interp;
material('shiny');
light('Position', [3, 3, 5]);
colormap('jet');
colorbar;
% 平滑旋转视角
view(angle, 20 + 10*sin(deg2rad(angle*2))); % 上下轻微摆动
axis tight;
xlabel('X'); ylabel('Y'); zlabel('Z');
title(sprintf('Peaks函数旋转视图 (%.0f°)', mod(angle, 360)));
drawnow;
frame = getframe(gcf);
writeVideo(v, frame);
end
close(v);
fprintf('高质量旋转视频已保存: rotating_surface.mp4\n');
运行结果:

自动生成如下mp4文件:

视频内容如下:
rotating_surface
旋转曲面动画案例
基本旋转动画
% 基本旋转曲面动画
figure;
[u, v] = meshgrid(0:0.1:2*pi, 0:0.1:pi);
% 创建环面(甜甜圈)
R = 3; r = 1;
X = (R + r*cos(v)) .* cos(u);
Y = (R + r*cos(v)) .* sin(u);
Z = r * sin(v);
% 旋转动画
for azimuth = 0:5:360
surf(X, Y, Z);
shading interp;
colormap('copper');
light('Position', [5, 5, 5]);
material('metal');
view(azimuth, 30); % 水平旋转
axis equal; axis off;
title(sprintf('环面旋转 (方位角: %d°)', azimuth));
drawnow;
pause(0.05);
end
运行结果:

多轴旋转动画
% 复杂的多轴旋转动画
figure;
% 创建三个子图进行不同类型的旋转
surfaces = cell(1,3);
titles = {'水平旋转', '垂直旋转', '复合旋转'};
% 准备三种不同的曲面
[X1, Y1] = meshgrid(-2:0.1:2, -2:0.1:2);
Z1 = peaks(X1, Y1);
[X2, Y2, Z2] = sphere(30);
[u, v] = meshgrid(0:0.2:2*pi, -1:0.1:1);
X3 = u .* cos(u);
Y3 = u .* sin(u);
Z3 = v;
surfaces{1} = {X1, Y1, Z1};
surfaces{2} = {X2, Y2, Z2};
surfaces{3} = {X3, Y3, Z3};
% 动画循环
for frame = 1:72 % 360度,每5度一帧
for i = 1:3
subplot(1, 3, i);
X = surfaces{i}{1};
Y = surfaces{i}{2};
Z = surfaces{i}{3};
surf(X, Y, Z);
shading interp;
light('Position', [2, 2, 3]);
colormap(gca, 'jet');
% 不同的旋转方式
angle = frame * 5;
switch i
case 1 % 水平旋转
view(angle, 30);
case 2 % 垂直旋转
view(45, angle/2);
case 3 % 复合旋转
view(angle, 30 + 20*sin(deg2rad(angle*2)));
end
axis tight;
title(sprintf('%s (%d°)', titles{i}, angle));
end
drawnow;
pause(0.1);
end
运行结果:

完整动画项目案例
制作完整的科学可视化动画
% 完整的波动方程可视化动画项目
% 设置视频参数
v = VideoWriter('wave_equation.mp4', 'MPEG-4');
v.FrameRate = 24;
v.Quality = 90;
open(v);
% 设置图形窗口
figure('Position', [100, 100, 1200, 800]);
set(gcf, 'Color', 'black');
% 创建网格
[X, Y] = meshgrid(-4:0.2:4, -4:0.2:4);
total_frames = 120;
fprintf('开始生成 %d 帧动画...\n', total_frames);
for frame = 1:total_frames
clf; % 清除图形
% 计算波动方程
t = frame * 0.1;
Z1 = exp(-0.3*(X.^2 + Y.^2)) .* sin(sqrt(X.^2 + Y.^2) - 2*t);
Z2 = 0.5 * exp(-0.2*((X-2).^2 + (Y-2).^2)) .* cos(sqrt((X-2).^2 + (Y-2).^2) - 3*t);
Z = Z1 + Z2;
% 绘制主曲面
surf(X, Y, Z, 'EdgeColor', 'none');
shading interp;
colormap('jet');
alpha(0.8);
% 添加光照
light('Position', [5, 5, 3], 'Color', [1, 1, 1]);
light('Position', [-3, -3, 2], 'Color', [0.5, 0.5, 1]);
material('shiny');
% 设置视角(缓慢旋转)
view_angle = 45 + 30 * sin(2*pi*frame/total_frames);
view(view_angle, 25);
% 美化图形
axis([-4 4 -4 4 -1 1]);
xlabel('X', 'Color', 'white', 'FontSize', 12);
ylabel('Y', 'Color', 'white', 'FontSize', 12);
zlabel('Z', 'Color', 'white', 'FontSize', 12);
title(sprintf('波动方程可视化 (t = %.1f)', t), ...
'Color', 'white', 'FontSize', 16);
% 设置坐标轴颜色
set(gca, 'XColor', 'white', 'YColor', 'white', 'ZColor', 'white');
grid on;
% 添加颜色条
cb = colorbar;
set(cb, 'Color', 'white');
drawnow;
% 捕获帧并写入视频
frame_data = getframe(gcf);
writeVideo(v, frame_data);
% 显示进度
if mod(frame, 10) == 0
fprintf('已完成: %d/%d 帧\n', frame, total_frames);
end
end
close(v);
fprintf('动画制作完成!文件保存为: wave_equation.mp4\n');
运行结果:

视频如下:
wave_equation
交互式动画控制
% 可控制的实时动画
figure('Position', [100, 100, 800, 600]);
% 创建控制按钮
uicontrol('Style', 'pushbutton', 'String', '开始/暂停', ...
'Position', [20, 20, 80, 30], 'Callback', @toggle_animation);
uicontrol('Style', 'pushbutton', 'String', '重置', ...
'Position', [120, 20, 80, 30], 'Callback', @reset_animation);
% 速度滑块
uicontrol('Style', 'text', 'String', '速度:', ...
'Position', [220, 25, 40, 20]);
speed_slider = uicontrol('Style', 'slider', 'Min', 0.01, 'Max', 0.2, ...
'Value', 0.05, 'Position', [270, 20, 100, 30]);
% 全局变量
global is_running current_time;
is_running = false;
current_time = 0;
% 初始化图形
[X, Y] = meshgrid(-3:0.2:3, -3:0.2:3);
h_surf = surf(X, Y, zeros(size(X)));
shading interp;
colormap('jet');
light('Position', [3, 3, 5]);
axis([-3 3 -3 3 -2 2]);
title('交互式波动动画');
% 动画主循环
while ishandle(h_surf)
if is_running
current_time = current_time + get(speed_slider, 'Value');
Z = sin(sqrt(X.^2 + Y.^2) - current_time);
set(h_surf, 'ZData', Z);
title(sprintf('交互式波动动画 (t = %.2f)', current_time));
end
drawnow;
pause(0.02);
end
% 回调函数
function toggle_animation(~, ~)
is_running = ~is_running;
end
function reset_animation(~, ~)
current_time = 0;
end
end
运行结果:
性能优化技巧
提高动画性能
% 性能优化的动画制作
figure;
[X, Y] = meshgrid(-2:0.1:2, -2:0.1:2);
% 预分配和优化设置
set(gca, 'NextPlot', 'replacechildren'); % 避免重复创建对象
h_surf = surf(X, Y, zeros(size(X)));
shading interp;
light('Position', [2, 2, 3]);
% 使用句柄更新而非重新创建
tic;
for t = 1:100
Z = sin(sqrt(X.^2 + Y.^2) - t*0.1);
set(h_surf, 'ZData', Z); % 只更新数据,不重新创建对象
title(sprintf('优化动画 帧 %d', t));
drawnow limitrate; % 限制更新率
pause(0.01);
end
elapsed_time = toc;
fprintf('优化后动画用时: %.2f 秒\n', elapsed_time);

总结与最佳实践
命令使用建议
-
drawnow vs drawnow limitrate
- 普通动画使用
drawnow - 高频更新使用
drawnow limitrate
- 普通动画使用
-
pause时间设置
- 流畅动画: 0.02-0.05秒
- 慢速演示: 0.1-0.5秒
- 快速预览: 0.01秒
-
视频制作参数
- 演示用: FrameRate = 15-24
- 科学分析: FrameRate = 30-60
- Quality = 80-95
性能优化原则
- 使用句柄更新数据而非重新绘制
- 预设固定的坐标轴范围
- 合理使用
drawnow limitrate - 避免在循环中创建新对象
上述例程汇总为mlx文件,如下:
通过网盘分享的文件:2.6 动态图形与动画
链接: https://pan.baidu.com/s/1qK1hiF2HnXd-Lk65FgntwQ?pwd=5emw 提取码: 5emw
如需帮助,或有导航、定位滤波相关的代码定制需求,请点击下方卡片联系作者
525

被折叠的 条评论
为什么被折叠?



