SmokePartical.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // 定义Partical类
  2. import * as THREE from 'three';
  3. import gsap from 'gsap';
  4. export default class SmokePartical {
  5. range; // 粒子的分布半径
  6. center; // 粒子的分布中心
  7. life; // 粒子的存活时间,毫秒
  8. createTime; // 粒子创建时间
  9. updateTime; // 上次更新时间
  10. size; // 粒子大小
  11. opacityFactor; // 粒子透系数
  12. opacity = 0; //粒子透明度
  13. scale = 0; // 粒子缩放量
  14. scaleFactor; //粒子放大系数
  15. position; // 粒子位置
  16. speed; //粒子扩散速度
  17. normal; // 粒子法向
  18. pathArr = []; // 运动路径对象,包含路径、是否扩散等信息
  19. pathLifeRatio: number[] = [];
  20. updateFactor = 5;
  21. pathIndex = 0;
  22. isDie = false;
  23. currentPathAlpha = 0; // 当前路段的插值因素
  24. // 动画更新系数;
  25. constructor(range = 10, center = { x: 0, y: 0, z: 0 }, opacityFactor, scaleFactor, life, pathArr?) {
  26. this.range = range;
  27. this.center = center;
  28. this.life = life;
  29. this.createTime = Date.now();
  30. this.updateTime = Date.now();
  31. this.size = 15;
  32. // 粒子透明度,及系数
  33. this.opacityFactor = opacityFactor;
  34. // this.opacity = 1 * this.opacityFactor;
  35. // 粒子放大量,及放大系数
  36. this.scaleFactor = scaleFactor;
  37. this.position = {
  38. x: 0,
  39. y: 0,
  40. z: 0,
  41. };
  42. this.initDistance(pathArr);
  43. }
  44. initDistance(pathArr) {
  45. let totalLen = 0;
  46. const pathLen: number[] = [];
  47. for (let i = 0; i < pathArr.length; i++) {
  48. const obj = {
  49. path0: pathArr[i].path0.clone(),
  50. path1: pathArr[i].path1.clone(),
  51. isSpread: pathArr[i].isSpread,
  52. spreadDirection: pathArr[i].spreadDirection, // 1是由小变大,-1是由大变小
  53. spreadRang: pathArr[i]['spreadRang'] || 0,
  54. };
  55. if (obj.isSpread) {
  56. if (obj.spreadDirection >= 1) {
  57. let vec;
  58. if (Math.abs(obj.path0.y - obj.path1.y) > 3) {
  59. const len = obj.spreadRang ? obj.spreadRang : 8;
  60. vec = new THREE.Vector3(
  61. (Math.random() * 2 - 1) * 3 + obj.path1.x,
  62. Math.random() * len + obj.path1.y,
  63. (Math.random() * 2 - 1) * 3 + obj.path1.z
  64. );
  65. } else {
  66. const len = obj.spreadRang ? obj.spreadRang : 3;
  67. vec = new THREE.Vector3(
  68. (Math.random() * 2 - 1) * len + obj.path1.x,
  69. (Math.random() * 2 - 1) * len + obj.path1.y,
  70. (Math.random() * 2 - 1) * len + obj.path1.z
  71. );
  72. }
  73. obj.path1.copy(vec);
  74. } else if (obj.spreadDirection == -1) {
  75. let vec;
  76. if (Math.abs(obj.path0.y - obj.path1.y) > 3) {
  77. const len = obj.spreadRang ? obj.spreadRang : 8;
  78. vec = new THREE.Vector3(
  79. (Math.random() * 2 - 1) * 3 + obj.path0.x,
  80. Math.random() * len + obj.path0.y,
  81. (Math.random() * 2 - 1) * 3 + obj.path0.z
  82. );
  83. } else {
  84. const len = obj.spreadRang ? obj.spreadRang : 3;
  85. vec = new THREE.Vector3(
  86. (Math.random() * 2 - 1) * len + obj.path0.x,
  87. (Math.random() * 2 - 1) * len + obj.path0.y,
  88. (Math.random() * 2 - 1) * len + obj.path0.z
  89. );
  90. }
  91. obj.path0.copy(vec);
  92. }
  93. } else if (obj.spreadDirection != 0) {
  94. const len = 1;
  95. const vec = new THREE.Vector3(
  96. (Math.random() * 2 - 1) * 3 * len + obj.path0.x,
  97. (Math.random() * 2 - 1) * obj.spreadDirection * len + obj.path0.y,
  98. (Math.random() * 2 - 1) * 3 * len + obj.path0.z
  99. );
  100. const vec1 = new THREE.Vector3(
  101. (Math.random() * 2 - 1) * 3 * len + obj.path1.x,
  102. (Math.random() * 2 - 1) * obj.spreadDirection * len + obj.path1.y,
  103. (Math.random() * 2 - 1) * 3 * len + obj.path1.z
  104. );
  105. obj.path0.copy(vec);
  106. obj.path1.copy(vec1);
  107. }
  108. this.pathArr.push(obj);
  109. const len = obj.path0.distanceTo(obj.path1);
  110. pathLen.push(len);
  111. totalLen += len;
  112. }
  113. pathLen.forEach((len) => {
  114. this.pathLifeRatio.push(len / totalLen);
  115. });
  116. }
  117. // 更新粒子
  118. update() {
  119. if (!this.pathArr || this.pathArr.length - 1 < this.pathIndex) {
  120. this.isDie = true;
  121. return;
  122. }
  123. let isFirst = false;
  124. if (this.currentPathAlpha == 0) {
  125. isFirst = true;
  126. }
  127. const pathArr = this.pathArr[this.pathIndex];
  128. const position = new THREE.Vector3(this.position.x, this.position.y, this.position.z);
  129. const life = this.pathLifeRatio[this.pathIndex] * this.life;
  130. this.currentPathAlpha += 1 / life;
  131. const currentPathAlpha = this.currentPathAlpha > 1 ? 1 : this.currentPathAlpha;
  132. position.lerpVectors(pathArr.path0, pathArr.path1, currentPathAlpha);
  133. if (position != undefined) {
  134. // 更新位置
  135. this.position.x = position.x;
  136. this.position.y = position.y;
  137. this.position.z = position.z;
  138. if (!pathArr.isSpread) {
  139. if (isFirst) this.opacity = this.opacityFactor * 0.5;
  140. if (isFirst) this.scale = ((0.3 * Math.random() + 0.7) / 2) * this.scaleFactor;
  141. } else {
  142. if (pathArr.spreadDirection == 1) {
  143. // 计算粒子透明度
  144. this.opacity = 1 - currentPathAlpha;
  145. this.opacity *= this.opacityFactor * 0.5;
  146. if (this.opacity < 0) this.opacity = 0;
  147. // 计算放大量
  148. this.scale = this.scaleFactor * (currentPathAlpha + 1 / 2);
  149. // if (this.scale > 1 + this.scaleFactor) this.scale = 1.5 * this.scaleFactor;
  150. } else {
  151. // 计算粒子透明度
  152. this.opacity = currentPathAlpha * currentPathAlpha * currentPathAlpha;
  153. // this.opacity = this.currentPathAlpha;
  154. this.opacity *= this.opacityFactor * 0.5;
  155. if (this.opacity < 0) this.opacity = 0;
  156. // 计算放大量
  157. this.scale = this.scaleFactor * (1 - currentPathAlpha + 1 / 2);
  158. }
  159. }
  160. if (this.currentPathAlpha >= 1) {
  161. ++this.pathIndex;
  162. this.currentPathAlpha = 0;
  163. }
  164. }
  165. }
  166. controlUpdate() {
  167. // gsap.to(this.speed, {
  168. // x: 250,
  169. // duration: 1,
  170. // ease: 'none',
  171. // repeat: -1,
  172. // });
  173. }
  174. }