生成 p5.js 龙卷风模拟 html
2025-12-19
生成 p5.js 龙卷风模拟 html 展示
思考过程
**Developing a Simulation Plan**
I'm now focusing on the particle system. My plan is to start with a basic swirl effect for the visuals. I'll then shape the swirl into a cone, with the bottom narrower. Randomness will be critical. I'm exploring dust and debris effects, too. Motion will include rotation and upward movement.
**Analyzing Particle Behavior**
I've decided to move forward with the WEBGL implementation, since it gives a more realistic look for the tornado. I'm now looking at how to make the particles behave. I'll need to define their angle, radius, height, speed, size and color. The `Particle` class is the correct solution for this. I'll also start with the most basic effects and add more layers of complexity.
**Finalizing Implementation Details**
The core structure is now in place. I'm focusing on the `Particle` class with angle, radius, height, speed, size, and color properties, alongside the `setup()` and `draw()` functions. I am now finalizing the calculations for the radius, angle, and height to achieve the desired conical shape and rotational movement. I'm adding `noise()` to the center for a wobble effect, and I have set the particle color to be blue-ish/brown-ish. The last thing to do is determine what to do when particles reach the top, and apply different speeds at varying distances.
这是一个使用 p5.js 实现的 3D 龙卷风模拟效果。它通过大量的粒子旋转、向上移动并逐渐扩大半径来模拟龙卷风的锥形动态,同时加入了简单的噪声(Noise)来模拟龙卷风的不规则摆动。
你可以将以下代码保存为 `index.html`,然后在浏览器中打开即可看到效果。
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>p5.js 龙卷风模拟</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #111;
}
canvas {
display: block;
}
.controls {
position: absolute;
top: 20px;
left: 20px;
color: white;
font-family: sans-serif;
pointer-events: none;
text-shadow: 1px 1px 2px black;
}
</style>
</head>
<body>
<div class="controls">
<h2>龙卷风模拟</h2>
<p>鼠标移动改变视角</p>
</div>
<script>
let particles = [];
const numParticles = 1200; // 粒子数量
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
// 初始化粒子
for (let i = 0; i < numParticles; i++) {
particles.push(new Particle());
}
}
function draw() {
background(20, 24, 30);
// 轨道控制:根据鼠标位置旋转场景
rotateY(map(mouseX, 0, width, -PI, PI));
rotateX(map(mouseY, 0, height, PI/4, -PI/4));
// 绘制地面阴影感
push();
translate(0, 200, 0);
rotateX(HALF_PI);
fill(30, 30, 30, 150);
noStroke();
ellipse(0, 0, 400, 400);
pop();
// 更新和绘制粒子
for (let p of particles) {
p.update();
p.show();
}
}
class Particle {
constructor() {
this.init();
}
init() {
// y 从底部 (200) 到顶部 (-400)
this.y = random(200, -400);
this.angle = random(TWO_PI);
this.speed = random(0.05, 0.15); // 旋转速度
this.riseSpeed = random(1, 3); // 上升速度
this.noiseOffset = random(1000);
// 颜色:灰褐色系
let c = random(100, 200);
this.color = color(c, c - 10, c - 20, random(100, 200));
}
update() {
// 1. 向上移动
this.y -= this.riseSpeed;
// 2. 旋转
this.angle += this.speed;
// 3. 核心逻辑:半径随高度变化(锥形)
// 越往上,半径越大。y越小(负值),半径越大。
let baseRadius = map(this.y, 200, -400, 10, 250);
// 加入一点摆动 (Noise)
let wiggle = noise(this.y * 0.01, frameCount * 0.02) * 50;
this.currentRadius = baseRadius + wiggle;
// 4. 计算 3D 坐标
this.x = cos(this.angle) * this.currentRadius;
this.z = sin(this.angle) * this.currentRadius;
// 5. 循环:如果飞出顶部,重置到底部
if (this.y < -400) {
this.y = 200;
this.angle = random(TWO_PI);
}
}
show() {
push();
translate(this.x, this.y, this.z);
noStroke();
fill(this.color);
// 粒子大小随高度微调
let sz = map(this.y, 200, -400, 2, 6);
sphere(sz, 4, 4); // 使用简化的球体提高性能
pop();
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
</script>
</body>
</html>
```
### 核心原理解析:
1. **3D 渲染 (`WEBGL`)**: 使用 p5.js 的 WEBGL 模式,可以方便地在三维空间中放置粒子,并实现视角的旋转。
2. **锥形结构**:
* 龙卷风的形状是通过 `map(this.y, 200, -400, 10, 250)` 实现的。
* 底部(`y = 200`)半径较小(10像素)。
* 顶部(`y = -400`)半径较大(250像素)。
3. **粒子运动**:
* **旋转**: 使用三角函数 `cos(angle)` 和 `sin(angle)` 结合不断增加的半径,使粒子产生螺旋上升的效果。
* **上升**: 每个粒子的 `y` 值不断减小,当到达一定高度后重置到底部,形成持续的流动感。
4. **动态摆动**: 使用 `noise()` 函数对每一层的半径进行偏移,模拟现实中龙卷风晃动、不稳定的质感。
5. **性能优化**:
* 使用了 `sphere(sz, 4, 4)`,通过降低球体的细分数(只有4个分段)来保证在粒子数量较多时依然流畅。
### 如何自定义:
* **颜色**: 修改 `this.color` 可以改变龙卷风的颜色(例如改成沙尘暴的黄色或风暴的深蓝色)。
* **粒子数**: 修改 `numParticles`。数量越多效果越浓密,但对电脑性能要求越高。
* **形状**: 修改 `baseRadius` 的映射范围,可以改变龙卷风的“胖瘦”。