【threejs】创建沿轨迹流动的粒子效果

基本思路

使用bufferGeometry创建沿着轨迹的网格(geometry),再使用threjs的point对象实体化粒子组成的路径,最后在动画回调中更新每个粒子的位置,然后更新网格的points

粒子路径

粒子对象

使用class管理整个粒子系统

import {
BufferGeometry,
Float32BufferAttribute,
Points,
PointsMaterial,
} from "three";
/**
* roll particles through a path form series of vec3
*/
export default class ParticleGroup {
path = []; //PATH OF LINE
pathLength = 0;
particles = []; //PARTICLES points
counts = 300; //Particles mounts
radius = 1;
mesh;
t = 0;
constructor(path) {
  this.path = path;
  this.pathLength = path.length;

  this.init();
}

init = () => {
  let { counts, particles, path, radius, pathLength } = this;

  for (let i = 0; i < counts; i++) {
    const index = Math.floor((pathLength / counts) * i);
    const current = path[index];
    const { x, y, z } = current;
    const dx = (Math.random() - 0.5) * radius;
    const dy = (Math.random() - 0.5) * radius;
    const dz = (Math.random() - 0.5) * radius;
    //   vertices.push(x + dx, y + dy, z + dz);
    const particle = new Particle(x, y, z, dx, dy, dz, index, i);
    particles.push(particle);
    //   const
  }

  const vertices = this.getVertices();
  const geometry = new BufferGeometry();
  geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));
  const material = new PointsMaterial({ size: 0.03, color: 0x00ffff });
  let points = new Points(geometry, material);
  this.mesh = points;
  //   scene.add(points);
};

//   get current paritcle group geometry's vectices
getVertices = () => {
  let { path, pathLength } = this;

  const vertices = [];
  this.particles.forEach((particle) => {
    let { dx, dy, dz, index, id } = particle;
    const current = path[index];
    const { x, y, z } = current;
    let expandScale =
      // (3 - (index / pathLength) * 3) * Math.sin((id * index) / 10000) + 0.8;
      (5 - (index / pathLength) * 5) * Math.sin(id) * Math.sin(index / 100) +
      0.3;
    // (3 - (index / pathLength) * 3) * Math.sin(id) + 0.3;
    vertices.push(
      x + dx * expandScale,
      y + dy * expandScale,
      z + dz * expandScale
    );
  });

  return vertices;
};
// update particle index
upDateParitcles = () => {
  let { particles, pathLength } = this;
  particles.forEach((particle) => {
    particle.index += 1;
    if (particle.index == pathLength) {
      particle.index = 0;
    }
  });
};
//   update mesh geometry
upDateMeshGeometry = () => {
  let vertices = this.getVertices();
  const geometry = this.mesh.geometry;
  geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));
  this.mesh.geometry = geometry;
};
render = () => {
  requestAnimationFrame(this.render);
  let { particles, pathLength } = this;
  this.t += 0.01;
  this.upDateParitcles();

  this.upDateMeshGeometry();
};

//   add mesh to group or scene
addto = (group) => {
  group.add(this.mesh);
};
}

class Particle {
x;
y;
z;
dx;
dy;
dz;
index;
id;
constructor(x, y, z, dx, dy, dz, index, id) {
  this.x = x;
  this.y = y;
  this.z = z;
  this.dx = dx;
  this.dy = dy;
  this.dz = dz;
  this.index = index;
  this.id = id;
}
}

在场景中使用


const path = new THREE.CatmullRomCurve3([
    new THREE.Vector3(0, -4, -4),
    new THREE.Vector3(-4, 0 - 4),
    new THREE.Vector3(-4, 0, 4),
    new THREE.Vector3(4, 0, 4),
    new THREE.Vector3(4, 0, -4),
  ]);
  const PS = path.getPoints(2000);
  const parts = new ParticleGroup(PS);
  console.log(parts);
  parts.addto(scene);
  parts.render();
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是提供 vue 下 three.js 粒子效果的函数代码: ```javascript <template> <div ref="container"></div> </template> <script> import * as THREE from 'three'; export default { name: 'ParticleEffect', props: { particleCount: { type: Number, default: 100 }, particleSize: { type: Number, default: 1 }, particleColor: { type: String, default: '#ffffff' }, particleSpeed: { type: Number, default: .1 } }, mounted() { this.init(); this.animate(); }, methods: { init() { this.scene = new THREE.Scene(); this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100); this.camera.position.z = 500; this.renderer = new THREE.WebGLRenderer(); this.renderer.setSize(window.innerWidth, window.innerHeight); this.$refs.container.appendChild(this.renderer.domElement); this.particles = new THREE.Geometry(); for (let i = ; i < this.particleCount; i++) { const particle = new THREE.Vector3( Math.random() * 100 - 500, Math.random() * 100 - 500, Math.random() * 100 - 500 ); this.particles.vertices.push(particle); } const particleMaterial = new THREE.PointsMaterial({ color: this.particleColor, size: this.particleSize }); this.particleSystem = new THREE.Points(this.particles, particleMaterial); this.scene.add(this.particleSystem); }, animate() { requestAnimationFrame(this.animate); this.particleSystem.rotation.x += this.particleSpeed; this.particleSystem.rotation.y += this.particleSpeed; this.renderer.render(this.scene, this.camera); } } }; </script> ``` 希望对你有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸢_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值