可视化之粒子风场

绘制风场的关键点在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. 调用粒子对象的方法,包括运动、碰撞检测和更新。

相关推荐
程序员码歌2 小时前
短思考第261天,浪费时间的十个低效行为,看看你中了几个?
前端·ai编程
Swift社区3 小时前
React Navigation 生命周期完整心智模型
前端·react.js·前端框架
若梦plus3 小时前
从微信公众号&小程序的SDK剖析JSBridge
前端
用泥种荷花4 小时前
Python环境安装
前端
Light604 小时前
性能提升 60%:前端性能优化终极指南
前端·性能优化·图片压缩·渲染优化·按需拆包·边缘缓存·ai 自动化
Jimmy4 小时前
年终总结 - 2025 故事集
前端·后端·程序员
烛阴4 小时前
C# 正则表达式(2):Regex 基础语法与常用 API 全解析
前端·正则表达式·c#
roman_日积跬步-终至千里4 小时前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
GIS之路4 小时前
GIS 数据转换:使用 GDAL 将 TXT 转换为 Shp 数据
前端
多看书少吃饭4 小时前
从Vue到Nuxt.js
前端·javascript·vue.js