||

p5-vue:使用柏林噪声生成有趣的动态图案

前面的博文中通过封装了一个 p5-vue 组件,使得在 Vue 项目中应用 p5.js 的强大绘图能力成为可能。本篇主要介绍一下 p5.js 中的柏林噪声,以及通过柏林噪声来绘制一些极富创造力的美丽图案。

柏林噪声

Perlin噪声 ( Perlin noise )指由Ken Perlin发明的自然噪声生成算法 。

一个噪声函数基本上是一个种子随机发生器。它需要一个整数作为参数,然后根据这个参数返回一个随机数。如果你两次都传同一个参数进来,它就会产生两次相同的数。这条规则非常重要,它确定了柏林噪声的确定性。

一般来说,通过柏林噪声可以产生连续性很好的数据,原因在于其生成的随机数会基于上一条随机数来计算,所以其随机噪声不是完全杂乱无章的。

p5-vue

基于上篇文章封装的组件,在外部组件中引用 p5-vue 。

<template>
  <div id="app">
      <p5 :sketch="sketch"></p5>
  </div>
</template>

定义绘图函数的来源。

import p5 from '@/components/P5'
import p5_demo from './lib/p5/demo'

export default {
    name: 'App',
    components: {
        p5
    },
    data() {
        return {
            width: 600,
            height: 600
        }
    },
    methods: {

        sketch(p5) {
            return p5_demo(p5, this);
        }
    }
}

然后定义绘图函数,绘图的尺寸由外部组件的 data 对象来定义,通过 context 上下文对象传入到绘图函数中。

module.exports = (p5, context) => {
    let margin = 44;
    let density = 1 / 650;
    let nLines = 64;
    let s;
    let interLines;

    p5.setup = () => {
        p5.createCanvas(context.width, context.height);
        p5.colorMode(p5.HSB, 1);
        p5.noFill();
        p5.stroke(0);
        p5.strokeWeight(2.5);
        p5.strokeCap(p5.SQUARE);

        s = p5.width - 2 * margin;
        interLines = s / (nLines - 1);
    }

    p5.draw = () => {
        p5.background(0.15, 0.9, 1);

        p5.translate(margin, margin);
        for (let i = 0; i < nLines; i++) {
            let y = interLines * i;
            p5.beginShape();
            for (let x = 0; x < s; x++) {
                let offset = 0;
                let noize = p5.noise(x * density, y * density, p5.frameCount / 700);
                let factor = 0;
                if (p5.floor(noize * 50) % 2 === 0) {
                    factor = interLines / 3;
                }
                offset = p5.cos(x / 2 - p5.frameCount / 10) * factor;
                p5.curveVertex(x, y + offset);
            }
            p5.endShape();
        }
    }
}

最后得到的绘图效果:

其他效果

修改绘图函数,通过柏林噪声加上粒子系统,可以绘制更复杂的图案,例如下图。

绘图函数如下:

module.exports = (p5, context) => {
    let particles_a = [];
    let particles_b = [];
    let particles_c = [];
    let nums = 200;
    let noiseScale = 800;

    p5.setup = () => {
        p5.createCanvas(context.width, context.height);
        p5.background(21, 8, 50);
        for (let i = 0; i < nums; i++) {
            particles_a[i] = new Particle(p5.random(0, p5.width), p5.random(0, p5.height));
            particles_b[i] = new Particle(p5.random(0, p5.width), p5.random(0, p5.height));
            particles_c[i] = new Particle(p5.random(0, p5.width), p5.random(0, p5.height));
        }
    }

    p5.draw = () => {
        p5.noStroke();
        p5.smooth();
        for (let i = 0; i < nums; i++) {
            let radius = p5.map(i, 0, nums, 1, 2);
            let alpha = p5.map(i, 0, nums, 0, 250);

            p5.fill(69, 33, 124, alpha);
            particles_a[i].move();
            particles_a[i].display(radius);
            particles_a[i].checkEdge();

            p5.fill(7, 153, 242, alpha);
            particles_b[i].move();
            particles_b[i].display(radius);
            particles_b[i].checkEdge();

            p5.fill(255, 255, 255, alpha);
            particles_c[i].move();
            particles_c[i].display(radius);
            particles_c[i].checkEdge();
        }
    }


    function Particle(x, y) {
        this.dir = p5.createVector(0, 0);
        this.vel = p5.createVector(0, 0);
        this.pos = p5.createVector(x, y);
        this.speed = 0.4;

        this.move = function () {
            let angle = p5.noise(this.pos.x / noiseScale, this.pos.y / noiseScale) * p5.TWO_PI * noiseScale;
            this.dir.x = p5.cos(angle);
            this.dir.y = p5.sin(angle);
            this.vel = this.dir.copy();
            this.vel.mult(this.speed);
            this.pos.add(this.vel);
        }

        this.checkEdge = function () {
            if (this.pos.x > p5.width || this.pos.x < 0 || this.pos.y > p5.height || this.pos.y < 0) {
                this.pos.x = p5.random(50, p5.width);
                this.pos.y = p5.random(50, p5.height);
            }
        }

        this.display = function (r) {
            p5.ellipse(this.pos.x, this.pos.y, r, r);
        }
    }
}

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注