可视化之粒子风场

绘制风场的关键点在Perlin 噪声。我们依然采用p5.js来绘制风场。 Perlin 噪声,Perlin 噪声是一种基于梯度的连续随机函数,可以用来生成连续的、自然的随机数。在这个代码中,我们使用 Perlin 噪声来计算粒子的运动角度,以此来实现粒子的运动轨迹。

Particle 类中,我们使用了 Perlin 噪声来计算粒子的角度,并根据角度计算粒子的方向向量和速度向量。然后,我们将速度向量乘以大小系数,并使用 add() 函数将速度向量加到位置向量上,从而更新粒子的位置。

Particle 类中,我们使用 checkEdges() 方法来检测粒子是否碰到边界,如果是则重新生成粒子。这样可以避免粒子飞出画布,同时也可以增加粒子的数量和密度。

setup() 函数中,我们创建了三个粒子数组,分别用来存储不同颜色的粒子对象。这样可以方便地遍历和绘制不同颜色的粒子。

draw() 函数中,我们使用 rect() 函数来绘制背景。由于我们希望背景具有一定的透明度,所以使用了 fill() 函数来设置背景颜色的透明度。

js 复制代码
// 定义粒子类
class Particle {
    constructor(loc_, dir_, speed_) {
        this.loc = loc_; // 粒子位置向量
        this.dir = dir_; // 粒子方向向量
        this.speed = speed_; // 粒子速度
        this.d = 1; // 粒子大小系数
    }

    // 粒子运动,包括更新位置和速度
    move() {
        // 使用 Perlin 噪声计算粒子的角度
        this.angle = noise(this.loc.x / noiseScale, this.loc.y / noiseScale, frameCount / noiseScale) * TWO_PI * noiseStrength;
        // 根据角度计算粒子的方向向量
        this.dir.x = cos(this.angle) + sin(this.angle) - sin(this.angle);
        this.dir.y = sin(this.angle) - cos(this.angle) * sin(this.angle);
        // 根据方向向量计算粒子的速度向量
        this.vel = this.dir.copy();
        this.vel.mult(this.speed * this.d);
        // 更新粒子的位置向量
        this.loc.add(this.vel);
    }

    // 检测粒子是否碰到边界,如果是则重新生成粒子
    checkEdges() {
        if (this.loc.x < 0 || this.loc.x > width || this.loc.y < 0 || this.loc.y > height) {
            this.loc.x = random(width * 1.2);
            this.loc.y = random(height);
        }
    };

    // 更新粒子的大小和位置
    update(r) {
        ellipse(this.loc.x, this.loc.y, r);
    };

    // 粒子的总运动,包括运动、碰撞检测和更新
    run() {
        this.move();
        this.checkEdges();
        this.update();
    }
}

// 粒子数量
let num = 1024;

// 粒子数组
var particles_a = [];
var particles_b = [];
var particles_c = [];

// 粒子消失的速度
var fade = 600;

// 粒子半径
var radius = 3; 

// 噪声的规模
let noiseScale = 400;

// 噪声的强度
let noiseStrength = 1.4;

function setup() {
    createCanvas(windowWidth, windowHeight);
    noStroke();
    // 创建粒子数组
    for (let i = 0; i < num; i++) {
        // 随机生成粒子的位置向量和方向向量
        let loc_a = createVector(random(width * 1.2), random(height), 2);
        let angle_a = random(TWO_PI);
        let dir_a = createVector(cos(angle_a), sin(angle_a));
        let loc_b = createVector(random(width * 1.2), random(height), 2);
        let angle_b = random(TWO_PI);
        let dir_b = createVector(cos(angle_b), sin(angle_b));
        let loc_c = createVector(random(width * 1.2), random(height), 2);
        let angle_c = random(TWO_PI);
        let dir_c = createVector(cos(angle_c), sin(angle_c));
        // 创建粒子对象并添加到数组中
        particles_a[i] = new Particle(loc_a, dir_a, 0.5);
        particles_b[i] = new Particle(loc_b, dir_b, 0.5);
        particles_c[i] = new Particle(loc_c, dir_c, 0.75);

    }
}

function draw() {
    // 绘制背景
    fill(0, 2); 
    noStroke();
    rect(0, 0, width, height);

    // 遍历所有的粒子
    for (let i = 0; i < num; i++) {
        // 绘制蓝色粒子
        fill(255, fade); 
        particles_a[i].move();
        particles_a[i].update(radius);
        particles_a[i].checkEdges();

        // 绘制青色粒子
        fill(0, 255, 255, fade); 
        particles_b[i].move();
        particles_b[i].update(radius);
        particles_b[i].checkEdges();

        // 绘制浅蓝色粒子
        fill(102, 153, 255, fade); 
        particles_c[i].move();
        particles_c[i].update(radius);
        particles_c[i].checkEdges();
    }
}

Particle 类中,我们定义了四个方法:

  1. constructor() 方法:在创建粒子对象时,初始化粒子的位置向量、方向向量、速度和大小系数。

  2. move() 方法:根据 Perlin 噪声计算粒子的角度,并根据角度计算粒子的方向向量和速度向量,最后根据速度向量更新粒子的位置向量。

  3. checkEdges() 方法:检测粒子是否碰到边界,如果是则重新生成粒子。

  4. update() 方法:更新粒子的大小和位置。

setup() 函数中,我们完成了以下工作:

  1. 创建画布。

  2. 创建粒子数组。

  3. 随机生成粒子的位置向量和方向向量,并创建粒子对象并添加到数组中。

draw() 函数中,我们完成了以下工作:

  1. 绘制背景。

  2. 遍历所有的粒子,在每个粒子的位置绘制相应颜色的粒子。

  3. 调用粒子对象的方法,包括运动、碰撞检测和更新。

相关推荐
万物得其道者成4 小时前
前端大整数精度丢失:一次踩坑后的实战解决方案(`json-bigint`)
前端·json
鹏北海5 小时前
移动端 H5 响应式字体适配方案完全指南
前端
柳杉7 小时前
使用AI从零打造炫酷医疗数据可视化大屏,源码免费拿!
前端·javascript·数据可视化
凌云拓界7 小时前
前端开发的“平衡木”:在取舍之间找到最优解
前端·性能优化·架构·前端框架·代码规范·设计规范
zhengfei6117 小时前
【XSS payload 】一个经典的XSS payload
前端·xss
全栈老石8 小时前
手写一个无限画布 #1:坐标系的谎言
前端·canvas
XW01059999 小时前
4-11判断素数
前端·python·算法·素数
J2虾虾9 小时前
Spring Boot中使用@Scheduled做定时任务
java·前端·spring boot
Heo9 小时前
深入React19任务调度器Scheduler
前端·javascript·面试
一枚前端小姐姐9 小时前
Vue3 + Pinia 状态管理,从入门到模块化
前端·vue.js