123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- // 定义Partical类
- import * as THREE from 'three';
- import gsap from 'gsap';
- export default class SmokePartical {
- range; // 粒子的分布半径
- center; // 粒子的分布中心
- life; // 粒子的存活时间,毫秒
- createTime; // 粒子创建时间
- updateTime; // 上次更新时间
- size; // 粒子大小
- opacityFactor; // 粒子透系数
- opacity = 0; //粒子透明度
- scale = 0; // 粒子缩放量
- scaleFactor; //粒子放大系数
- position; // 粒子位置
- speed; //粒子扩散速度
- normal; // 粒子法向
- pathArr = []; // 运动路径对象,包含路径、是否扩散等信息
- pathLifeRatio: number[] = [];
- updateFactor = 5;
- pathIndex = 0;
- isDie = false;
- currentPathAlpha = 0; // 当前路段的插值因素
- // 动画更新系数;
- constructor(range = 10, center = { x: 0, y: 0, z: 0 }, opacityFactor, scaleFactor, life, pathArr?) {
- this.range = range;
- this.center = center;
- this.life = life;
- this.createTime = Date.now();
- this.updateTime = Date.now();
- this.size = 15;
- // 粒子透明度,及系数
- this.opacityFactor = opacityFactor;
- // this.opacity = 1 * this.opacityFactor;
- // 粒子放大量,及放大系数
- this.scaleFactor = scaleFactor;
- this.position = {
- x: 0,
- y: 0,
- z: 0,
- };
- this.initDistance(pathArr);
- }
- initDistance(pathArr) {
- let totalLen = 0;
- const pathLen: number[] = [];
- for (let i = 0; i < pathArr.length; i++) {
- const obj = {
- path0: pathArr[i].path0.clone(),
- path1: pathArr[i].path1.clone(),
- isSpread: pathArr[i].isSpread,
- spreadDirection: pathArr[i].spreadDirection, // 1是由小变大,-1是由大变小
- spreadRang: pathArr[i]['spreadRang'] || 0,
- };
- if (obj.isSpread) {
- if (obj.spreadDirection >= 1) {
- let vec;
- if (Math.abs(obj.path0.y - obj.path1.y) > 3) {
- const len = obj.spreadRang ? obj.spreadRang : 8;
- vec = new THREE.Vector3(
- (Math.random() * 2 - 1) * 3 + obj.path1.x,
- Math.random() * len + obj.path1.y,
- (Math.random() * 2 - 1) * 3 + obj.path1.z
- );
- } else {
- vec = new THREE.Vector3(
- (Math.random() * 2 - 1) * 3 + obj.path1.x,
- (Math.random() * 2 - 1) * 3 + obj.path1.y,
- (Math.random() * 2 - 1) * 3 + obj.path1.z
- );
- }
- obj.path1.copy(vec);
- } else if (obj.spreadDirection == -1) {
- let vec;
- if (Math.abs(obj.path0.y - obj.path1.y) > 3) {
- vec = new THREE.Vector3(
- (Math.random() * 2 - 1) * 3 + obj.path0.x,
- Math.random() * 8 + obj.path0.y,
- (Math.random() * 2 - 1) * 3 + obj.path0.z
- );
- } else {
- vec = new THREE.Vector3(
- (Math.random() * 2 - 1) * 3 + obj.path0.x,
- (Math.random() * 2 - 1) * 3 + obj.path0.y,
- (Math.random() * 2 - 1) * 3 + obj.path0.z
- );
- }
- obj.path0.copy(vec);
- }
- } else if (obj.spreadDirection != 0) {
- const len = 1;
- const vec = new THREE.Vector3(
- (Math.random() * 2 - 1) * 3 * len + obj.path0.x,
- (Math.random() * 2 - 1) * obj.spreadDirection * len + obj.path0.y,
- (Math.random() * 2 - 1) * 3 * len + obj.path0.z
- );
- const vec1 = new THREE.Vector3(
- (Math.random() * 2 - 1) * 3 * len + obj.path1.x,
- (Math.random() * 2 - 1) * obj.spreadDirection * len + obj.path1.y,
- (Math.random() * 2 - 1) * 3 * len + obj.path1.z
- );
- obj.path0.copy(vec);
- obj.path1.copy(vec1);
- }
- this.pathArr.push(obj);
- const len = obj.path0.distanceTo(obj.path1);
- pathLen.push(len);
- totalLen += len;
- }
- pathLen.forEach((len) => {
- this.pathLifeRatio.push(len / totalLen);
- });
- }
- // 更新粒子
- update() {
- if (!this.pathArr || this.pathArr.length - 1 < this.pathIndex) {
- this.isDie = true;
- return;
- }
- let isFirst = false;
- if (this.currentPathAlpha == 0) {
- isFirst = true;
- }
- const pathArr = this.pathArr[this.pathIndex];
- const position = new THREE.Vector3(this.position.x, this.position.y, this.position.z);
- const life = this.pathLifeRatio[this.pathIndex] * this.life;
- this.currentPathAlpha += 1 / life;
- const currentPathAlpha = this.currentPathAlpha > 1 ? 1 : this.currentPathAlpha;
- position.lerpVectors(pathArr.path0, pathArr.path1, currentPathAlpha);
- if (position != undefined) {
- // 更新位置
- this.position.x = position.x;
- this.position.y = position.y;
- this.position.z = position.z;
- if (!pathArr.isSpread) {
- if (isFirst) this.opacity = this.opacityFactor * 0.5;
- if (isFirst) this.scale = ((0.3 * Math.random() + 0.7) / 2) * this.scaleFactor;
- } else {
- if (pathArr.spreadDirection == 1) {
- // 计算粒子透明度
- this.opacity = 1 - currentPathAlpha;
- this.opacity *= this.opacityFactor * 0.5;
- if (this.opacity < 0) this.opacity = 0;
- // 计算放大量
- this.scale = this.scaleFactor * (currentPathAlpha + 1 / 2);
- // if (this.scale > 1 + this.scaleFactor) this.scale = 1.5 * this.scaleFactor;
- } else {
- // 计算粒子透明度
- this.opacity = currentPathAlpha * currentPathAlpha * currentPathAlpha;
- // this.opacity = this.currentPathAlpha;
- this.opacity *= this.opacityFactor * 0.5;
- if (this.opacity < 0) this.opacity = 0;
- // 计算放大量
- this.scale = this.scaleFactor * (1 - currentPathAlpha + 1 / 2);
- }
- }
- if (this.currentPathAlpha >= 1) {
- ++this.pathIndex;
- this.currentPathAlpha = 0;
- }
- }
- }
- controlUpdate() {
- // gsap.to(this.speed, {
- // x: 250,
- // duration: 1,
- // ease: 'none',
- // repeat: -1,
- // });
- }
- }
|