FlyLine1.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import * as THREE from 'three';
  2. class Fly {
  3. points;
  4. length;
  5. circle;
  6. opacity;
  7. size;
  8. progress;
  9. frameId;
  10. geometry;
  11. material;
  12. texture;
  13. obj;
  14. color;
  15. constructor(points, length, circle = 2, color = '#ff00ff', opacity = 1, size = 10) {
  16. this.points = points; // 路径
  17. this.length = length; // 长度(粒子数)
  18. this.circle = circle; // 周期
  19. this.color = color; // 颜色
  20. this.opacity = opacity; // 透明度
  21. this.size = size; // 大小
  22. this.progress = 0;
  23. this.frameId = null;
  24. this.geometry = null;
  25. this.material = null;
  26. this.texture = null;
  27. this.obj = null;
  28. this.createFly();
  29. }
  30. createFly() {
  31. // 几何体
  32. this.geometry = new THREE.BufferGeometry();
  33. this.updateFly();
  34. // 纹理和材质
  35. this.texture = new THREE.TextureLoader().load('/model/img/spark.png');
  36. this.material = new THREE.PointsMaterial({
  37. color: this.color,
  38. map: this.texture,
  39. // alphaTest: 0.9,
  40. transparent: true,
  41. depthWrite: false,
  42. // depthTest: false,
  43. opacity: this.opacity,
  44. //blending: THREE.AdditiveBlending,
  45. size: this.size,
  46. sizeAttenuation: true,
  47. side: THREE.DoubleSide,
  48. });
  49. // 修正着色器
  50. this.material.onBeforeCompile = (shader) => {
  51. const vertex = `
  52. attribute float aScale;
  53. void main() {
  54. `;
  55. const vertex1 = `gl_PointSize = size * aScale;`;
  56. shader.vertexShader = shader.vertexShader.replace('void main() {', vertex);
  57. shader.vertexShader = shader.vertexShader.replace('gl_PointSize = size;', vertex1);
  58. };
  59. // 物体
  60. this.obj = new THREE.Points(this.geometry, this.material);
  61. }
  62. // 更新
  63. updateFly() {
  64. // 计算新数据
  65. const posArr = [];
  66. const scaleArr = [];
  67. const posIndex = Math.floor(this.progress * this.points.length);
  68. const flyPointArr = this.points.filter((point, index) => {
  69. if (index >= posIndex && index <= posIndex + this.length) return true;
  70. });
  71. flyPointArr.forEach((point, index) => {
  72. posArr.push(...point);
  73. // scaleArr.push((index + 1) / this.length);
  74. const scale = Math.random() * 1;
  75. scaleArr.push(scale);
  76. });
  77. // 更新几何体
  78. this.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(posArr), 3));
  79. this.geometry.setAttribute('aScale', new THREE.BufferAttribute(new Float32Array(scaleArr), 1));
  80. this.geometry.boundingBox = new THREE.Box3(new THREE.Vector3(10000, -10000, 10000), new THREE.Vector3(-10000, 10000, -10000));
  81. this.geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0), 10000);
  82. }
  83. // 移动
  84. move() {
  85. if (this.frameId) return;
  86. const clock = new THREE.Clock(); // 时钟
  87. const h = () => {
  88. this.frameId = requestAnimationFrame(h);
  89. const dt = clock.getDelta();
  90. this.progress += dt / this.circle; // 更新进度
  91. if (this.progress > 1) this.progress = 1;
  92. this.updateFly();
  93. if (this.progress == 1) this.progress = 0;
  94. };
  95. this.frameId = requestAnimationFrame(h);
  96. }
  97. // 停止
  98. stop() {
  99. if (this.frameId) {
  100. cancelAnimationFrame(this.frameId);
  101. this.frameId = null;
  102. }
  103. }
  104. clear() {
  105. this.points = [];
  106. }
  107. }
  108. export default Fly;