Skip to content

158. 粒子生命周期行为控制

Published:

上节学了各种形状的粒子发射器,但它们还是有些呆板。

比如我希望粒子在运动的过程中逐渐变小,而现在粒子大小是不变的。

2025-06-01 17.04.02.gif

比如我希望粒子在运动过程中颜色逐渐变浅,而现在粒子颜色也是不变的。

还有,我希望粒子运动速度是先快后慢,而现在也是控制不了的。

如何控制粒子运动过程中的行为呢?

这就要用 addBehavior 的 api 了。

我们来试试:

npx create-vite three-quarks-behavior-control

image.png

进入项目,安装依赖:

npm install
npm install --save three
npm install --save-dev @types/three

改下 src/main.js

import './style.css';
import * as THREE from 'three';
import {
    OrbitControls
} from 'three/addons/controls/OrbitControls.js';
import mesh from './mesh.js';

const scene = new THREE.Scene();

scene.add(mesh);

const directionLight = new THREE.DirectionalLight(0xffffff);
directionLight.position.set(500, 600, 800);
scene.add(directionLight);

const ambientLight = new THREE.AmbientLight();
scene.add(ambientLight);

const helper = new THREE.AxesHelper(1000);
scene.add(helper);

const width = window.innerWidth;
const height = window.innerHeight;

const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 10000);
camera.position.set(500, 600, 800);
camera.lookAt(0, 0, 0);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height)

function render() {
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

render();

document.body.append(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);

创建 Scene、Light、Camera、Renderer。

改下 style.css

body {
  margin: 0;
}

安装下粒子效果库:

npm install --save three.quarks

在 mesh.js 初始化下 three.quarks

import * as THREE from "three";
import { BatchedParticleRenderer, ConstantValue, GridEmitter, IntervalValue, ParticleSystem,PointEmitter,RandomColor, RenderMode } from "three.quarks";

const group = new THREE.Group();

const batchRenderer = new BatchedParticleRenderer();
group.add(batchRenderer);

const loader = new THREE.TextureLoader();
const texture = loader.load('./point.png');

const particles = new ParticleSystem({
    duration: 5,
    looping: true,
    startLife: new IntervalValue(0, 3),
    startSpeed: new IntervalValue(0, 600),
    startSize: new ConstantValue(100),
    startColor: new RandomColor(
        new THREE.Vector4(1, 0.5, 0.5, 1),
        new THREE.Vector4(0.5, 0.5, 1, 1)
    ),
    emissionOverTime: new ConstantValue(5),
    shape: new GridEmitter({
        width: 300,
        height: 300,
        row: 1,
        column: 1
    }),
    material: new THREE.MeshBasicMaterial({
        map: texture,
        transparent: true,
        side: THREE.DoubleSide
    })
});

group.add(particles.emitter);

batchRenderer.addSystem(particles);

export {
    batchRenderer
}

export default group;

我们主要是看粒子的变化,所以用了 GridEimtter,一行一列。

然后每次发射 5 个粒子,大小是固定的 100

在 main.js 里引入下:

import { batchRenderer } from './mesh.js';
const clock = new THREE.Clock();
function render() {
    const delta = clock.getDelta();
    renderer.render(scene, camera);
    requestAnimationFrame(render);

    if(batchRenderer) {
      batchRenderer.update(delta);
    }
}
render();

跑一下:

npm run dev

image.png

2025-06-01 17.26.03.gif

可以看到,在整个生命周期中,粒子大小都是不变的。

如何让粒子在生命周期中逐渐变小呢?

使用 addBehavior 来添加行为。

image.png

SizeOverLife 是 size 在整个生命周期的变化。

我们定义贝塞尔曲线来变化,四个值分别是 4 个时间点的大小。

particles.addBehavior(
    new SizeOverLife(new PiecewiseBezier(
        [
            [
                new Bezier(1, 0.7, 0.3, 0),
                0
            ]
        ]
    ))
)

2025-06-01 17.34.34.gif

可以看到,现在粒子就会逐渐变小了。

速度也可以变化,现在是匀速:

image.png

particles.addBehavior(
    new SpeedOverLife(new PiecewiseBezier(
        [
            [
                new Bezier(0.1 ,0.8, 0.3, 10),
                0
            ]
        ]
    ))
);

最开始是初始速度的 0.1,先变大,后变小,最后结束的时候加速到 10 倍速度。

看下效果:

2025-06-01 17.46.12.gif

可以看到,开始比较慢,最后变的很小的时候就运动特别快了。

如果想让颜色也逐渐变化呢?

那自然就是用 ColorOverBehavior 来控制:

image.png

particles.addBehavior(
    new ColorOverLife(new ColorRange(
        new THREE.Vector4(1, 0, 0, 1),
        new THREE.Vector4(0, 0, 1, 1)
    ))
);

指定颜色变化的范围,从红变为蓝:

2025-06-01 17.47.57.gif 现在小球在运动过程中就会变色了。

此外,还可以运动过程中修改 x、y、z:

image.png

particles.addBehavior(new ForceOverLife(
    new ConstantValue(0), 
    new ConstantValue(-500), 
    new ConstantValue(0)
));

这里我们运动过程中 y 逐渐向下。

2025-06-01 17.56.24.gif

这样,就可以控制运动过程中的位置变化了。

此外,还可以变换角度,这里用圆看不出来,我们换一个图片:

heart.png

image.png

image.png

2025-06-01 17.59.02.gif

可以看到,现在心在运动过程中旋转角度是不变的。

这个旋转角度也可以控制:

image.png

particles.addBehavior(new RotationOverLife(
    new IntervalValue(-Math.PI, Math.PI))
);

设置一个 -Math.PI 到 Math.PI 的随机值。

2025-06-01 18.01.36.gif

这样,运动过程中就会做随机的旋转。

案例代码上传了小册仓库

总结

这节我们学了如何自定义粒子运动的生命周期中的行为。

可以通过 addBehavior 添加自定义行为:

通过自定义各种属性的变化,可以实现更复杂的粒子效果。

评论