可视化之粒子风场

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

相关推荐
mldong1 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排2 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60612 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角3 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!3 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰4 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi5 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen6 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马6 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒7 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端