Three.js 粒子特效实战①:用 Three.Quarks 打造拟真火焰喷射与喷泉效果

在游戏场景的技能光效、网页活动的动态背景、数据可视化的粒子流中,我们总能看到炫酷的粒子特效,类似这种👇👇👇

图片

image.png

体验地址:

https://opensource.icegl.cn/#/plugins/visualArts/imgParticle

这些效果看似复杂,实则可通过 Three.js 的专用粒子库 Three.Quarks 高效实现。

本系列课程我们将带着大家从基础到进阶拆解 Three.Quarks 的实战应用,并通过三个案例详解粒子特效的实现逻辑与操作步骤,帮助大家掌握酷炫粒子效果的开发方法。

  1. 火焰喷射效果&喷泉效果

  2. 粒子重组效果

  3. 引用官方的粒子json文件

今天我们实现一下 火焰喷射效果&喷泉效果

基本api使用

以下是使用three.quark粒子系统的基本流程

1.创建粒子渲染器以及粒子容器

// 创建粒子系统批量渲染器
const batchRenderer = new BatchedParticleRenderer();
const group = new THREE.Group();

2.创建粒子系统

const particles = new ParticleSystem({
	...粒子系统参数
});

什么是粒子系统? 打一个比方,在消防员灭火的时候,喷枪中会喷射出很多的水,每一个水滴如果是一个粒子的话,那么粒子系统就是消防员手中的喷枪,可以决定粒子的喷射方式,喷射速度,喷射时间等等

3.将粒子系统添加到粒子渲染器中

group.add(particles.emitter);
batchRenderer.addSystem(particles);
scene.add(group);

4.在动画函数中更新渲染器

const clock = new THREE.Clock();
renderer.setAnimation(() => {
  const delta = clock.getDelta();
  renderer.render(scene, camera);
  // 渲染循环中更新粒子
  if (batchRenderer) {
    batchRenderer.update(delta);
  }
});

具体的流程并不复杂,粒子系统中复杂的是ParticleSystem中的参数

先来看看上图中火焰效果的参数

以下参数的解释分别为:

1.duration 整个粒子动画的周期

2.looping 粒子动画是否循环播放

3.startLife 粒子的生命周期时长,这里设置为IntervalValue数据,这个是three.quark自带的数据类型,可以描述一个随机范围,粒子的生命周期时长将处于5---9秒

4.startSpeed 粒子的速度,这里也可以设置为一个范围数据,如果想要设置为固定数据,可以填ConstantValue

5.startSize 粒子的大小,取值逻辑同上

6.emissionOverTime 粒子的排放数量,数量越多粒子越多

7.shape 粒子发射器的类型,在quark中有很多排放类型, 比如圆形排放,锥形排放,这里火焰是呈锥形排放的

8.material 每个粒子的材质,可以写入一个基本材质

const particles = new ParticleSystem({
  duration: 20,
  looping: true,
  startLife: new IntervalValue(5, 9),
  startSpeed: new IntervalValue(0.8,1.2),
  startSize: new IntervalValue(0.5, 1),
  emissionOverTime: new ConstantValue(100),
  shape: new ConeEmitter({
    radius: 0,
    arc: Math.PI * 2,
    angle:Math.PI/4
  }),
  material: new THREE.MeshBasicMaterial({
    map: texture,
    transparent: true,
    side: THREE.DoubleSide,
    depthWrite: false,
  }),
});

实现火焰效果

实现效果

源码实现

省略threejs的基本环境配置
// -----------------------------------------实现粒子效果---------------------------------------
const group = new THREE.Group();

// 创建粒子系统批量渲染器
const batchRenderer = new BatchedParticleRenderer();
group.add(batchRenderer);

const loader = new THREE.TextureLoader();
const texture = loader.load("/src/assets/texture/smoke.png");

// 初始化粒子系统,并绑定材质
// 动画时长20s,循环执行,每个粒子的生命周期在0-10s随机,速度在0-500s随机,大小在0-100随机
// emissionOverTime是发射多少个粒子
// shape是粒子发射器的类型
const particles = new ParticleSystem({
  duration: 20,
  looping: true,
  startLife: new IntervalValue(5, 9),
  startSpeed: new IntervalValue(0.8,1.2),
  startSize: new IntervalValue(0.5, 1),
  emissionOverTime: new ConstantValue(100),
  shape: new ConeEmitter({
    radius: 0,
    arc: Math.PI * 2,
    angle:Math.PI/4
  }),
  material: new THREE.MeshBasicMaterial({
    map: texture,
    transparent: true,
    side: THREE.DoubleSide,
    depthWrite: false,
  }),
});
console.log(particles);

// 旋转粒子发射器,使其向上发射
particles.emitter.rotateX(-Math.PI / 2);
group.add(particles.emitter);
batchRenderer.addSystem(particles);

particles.addBehavior(
  new SizeOverLife(new PiecewiseBezier([[new Bezier(1, 0.2, 0.4, 0), 0]]))
);

const gradient = new Gradient(
  [
    [new THREE.Vector3(0.9, 0.3, 0.1), 0], // Black at position 0
    [new THREE.Vector3(0.7, 0.7, 0.1), 0.3], // Black at position 0
    [new THREE.Vector3(0.2, 0.2, 0.2), 0.5],
    [new THREE.Vector3(0,0,0), 1], // White at position 1
  ],
  [
    [1, 0], // Alpha 1 at position 0
    [0.1, 1], // Alpha 1 at position 1
  ]
);

particles.addBehavior(
  new ColorOverLife(
    gradient
  )
);

scene.add(group);
const clock = new THREE.Clock();
renderer.setAnimation(() => {
  const delta = clock.getDelta();
  renderer.render(scene, camera);
  // 渲染循环中更新粒子
  if (batchRenderer) {
    batchRenderer.update(delta);
  }
});

实现原理

在基本的api使用基础上,添加了粒子系统的行为模式设置

核心api

particles.addBehavior

粒子的行为模式设置可以决定粒子在生命周期中的状态,这个状态可以是颜色,大小,速度等属性

比如火焰的颜色从刚开始的时候应该是明黄色,但是如果到了末尾,颜色应该变为灰色或者黑色。

又比如喷泉的效果需要在粒子上升之后又随着重力下降,这种状态变化也是行为模式Behavior

quark的行为模式放在了文档behavior章节中,我们学习基本的即可

这里需要让粒子在生命周期中颜色不断发生变化,可以设置颜色行为模式

这里一定要使用quarks的数据格式,比如Gradient,就是quarks专用的渐变颜色格式

这里我设置了四个颜色阶段,粒子会从比较橙黄色慢慢变化到灰色,透明度也会慢慢变淡

const gradient = new Gradient(
  [
    [new THREE.Vector3(0.9, 0.3, 0.1), 0], // Black at position 0
    [new THREE.Vector3(0.7, 0.7, 0.1), 0.3], // Black at position 0
    [new THREE.Vector3(0.2, 0.2, 0.2), 0.5],
    [new THREE.Vector3(0,0,0), 1], // White at position 1
  ],
  [
    [1, 0], // Alpha 1 at position 0
    [0.1, 1], // Alpha 1 at position 1
  ]
);

particles.addBehavior(
  new ColorOverLife(
    gradient
  )
);

同时,我还设置了粒子大小的行为模式,因为火焰的扩散是从小到大的,这里设置一个贝塞尔曲线的数值,PiecewiseBezier中要求的参数是一个curve,也就是我们之前讲过的曲线,这里的数值会从0.3慢慢变化到3,数组中第二个参数固定填0即可

particles.addBehavior(
  new SizeOverLife(new PiecewiseBezier([[new Bezier(0.3, 0.6, 2.4, 3), 0]]))
);

实现喷泉效果

实现效果

源码

省略threejs的基本场景搭建
// -----------------------------------------实现粒子效果---------------------------------------
const group = new THREE.Group();

// 创建粒子系统批量渲染器
const batchRenderer = new BatchedParticleRenderer();
group.add(batchRenderer);

const loader = new THREE.TextureLoader();
const texture = loader.load("/src/assets/texture/fountain.png");

const particles = new ParticleSystem({
  duration: 20,
  looping: true,
  startLife: new IntervalValue(20, 60),
  startSpeed: new IntervalValue(1200, 1400),
  startSize: new IntervalValue(0, 10),
  emissionOverTime: new ConstantValue(2000),
  renderMode: RenderMode.Trail,
  rendererEmitterSettings: {
    startLength: new ConstantValue(5),
  },
  shape: new ConeEmitter({
    radius: 0,
    arc: Math.PI * 2,
  }),
  material: new THREE.MeshBasicMaterial({
    map: texture,
    transparent: true,
    side: THREE.DoubleSide,
  }),
});
particles.emitter.rotateX(-Math.PI / 2);
group.add(particles.emitter);
batchRenderer.addSystem(particles);

particles.addBehavior(
  new SizeOverLife(new PiecewiseBezier([[new Bezier(1, 0.2, 0.4, 0), 0]]))
);

const gradient = new Gradient(
  [
    [new THREE.Vector3(1, 1, 1), 0], // Black at position 0
    [new THREE.Vector3(0, 0, 0), 1], // White at position 1
  ],
  [
    [1, 0], // Alpha 1 at position 0
    [0, 1], // Alpha 1 at position 1
  ]
);

particles.addBehavior(new ColorOverLife(gradient));

// 使用重力
particles.addBehavior(
  new ApplyForce(new THREE.Vector3(0, 0, -1), new ConstantValue(1000))
);

// 添加速度变化
particles.addBehavior(
    new SpeedOverLife(new PiecewiseBezier(
        [
            [
                new Bezier(1.5 ,0.8, 0.4, 0),
                0
            ]
        ]
    ))
);

scene.add(group);
const clock = new THREE.Clock();
renderer.setAnimation(() => {
  const delta = clock.getDelta();
  renderer.render(scene, camera);
  // 渲染循环中更新粒子
  if (batchRenderer) {
    batchRenderer.update(delta);
  }
});

实现原理

有了上一节的基础,再来实现喷泉就很简单了

我们将材质的图片替换为喷泉粒子的图片,并且设置好基本参数,这里新增的设置包括

1.renderMode:RenderMode.Trail 这个配置可以让喷泉效果具有拖尾的感觉

2.rendererEmitterSettings :配合renderMode使用,设置拖尾的长度

const loader = new THREE.TextureLoader();
const texture = loader.load("/src/assets/texture/fountain.png");

const particles = new ParticleSystem({
  duration: 20,
  looping: true,
  startLife: new IntervalValue(20, 60),
  startSpeed: new IntervalValue(1200, 1400),
  startSize: new IntervalValue(0, 10),
  emissionOverTime: new ConstantValue(2000),
  renderMode: RenderMode.Trail,
  rendererEmitterSettings: {
    startLength: new ConstantValue(5),
  },
  shape: new ConeEmitter({
    radius: 0,
    arc: Math.PI * 2,
  }),
  material: new THREE.MeshBasicMaterial({
    map: texture,
    transparent: true,
    side: THREE.DoubleSide,
  }),
});

然后我添加了粒子大小的行为模式,并让喷泉粒子在喷射之后不断变小

particles.addBehavior(
  new SizeOverLife(new PiecewiseBezier([[new Bezier(1, 0.2, 0.4, 0), 0]]))
);

添加颜色的简单变化,让喷泉粒子不断变淡

const gradient = new Gradient(
  [
    [new THREE.Vector3(1, 1, 1), 0], // Black at position 0
    [new THREE.Vector3(0, 0, 0), 1], // White at position 1
  ],
  [
    [1, 0], // Alpha 1 at position 0
    [0, 1], // Alpha 1 at position 1
  ]
);

particles.addBehavior(new ColorOverLife(gradient));

添加重力行为模式,这里让重力朝-z方向,因为我们的粒子系统是做了旋转的,所以-z才是重力方向

调整重力的强度为1000

particles.addBehavior(
  new ApplyForce(new THREE.Vector3(0, 0, -1), new ConstantValue(1000))
);

添加粒子的速度变化

// 添加速度变化
particles.addBehavior(
    new SpeedOverLife(new PiecewiseBezier(
        [
            [
                new Bezier(1.5 ,0.8, 0.4, 0),
                0
            ]
        ]
    ))
);

来源:https://mp.weixin.qq.com/s/PX-iDJ6IKyBXpBzt7SHHRw

webgis开发学习资料+下方↓↓小助手

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值