使用Makie的烟花动画
Makie是julia生态系统中受欢迎的可视化库。
在本例中,主题如:
-使用调色板([colormap](https://docs.makie.org/dev/explanations/colors#colormaps )/colorschemes)
-创建mp4动画(作为替代 @gif 在地块。jl)
-建筑逐点图的特点(scatter):
-尺寸
-标记
-颜色
-阿尔法通道
礼炮模型作为微分方程组
本例中的salyut模型由常微分方程组(ODES)描述,该系统模拟了粒子在重力,空气阻力和水平风影响下的运动。 该系统包括四个变量:坐标 和 ,以及它们相对于时间的导数(速度 和 ). 方程的形式如下:
这里 -自由落体加速, -空气阻力系数, -粒子的质量, -风速, -风阻系数。 该系统使用包进行数值求解 DifferentialEquations.jl,这使得能够模拟爆炸后烟花粒子的逼真行为。
安装依赖项和导入库
要处理动画和解决微分方程,我们需要软件包 DifferentialEquations, CairoMakie 和 Random. 我们将安装它们,如果它们尚未安装,并导入它们。
import Pkg; Pkg.add(["DifferentialEquations","CairoMakie","Random"])
using DifferentialEquations
using CairoMakie
using Random
# 为可重复性设置种子
Random.seed!(1945_2025)
程序结构
我们的程序由几个关键组件组成:一组烟花,每个烟花都包含粒子,为每个粒子计算一个轨迹,轨迹是一组点。 .
定义模型和参数
定义函数 particle_motion!,其描述了根据ODES的上述系统的粒子的运动。 我们还设置了模拟参数:重力加速度、空气阻力、粒子质量、风速等.
# 考虑到风的粒子运动的功能
function particle_motion!(du, u, p, t)
g, k, m, v_w, k_w = p
du[1] = u[3] # dx/dt = v_x
du[2] = u[4] # dy/dt = v_y
du[3] = -(k + k_w) / m * u[3] + k_w * v_w / m # dv_x/dt = -(k + k_w)/m * v_x + k_w * v_w/m
du[4] = -g - k / m * u[4] # dv_y/dt = -g - k/m * v_y
end
# 参数
g = 9.81 # 自由落体加速
k = 0.1 # 空气阻力系数
m = 0.1 # 粒子质量
v_w = 0.1 # 水平风速(m/s,正向—向右)
k_w = 0.1 # 风阻系数
n_fireworks = 3 # 烟花数目
n_particles_per_firework = 150 # 烟花用粒子
v0_values = [1:2.5:25;] # 不同的初始速度
tspan = (0.0, 1.5) # 总时间间隔
saveat = 0.0125 # 固定时间步长
烟花生成和调色板选择
每个敬礼的特征是随机的起始位置(\(x_0,y_0\)),爆炸的时间和一组三个调色板。 我们使用 Makie.ColorSchemes 为了创造一个视觉上吸引人的效果,每个烟花的粒子被涂在三个不同的颜色方案。
# 调色板列表
available_palettes = [
Makie.ColorSchemes.Reds,
Makie.ColorSchemes.pink,
Makie.ColorSchemes.solar,
Makie.ColorSchemes.Blues
]
# 烟花的定义
fireworks = []
for i in 1:n_fireworks
# 随机起始位置
x0 = rand(-12:12)
y0 = rand(5:3:15)
# 随机突发时间(tspan在0.0到75%之间)
explosion_time = rand(tspan[1]:0.1:0.75*tspan[2])
# 为烟花选择三个随机调色板
selected_palettes = shuffle(available_palettes)[1:3] # 选择3种不同的调色板
push!(fireworks, (x0=x0, y0=y0, explosion_time=explosion_time, palettes=selected_palettes))
end
粒子轨迹建模
对于每个敬礼,我们通过求解颂歌系统来模拟其粒子的轨迹。 每个粒子被分配到三个选定的调色板中的一个,以创建一个多彩多姿的烟花效果。
# 模拟每个敬礼的轨迹
all_trajectories = []
all_particle_palettes = []
for (idx, fw) in enumerate(fireworks)
trajectories = []
particle_palettes = []
# 我们将粒子分成三组,用于三个调色板
particles_per_palette = div(n_particles_per_firework, 3)
for i in 1:n_particles_per_firework
# 从v0_values中选择初始速度
n_v = length(v0_values)
v0 = v0_values[ceil(Int, (i - 1) / (n_particles_per_firework / n_v))%n_v+1] + rand(-2:0.25:2)
θ = 2π * (i - 1) / (n_particles_per_firework / n_v) + rand(-0.1:0.001:0.1) # 随机角度偏差
u0 = [fw.x0, fw.y0, v0 * cos(θ), v0 * sin(θ)] # 起始位置和速度
prob = ODEProblem(particle_motion!, u0, tspan, (g, k, m, v_w, k_w))
sol = solve(prob, Tsit5(), saveat=saveat)
push!(trajectories, [(u[1], u[2]) for u in sol.u])
# 我们根据粒子组分配调色板
palette_idx = (i - 1) ÷ particles_per_palette + 1
if palette_idx > 3 # 对于最后一组粒子
palette_idx = 3
end
push!(particle_palettes, fw.palettes[palette_idx])
end
push!(all_trajectories, trajectories)
push!(all_particle_palettes, particle_palettes)
end
创建场景并添加繁星背景
在创建动画之前,我们设置了一个黑色背景的场景,并添加了将在整个动画中显示的星星。 这创造了一个夜空效果。
# 可视化
fig = Figure(backgroundcolor=:black)
ax = Axis(fig[1, 1], aspect=1, limits=(-20, 20, -20, 20),
backgroundcolor=:black, xgridvisible=false, ygridvisible=false,
xticksvisible=false, yticksvisible=false,
xticklabelsvisible=false, yticklabelsvisible=false)
# 在背景中添加星星
n_stars = 50 # 星数
x_stars = rand(-20:0.1:20, n_stars) # 随机x坐标
y_stars = rand(-20:0.1:20, n_stars) # 随机y坐标
创建动画
使用函数 record 从 CairoMakie 来创建MP4动画。 在每个动画帧中,我们重新绘制已经爆炸的星星和烟花粒子,同时考虑到尾部效果和个别褪色。
# 动画制作
total_frames = ceil((tspan[2] - tspan[1]) / saveat) + 1 # 总帧数
record(fig, "firework_with_wind.mp4", 1:total_frames-1) do frame_idx
empty!(ax)
# 重绘星星
CairoMakie.scatter!(ax, x_stars, y_stars, marker=:star5, color=:yellow, markersize=5, alpha=0.5)
# 动画中的当前时间
current_time = (frame_idx - 1) * saveat
# 我们通过每个敬礼
for firework_idx in 1:n_fireworks
fw = fireworks[firework_idx]
trajectories = all_trajectories[firework_idx]
particle_palettes = all_particle_palettes[firework_idx]
# 检查烟花是否爆炸
time_since_explosion = current_time - fw.explosion_time
if time_since_explosion >= 0
# 我们计算相对于爆炸时间的时间指数
i = Int(round(time_since_explosion / saveat)) + 1
# 我们将i限制在轨迹的长度
i = min(i, length(trajectories[1]))
# 每场烟花汇演的个别褪色
if time_since_explosion >= 0
fading_start = 0.6 # 60%的可见时间
fading_duration = 0.4 # 剩下的40%用于褪色
k_fading = time_since_explosion < fading_start ? 1.0 : max(0.0, 1.0 - (time_since_explosion - fading_start) / fading_duration)
# 我们限制尾部的长度:我们显示最后24个位置
for (traj, palette) in zip(trajectories, particle_palettes)
for j in max(1, i - 24):i
alpha = k_fading * (0.1 + 0.9 * exp(-0.4 * (i - j)))
markersize = 2 + 3 * exp(-0.5 * (i - j))
t = i > 1 ? (j - max(1, i - 14)) / (i - max(1, i - 14)) : 1.0
color = palette[t]
CairoMakie.scatter!(ax, [traj[j]], markersize=markersize, color=color, alpha=alpha)
end
end
end
end
end
end
动画可能需要一定的时间,之后将创建文件。 "firework_with_wind.mp4"
结论
在此示例中,我们使用生态系统创建了fireworks动画 Makie 有后端 CairoMakie. 我们已经学会了如何使用微分方程模拟粒子运动,应用调色板以获得视觉效果,以及创建MP4动画。 这种方法可以适用于其他可视化任务,如模拟行星运动、模拟爆炸或创建艺术动画。