Skip to content

160. 粒子的帧动画

Published:

前面的粒子效果都是用同一个图片:

image.png

image.png

能不能在粒子动画的过程中切换图片呢?

也就是粒子动画结合帧动画。

可以的,three-quarks 支持这个。

比如 three.quarks 仓库里的这些图片:

image.png

可以在粒子动画的过程中切换不同帧的图片,来实现更复杂的效果。

我们试一下:

npx create-vite three-quarks-frame-animation

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,ConeEmitter, ConstantValue, DonutEmitter, IntervalValue, ParticleSystem, RandomColor } 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: 20,
    looping: true,
    startLife: new IntervalValue(0, 10),
    startSpeed: new IntervalValue(0, 100),
    startSize: new IntervalValue(0, 20),
    startColor: new RandomColor(
        new THREE.Vector4(1, 0, 0, 1),
        new THREE.Vector4(0, 0, 1, 1)
    ),
    emissionOverTime: new ConstantValue(5000),
    shape: new DonutEmitter({
        radius: 300,
        arc: Math.PI * 2,
        donutRadius: 50
    }),
    material: new THREE.MeshBasicMaterial({
        map: texture,
        transparent: true,
        side: THREE.DoubleSide
    })
});

group.add(particles.emitter);

batchRenderer.addSystem(particles);

export {
    batchRenderer
}

export default group;

这次用环形粒子发射器。

point.png 从这里下载:

https://github.com/QuarkGluonPlasma/threejs-course-code/blob/main/all-shape-three-quarks/public/point.png

image.png

image.png

在 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-02 11.15.10.gif

现在每个粒子都是小圆点的图片。

image.png

three.quarks 仓库这张图片下载下来:

image.png

放 public 目录下:

image.png

那在代码里如何使用呢?

首先替换下 texture 的路径:

image.png

image.png

uTileCount: 10,
vTileCount: 10,
startTileIndex: new ConstantValue(53)

指定 u 和 v 方向都分割 10 份

startTileIndex 指定第 5 行第 3 列,这里是从 0 开始的

第五行第三列就是这个:

image.png

看下效果:

2025-06-02 11.32.11.gif

生效了,但是粒子太小看不清。

我们把粒子调大一点,数量调小:

image.png

startSize: new IntervalValue(0, 100),
emissionOverTime: new ConstantValue(50),

2025-06-02 11.34.31.gif

现在就明显多了。

然后如何让它做帧动画呢?

也是通过 addBehavior 来自定义行为:

从 53 到 61:

image.png

image.png

particles.addBehavior(
    new FrameOverLife(
        new PiecewiseBezier(
            [
                [new Bezier(53, 55, 58, 61), 0]
            ]
        )
    )
);

用 FrameOverLife 来自定义声明周期中的帧的变化。

看下效果:

2025-06-02 14.35.13.gif

现在粒子运动过程中就会切换图片了。

当然,现在可能看不清楚,我们换其他图片试试:

image.png

从 45 到 52

image.png

new Bezier(45, 48, 50, 52)

2025-06-02 14.38.33.gif

现在就可以明显看出图片的变化了。

案例代码上传了小册仓库

总结

这节我们学了如何在粒子动画的过程中让粒子实现帧动画。

首先准备一个包含多个帧的图片,设置 u 和 v 方向的分割数,然后定义从哪个开始。

之后用 addBehavior 和 FrameOverLife 来定义整个生命周期中帧的变化。

帧动画可以实现更复杂的粒子效果,比如烟雾效果、技能特效。

后面的实战会基于粒子动画和帧动画来实现逼真的粒子效果。

评论