@newkrok/three-particles 1.0.3 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +28 -12
  2. package/dist/bundle-report.json +1 -0
  3. package/dist/index.d.ts +7 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +6 -0
  6. package/dist/js/effects/three-particles/index.d.ts +7 -0
  7. package/dist/js/effects/three-particles/index.d.ts.map +1 -0
  8. package/dist/js/effects/three-particles/index.js +6 -0
  9. package/dist/js/effects/three-particles/shaders/particle-system-fragment-shader.glsl.d.ts +3 -0
  10. package/dist/js/effects/three-particles/shaders/particle-system-fragment-shader.glsl.d.ts.map +1 -0
  11. package/{src → dist}/js/effects/three-particles/shaders/particle-system-fragment-shader.glsl.js +66 -67
  12. package/dist/js/effects/three-particles/shaders/particle-system-vertex-shader.glsl.d.ts +3 -0
  13. package/dist/js/effects/three-particles/shaders/particle-system-vertex-shader.glsl.d.ts.map +1 -0
  14. package/{src → dist}/js/effects/three-particles/shaders/particle-system-vertex-shader.glsl.js +32 -33
  15. package/dist/js/effects/three-particles/three-particles-bezier.d.ts +5 -0
  16. package/dist/js/effects/three-particles/three-particles-bezier.d.ts.map +1 -0
  17. package/dist/js/effects/three-particles/three-particles-bezier.js +62 -0
  18. package/dist/js/effects/three-particles/three-particles-curves.d.ts +37 -0
  19. package/dist/js/effects/three-particles/three-particles-curves.d.ts.map +1 -0
  20. package/dist/js/effects/three-particles/three-particles-curves.js +37 -0
  21. package/dist/js/effects/three-particles/three-particles-enums.d.ts +25 -0
  22. package/dist/js/effects/three-particles/three-particles-enums.d.ts.map +1 -0
  23. package/dist/js/effects/three-particles/three-particles-enums.js +1 -0
  24. package/dist/js/effects/three-particles/three-particles-modifiers.d.ts +11 -0
  25. package/dist/js/effects/three-particles/three-particles-modifiers.d.ts.map +1 -0
  26. package/dist/js/effects/three-particles/three-particles-modifiers.js +93 -0
  27. package/dist/js/effects/three-particles/three-particles-utils.d.ts +36 -0
  28. package/dist/js/effects/three-particles/three-particles-utils.d.ts.map +1 -0
  29. package/dist/js/effects/three-particles/three-particles-utils.js +179 -0
  30. package/dist/js/effects/three-particles/three-particles.d.ts +13 -0
  31. package/dist/js/effects/three-particles/three-particles.d.ts.map +1 -0
  32. package/dist/js/effects/three-particles/three-particles.js +643 -0
  33. package/dist/js/effects/three-particles/types.d.ts +1037 -0
  34. package/dist/js/effects/three-particles/types.d.ts.map +1 -0
  35. package/dist/js/effects/three-particles/types.js +1 -0
  36. package/dist/three-particles.min.js +1 -0
  37. package/package.json +87 -37
  38. package/src/js/effects/three-particles/three-particles-bezier.js +0 -36
  39. package/src/js/effects/three-particles/three-particles-curves.js +0 -75
  40. package/src/js/effects/three-particles/three-particles-enums.js +0 -23
  41. package/src/js/effects/three-particles/three-particles-modifiers.js +0 -133
  42. package/src/js/effects/three-particles/three-particles-utils.js +0 -212
  43. package/src/js/effects/three-particles.d.ts +0 -138
  44. package/src/js/effects/three-particles.js +0 -931
@@ -1,931 +0,0 @@
1
- import * as THREE from "three";
2
-
3
- import {
4
- EmitFrom,
5
- Shape,
6
- SimulationSpace,
7
- TimeMode,
8
- } from "./three-particles/three-particles-enums.js";
9
- import {
10
- calculateRandomPositionAndVelocityOnBox,
11
- calculateRandomPositionAndVelocityOnCircle,
12
- calculateRandomPositionAndVelocityOnCone,
13
- calculateRandomPositionAndVelocityOnRectangle,
14
- calculateRandomPositionAndVelocityOnSphere,
15
- } from "./three-particles/three-particles-utils.js";
16
-
17
- import { CurveFunction } from "./three-particles/three-particles-curves.js";
18
- import { FBM } from "three-noise/build/three-noise.module.js";
19
- import { Gyroscope } from "three/examples/jsm/misc/Gyroscope.js";
20
- import { ObjectUtils } from "@newkrok/three-utils";
21
- import ParticleSystemFragmentShader from "./three-particles/shaders/particle-system-fragment-shader.glsl.js";
22
- import ParticleSystemVertexShader from "./three-particles/shaders/particle-system-vertex-shader.glsl.js";
23
- import { applyModifiers } from "./three-particles/three-particles-modifiers.js";
24
- import { createBezierCurveFunction } from "./three-particles/three-particles-bezier";
25
-
26
- let createdParticleSystems = [];
27
-
28
- export const blendingMap = {
29
- "THREE.NoBlending": THREE.NoBlending,
30
- "THREE.NormalBlending": THREE.NormalBlending,
31
- "THREE.AdditiveBlending": THREE.AdditiveBlending,
32
- "THREE.SubtractiveBlending": THREE.SubtractiveBlending,
33
- "THREE.MultiplyBlending": THREE.MultiplyBlending,
34
- };
35
-
36
- export const getDefaultParticleSystemConfig = () =>
37
- JSON.parse(JSON.stringify(DEFAULT_PARTICLE_SYSTEM_CONFIG));
38
-
39
- const DEFAULT_PARTICLE_SYSTEM_CONFIG = {
40
- transform: {
41
- position: { x: 0, y: 0, z: 0 },
42
- rotation: { x: 0, y: 0, z: 0 },
43
- scale: { x: 1, y: 1, z: 1 },
44
- },
45
- duration: 5.0,
46
- looping: true,
47
- startDelay: { min: 0.0, max: 0.0 },
48
- startLifetime: { min: 2.0, max: 2.0 },
49
- startSpeed: { min: 1.0, max: 1.0 },
50
- startSize: { min: 1.0, max: 1.0 },
51
- startRotation: { min: 0.0, max: 0.0 },
52
- startColor: {
53
- min: { r: 1.0, g: 1.0, b: 1.0 },
54
- max: { r: 1.0, g: 1.0, b: 1.0 },
55
- },
56
- startOpacity: { min: 1.0, max: 1.0 },
57
- gravity: 0.0,
58
- simulationSpace: SimulationSpace.LOCAL,
59
- maxParticles: 100.0,
60
- emission: {
61
- rateOverTime: 10.0,
62
- rateOverDistance: 0.0,
63
- },
64
- shape: {
65
- shape: Shape.SPHERE,
66
- sphere: {
67
- radius: 1.0,
68
- radiusThickness: 1.0,
69
- arc: 360.0,
70
- },
71
- cone: {
72
- angle: 25.0,
73
- radius: 1.0,
74
- radiusThickness: 1.0,
75
- arc: 360.0,
76
- },
77
- circle: {
78
- radius: 1.0,
79
- radiusThickness: 1.0,
80
- arc: 360.0,
81
- },
82
- rectangle: {
83
- rotation: { x: 0.0, y: 0.0 }, // TODO: add z rotation
84
- scale: { x: 1.0, y: 1.0 },
85
- },
86
- box: {
87
- scale: { x: 1.0, y: 1.0, z: 1.0 },
88
- emitFrom: EmitFrom.VOLUME,
89
- },
90
- },
91
- map: null,
92
- renderer: {
93
- blending: THREE.NormalBlending,
94
- discardBackgroundColor: false,
95
- backgroundColorTolerance: 1.0,
96
- backgroundColor: { r: 1.0, g: 1.0, b: 1.0 },
97
- transparent: true,
98
- depthTest: true,
99
- depthWrite: false,
100
- },
101
- velocityOverLifetime: {
102
- isActive: false,
103
- linear: {
104
- x: { min: 0, max: 0 },
105
- y: { min: 0, max: 0 },
106
- z: { min: 0, max: 0 },
107
- },
108
- orbital: {
109
- x: { min: 0, max: 0 },
110
- y: { min: 0, max: 0 },
111
- z: { min: 0, max: 0 },
112
- },
113
- },
114
- sizeOverLifetime: {
115
- isActive: false,
116
- curveFunction: CurveFunction.BEZIER,
117
- bezierPoints: [
118
- { x: 0, y: 0, percentage: 0 },
119
- { x: 1, y: 1, percentage: 1 },
120
- ],
121
- },
122
- /* colorOverLifetime: {
123
- isActive: false,
124
- curveFunction: CurveFunction.LINEAR,
125
- }, */
126
- opacityOverLifetime: {
127
- isActive: false,
128
- curveFunction: CurveFunction.BEZIER,
129
- bezierPoints: [
130
- { x: 0, y: 0, percentage: 0 },
131
- { x: 1, y: 1, percentage: 1 },
132
- ],
133
- },
134
- rotationOverLifetime: {
135
- isActive: false,
136
- min: 0.0,
137
- max: 0.0,
138
- },
139
- noise: {
140
- isActive: false,
141
- useRandomOffset: false,
142
- strength: 1.0,
143
- frequency: 0.5,
144
- octaves: 1,
145
- positionAmount: 1.0,
146
- rotationAmount: 0.0,
147
- sizeAmount: 0.0,
148
- },
149
- textureSheetAnimation: {
150
- tiles: new THREE.Vector2(1.0, 1.0),
151
- timeMode: TimeMode.LIFETIME,
152
- fps: 10.0,
153
- startFrame: { min: 0.0, max: 0.0 },
154
- },
155
- };
156
-
157
- const createFloat32Attributes = ({
158
- geometry,
159
- propertyName,
160
- maxParticles,
161
- factory,
162
- }) => {
163
- geometry.setAttribute(
164
- propertyName,
165
- new THREE.BufferAttribute(
166
- new Float32Array(
167
- Array.from(
168
- { length: maxParticles },
169
- typeof factory === "function" ? factory : () => factory
170
- )
171
- ),
172
- 1
173
- )
174
- );
175
- };
176
-
177
- const calculatePositionAndVelocity = (
178
- { shape, sphere, cone, circle, rectangle, box },
179
- startSpeed,
180
- position,
181
- quaternion,
182
- velocity,
183
- velocityOverLifetime
184
- ) => {
185
- switch (shape) {
186
- case Shape.SPHERE:
187
- calculateRandomPositionAndVelocityOnSphere(
188
- position,
189
- quaternion,
190
- velocity,
191
- startSpeed,
192
- sphere
193
- );
194
- break;
195
-
196
- case Shape.CONE:
197
- calculateRandomPositionAndVelocityOnCone(
198
- position,
199
- quaternion,
200
- velocity,
201
- startSpeed,
202
- cone
203
- );
204
- break;
205
-
206
- case Shape.CIRCLE:
207
- calculateRandomPositionAndVelocityOnCircle(
208
- position,
209
- quaternion,
210
- velocity,
211
- startSpeed,
212
- circle
213
- );
214
- break;
215
-
216
- case Shape.RECTANGLE:
217
- calculateRandomPositionAndVelocityOnRectangle(
218
- position,
219
- quaternion,
220
- velocity,
221
- startSpeed,
222
- rectangle
223
- );
224
- break;
225
-
226
- case Shape.BOX:
227
- calculateRandomPositionAndVelocityOnBox(
228
- position,
229
- quaternion,
230
- velocity,
231
- startSpeed,
232
- box
233
- );
234
- break;
235
- }
236
-
237
- if (velocityOverLifetime.isActive) {
238
- if (
239
- velocityOverLifetime.linear.x.min !== 0 ||
240
- velocityOverLifetime.linear.x.max !== 0
241
- ) {
242
- velocity.x += THREE.MathUtils.randFloat(
243
- velocityOverLifetime.linear.x.min,
244
- velocityOverLifetime.linear.x.max
245
- );
246
- }
247
- if (
248
- velocityOverLifetime.linear.y.min !== 0 ||
249
- velocityOverLifetime.linear.y.max !== 0
250
- ) {
251
- velocity.y += THREE.MathUtils.randFloat(
252
- velocityOverLifetime.linear.y.min,
253
- velocityOverLifetime.linear.y.max
254
- );
255
- }
256
- if (
257
- velocityOverLifetime.linear.z.min !== 0 ||
258
- velocityOverLifetime.linear.z.max !== 0
259
- ) {
260
- velocity.z += THREE.MathUtils.randFloat(
261
- velocityOverLifetime.linear.z.min,
262
- velocityOverLifetime.linear.z.max
263
- );
264
- }
265
- }
266
- };
267
-
268
- /**
269
- * @deprecated Since version 1.0.1. Will be deleted in version 1.1.0. Use particleSystem.dispose instead.
270
- */
271
- export const destroyParticleSystem = (particleSystem) => {
272
- createdParticleSystems = createdParticleSystems.filter(
273
- ({ particleSystem: savedParticleSystem, wrapper }) => {
274
- if (
275
- savedParticleSystem !== particleSystem &&
276
- wrapper !== particleSystem &&
277
- particleSystem.instance !== particleSystem
278
- ) {
279
- return true;
280
- }
281
-
282
- savedParticleSystem.geometry.dispose();
283
- savedParticleSystem.material.dispose();
284
- if (savedParticleSystem.parent)
285
- savedParticleSystem.parent.remove(savedParticleSystem);
286
- return false;
287
- }
288
- );
289
- };
290
-
291
- export const createParticleSystem = (
292
- config = DEFAULT_PARTICLE_SYSTEM_CONFIG,
293
- externalNow
294
- ) => {
295
- const now = externalNow || Date.now();
296
- const generalData = {
297
- distanceFromLastEmitByDistance: 0,
298
- lastWorldPosition: new THREE.Vector3(-99999),
299
- currentWorldPosition: new THREE.Vector3(-99999),
300
- worldPositionChange: new THREE.Vector3(),
301
- worldQuaternion: new THREE.Quaternion(),
302
- wrapperQuaternion: new THREE.Quaternion(),
303
- lastWorldQuaternion: new THREE.Quaternion(-99999),
304
- worldEuler: new THREE.Euler(),
305
- gravityVelocity: new THREE.Vector3(0, 0, 0),
306
- startValues: {},
307
- hasOrbitalVelocity: false,
308
- orbitalVelocityData: [],
309
- lifetimeValues: {},
310
- creationTimes: [],
311
- noise: null,
312
- isEnabled: true,
313
- };
314
-
315
- const normalizedConfig = ObjectUtils.patchObject(
316
- DEFAULT_PARTICLE_SYSTEM_CONFIG,
317
- config
318
- );
319
-
320
- const bezierCompatibleProperties = [
321
- "sizeOverLifetime",
322
- "opacityOverLifetime",
323
- ];
324
- bezierCompatibleProperties.forEach((key) => {
325
- if (
326
- normalizedConfig[key].isActive &&
327
- normalizedConfig[key].curveFunction === CurveFunction.BEZIER &&
328
- normalizedConfig[key].bezierPoints
329
- )
330
- normalizedConfig[key].curveFunction = createBezierCurveFunction(
331
- normalizedConfig[key].bezierPoints
332
- );
333
- });
334
-
335
- const {
336
- transform,
337
- duration,
338
- looping,
339
- startDelay,
340
- startLifetime,
341
- startSpeed,
342
- startSize,
343
- startRotation,
344
- startColor,
345
- startOpacity,
346
- gravity,
347
- simulationSpace,
348
- maxParticles,
349
- emission,
350
- shape,
351
- map,
352
- renderer,
353
- noise,
354
- velocityOverLifetime,
355
- onUpdate,
356
- onComplete,
357
- textureSheetAnimation,
358
- } = normalizedConfig;
359
-
360
- if (typeof renderer.blending === "string")
361
- renderer.blending = blendingMap[renderer.blending];
362
-
363
- const startPositions = Array.from(
364
- { length: maxParticles },
365
- () => new THREE.Vector3()
366
- );
367
- const velocities = Array.from(
368
- { length: maxParticles },
369
- () => new THREE.Vector3()
370
- );
371
-
372
- generalData.creationTimes = Array.from({ length: maxParticles }, () => 0);
373
- generalData.hasOrbitalVelocity =
374
- normalizedConfig.velocityOverLifetime.isActive &&
375
- (normalizedConfig.velocityOverLifetime.orbital.x.min !== 0 ||
376
- normalizedConfig.velocityOverLifetime.orbital.x.max !== 0 ||
377
- normalizedConfig.velocityOverLifetime.orbital.y.min !== 0 ||
378
- normalizedConfig.velocityOverLifetime.orbital.y.max !== 0 ||
379
- normalizedConfig.velocityOverLifetime.orbital.z.min !== 0 ||
380
- normalizedConfig.velocityOverLifetime.orbital.z.max !== 0);
381
-
382
- if (generalData.hasOrbitalVelocity) {
383
- generalData.orbitalVelocityData = Array.from(
384
- { length: maxParticles },
385
- () => ({
386
- speed: new THREE.Vector3(),
387
- positionOffset: new THREE.Vector3(),
388
- })
389
- );
390
- }
391
-
392
- const startValueKeys = ["startSize", "startOpacity"];
393
- startValueKeys.forEach((key) => {
394
- generalData.startValues[key] = Array.from({ length: maxParticles }, () =>
395
- THREE.MathUtils.randFloat(
396
- normalizedConfig[key].min,
397
- normalizedConfig[key].max
398
- )
399
- );
400
- });
401
-
402
- const lifetimeValueKeys = ["rotationOverLifetime"];
403
- lifetimeValueKeys.forEach((key) => {
404
- if (normalizedConfig[key].isActive)
405
- generalData.lifetimeValues[key] = Array.from(
406
- { length: maxParticles },
407
- () =>
408
- THREE.MathUtils.randFloat(
409
- normalizedConfig[key].min,
410
- normalizedConfig[key].max
411
- )
412
- );
413
- });
414
-
415
- generalData.noise = {
416
- isActive: noise.isActive,
417
- strength: noise.strength,
418
- positionAmount: noise.positionAmount,
419
- rotationAmount: noise.rotationAmount,
420
- sizeAmount: noise.sizeAmount,
421
- sampler: noise.isActive
422
- ? new FBM({
423
- seed: Math.random(),
424
- scale: noise.frequency,
425
- octaves: noise.octaves,
426
- })
427
- : null,
428
- offsets: noise.useRandomOffset
429
- ? Array.from({ length: maxParticles }, () => Math.random() * 100)
430
- : null,
431
- };
432
-
433
- const material = new THREE.ShaderMaterial({
434
- uniforms: {
435
- elapsed: {
436
- value: 0.0,
437
- },
438
- map: {
439
- value: map,
440
- },
441
- tiles: {
442
- value: textureSheetAnimation.tiles,
443
- },
444
- fps: {
445
- value: textureSheetAnimation.fps,
446
- },
447
- useFPSForFrameIndex: {
448
- value: textureSheetAnimation.timeMode === TimeMode.FPS,
449
- },
450
- backgroundColor: {
451
- value: renderer.backgroundColor,
452
- },
453
- discardBackgroundColor: {
454
- value: renderer.discardBackgroundColor,
455
- },
456
- backgroundColorTolerance: {
457
- value: renderer.backgroundColorTolerance,
458
- },
459
- },
460
- vertexShader: ParticleSystemVertexShader,
461
- fragmentShader: ParticleSystemFragmentShader,
462
- transparent: renderer.transparent,
463
- blending: renderer.blending,
464
- depthTest: renderer.depthTest,
465
- depthWrite: renderer.depthWrite,
466
- });
467
-
468
- const geometry = new THREE.BufferGeometry();
469
-
470
- for (let i = 0; i < maxParticles; i++)
471
- calculatePositionAndVelocity(
472
- shape,
473
- startSpeed,
474
- startPositions[i],
475
- generalData.wrapperQuaternion,
476
- velocities[i],
477
- velocityOverLifetime
478
- );
479
-
480
- geometry.setFromPoints(
481
- Array.from({ length: maxParticles }, (_, index) => ({
482
- ...startPositions[index],
483
- }))
484
- );
485
-
486
- const createFloat32AttributesRequest = (propertyName, factory) => {
487
- createFloat32Attributes({
488
- geometry,
489
- propertyName,
490
- maxParticles,
491
- factory,
492
- });
493
- };
494
-
495
- createFloat32AttributesRequest("isActive", false);
496
- createFloat32AttributesRequest("lifetime", 0);
497
- createFloat32AttributesRequest("startLifetime", () =>
498
- THREE.MathUtils.randFloat(startLifetime.min, startLifetime.max)
499
- );
500
- createFloat32AttributesRequest("startFrame", () =>
501
- THREE.MathUtils.randInt(
502
- textureSheetAnimation.startFrame.min,
503
- textureSheetAnimation.startFrame.max
504
- )
505
- );
506
-
507
- createFloat32AttributesRequest("opacity", 0);
508
-
509
- createFloat32AttributesRequest("rotation", () =>
510
- THREE.MathUtils.degToRad(
511
- THREE.MathUtils.randFloat(startRotation.min, startRotation.max)
512
- )
513
- );
514
-
515
- createFloat32AttributesRequest(
516
- "size",
517
- (_, index) => generalData.startValues.startSize[index]
518
- );
519
-
520
- createFloat32AttributesRequest("rotation", 0);
521
-
522
- const colorRandomRatio = Math.random();
523
- createFloat32AttributesRequest(
524
- "colorR",
525
- () =>
526
- startColor.min.r +
527
- colorRandomRatio * (startColor.max.r - startColor.min.r)
528
- );
529
- createFloat32AttributesRequest(
530
- "colorG",
531
- () =>
532
- startColor.min.g +
533
- colorRandomRatio * (startColor.max.g - startColor.min.g)
534
- );
535
- createFloat32AttributesRequest(
536
- "colorB",
537
- () =>
538
- startColor.min.b +
539
- colorRandomRatio * (startColor.max.b - startColor.min.b)
540
- );
541
- createFloat32AttributesRequest("colorA", 0);
542
-
543
- const deactivateParticle = (particleIndex) => {
544
- geometry.attributes.isActive.array[particleIndex] = false;
545
- geometry.attributes.colorA.array[particleIndex] = 0;
546
- geometry.attributes.colorA.needsUpdate = true;
547
- };
548
-
549
- const activateParticle = ({ particleIndex, activationTime, position }) => {
550
- geometry.attributes.isActive.array[particleIndex] = true;
551
- generalData.creationTimes[particleIndex] = activationTime;
552
-
553
- if (generalData.noise.offsets)
554
- generalData.noise.offsets[particleIndex] = Math.random() * 100;
555
-
556
- const colorRandomRatio = Math.random();
557
-
558
- geometry.attributes.colorR.array[particleIndex] =
559
- startColor.min.r +
560
- colorRandomRatio * (startColor.max.r - startColor.min.r);
561
- geometry.attributes.colorR.needsUpdate = true;
562
-
563
- geometry.attributes.colorG.array[particleIndex] =
564
- startColor.min.g +
565
- colorRandomRatio * (startColor.max.g - startColor.min.g);
566
- geometry.attributes.colorG.needsUpdate = true;
567
-
568
- geometry.attributes.colorB.array[particleIndex] =
569
- startColor.min.b +
570
- colorRandomRatio * (startColor.max.b - startColor.min.b);
571
- geometry.attributes.colorB.needsUpdate = true;
572
-
573
- geometry.attributes.startFrame.array[particleIndex] =
574
- THREE.MathUtils.randInt(
575
- textureSheetAnimation.startFrame.min,
576
- textureSheetAnimation.startFrame.max
577
- );
578
- geometry.attributes.startFrame.needsUpdate = true;
579
-
580
- geometry.attributes.startLifetime.array[particleIndex] =
581
- THREE.MathUtils.randFloat(startLifetime.min, startLifetime.max) * 1000;
582
- geometry.attributes.startLifetime.needsUpdate = true;
583
-
584
- generalData.startValues.startSize[particleIndex] =
585
- THREE.MathUtils.randFloat(startSize.min, startSize.max);
586
- generalData.startValues.startOpacity[particleIndex] =
587
- THREE.MathUtils.randFloat(startOpacity.min, startOpacity.max);
588
-
589
- geometry.attributes.rotation.array[particleIndex] =
590
- THREE.MathUtils.degToRad(
591
- THREE.MathUtils.randFloat(startRotation.min, startRotation.max)
592
- );
593
-
594
- if (normalizedConfig.rotationOverLifetime.isActive)
595
- generalData.lifetimeValues.rotationOverLifetime[particleIndex] =
596
- THREE.MathUtils.randFloat(
597
- normalizedConfig.rotationOverLifetime.min,
598
- normalizedConfig.rotationOverLifetime.max
599
- );
600
-
601
- geometry.attributes.rotation.needsUpdate = true;
602
- geometry.attributes.colorB.needsUpdate = true;
603
-
604
- calculatePositionAndVelocity(
605
- shape,
606
- startSpeed,
607
- startPositions[particleIndex],
608
- generalData.wrapperQuaternion,
609
- velocities[particleIndex],
610
- velocityOverLifetime
611
- );
612
- const positionIndex = Math.floor(particleIndex * 3);
613
- geometry.attributes.position.array[positionIndex] =
614
- (position ? position.x : 0) + startPositions[particleIndex].x;
615
- geometry.attributes.position.array[positionIndex + 1] =
616
- (position ? position.y : 0) + startPositions[particleIndex].y;
617
- geometry.attributes.position.array[positionIndex + 2] =
618
- (position ? position.z : 0) + startPositions[particleIndex].z;
619
- geometry.attributes.position.needsUpdate = true;
620
-
621
- if (generalData.hasOrbitalVelocity) {
622
- generalData.orbitalVelocityData[particleIndex].speed.set(
623
- THREE.MathUtils.randFloat(
624
- normalizedConfig.velocityOverLifetime.orbital.x.min,
625
- normalizedConfig.velocityOverLifetime.orbital.x.max
626
- ) *
627
- (Math.PI / 180),
628
- THREE.MathUtils.randFloat(
629
- normalizedConfig.velocityOverLifetime.orbital.y.min,
630
- normalizedConfig.velocityOverLifetime.orbital.y.max
631
- ) *
632
- (Math.PI / 180),
633
- THREE.MathUtils.randFloat(
634
- normalizedConfig.velocityOverLifetime.orbital.z.min,
635
- normalizedConfig.velocityOverLifetime.orbital.z.max
636
- ) *
637
- (Math.PI / 180)
638
- );
639
- generalData.orbitalVelocityData[particleIndex].positionOffset.set(
640
- startPositions[particleIndex].x,
641
- startPositions[particleIndex].y,
642
- startPositions[particleIndex].z
643
- );
644
- }
645
-
646
- geometry.attributes.lifetime.array[particleIndex] = 0;
647
- geometry.attributes.lifetime.needsUpdate = true;
648
-
649
- applyModifiers({
650
- delta: 0,
651
- elapsed: 0,
652
- noise: generalData.noise,
653
- startValues: generalData.startValues,
654
- lifetimeValues: generalData.lifetimeValues,
655
- hasOrbitalVelocity: generalData.hasOrbitalVelocity,
656
- orbitalVelocityData: generalData.orbitalVelocityData,
657
- normalizedConfig,
658
- attributes: particleSystem.geometry.attributes,
659
- particleLifetime: 0,
660
- particleLifetimePercentage: 0,
661
- particleIndex,
662
- forceUpdate: true,
663
- });
664
- };
665
-
666
- let particleSystem = new THREE.Points(geometry, material);
667
- particleSystem.sortParticles = true;
668
-
669
- particleSystem.position.copy(transform.position);
670
- particleSystem.rotation.x = THREE.MathUtils.degToRad(transform.rotation.x);
671
- particleSystem.rotation.y = THREE.MathUtils.degToRad(transform.rotation.y);
672
- particleSystem.rotation.z = THREE.MathUtils.degToRad(transform.rotation.z);
673
- particleSystem.scale.copy(transform.scale);
674
-
675
- const calculatedCreationTime =
676
- now + THREE.MathUtils.randFloat(startDelay.min, startDelay.max) * 1000;
677
-
678
- let wrapper;
679
- if (normalizedConfig.simulationSpace === SimulationSpace.WORLD) {
680
- wrapper = new Gyroscope();
681
- wrapper.add(particleSystem);
682
- }
683
-
684
- createdParticleSystems.push({
685
- particleSystem,
686
- wrapper,
687
- generalData,
688
- onUpdate,
689
- onComplete,
690
- creationTime: calculatedCreationTime,
691
- lastEmissionTime: calculatedCreationTime,
692
- duration,
693
- looping,
694
- simulationSpace,
695
- gravity,
696
- emission,
697
- normalizedConfig,
698
- iterationCount: 0,
699
- velocities,
700
- deactivateParticle,
701
- activateParticle,
702
- });
703
-
704
- const resumeEmitter = () => (generalData.isEnabled = true);
705
- const pauseEmitter = () => (generalData.isEnabled = false);
706
- const dispose = () => destroyParticleSystem(particleSystem);
707
-
708
- return {
709
- instance: wrapper || particleSystem,
710
- resumeEmitter,
711
- pauseEmitter,
712
- dispose,
713
- };
714
- };
715
-
716
- export const updateParticleSystems = ({ now, delta, elapsed }) => {
717
- createdParticleSystems.forEach((props) => {
718
- const {
719
- onUpdate,
720
- generalData,
721
- onComplete,
722
- particleSystem,
723
- wrapper,
724
- creationTime,
725
- lastEmissionTime,
726
- duration,
727
- looping,
728
- emission,
729
- normalizedConfig,
730
- iterationCount,
731
- velocities,
732
- deactivateParticle,
733
- activateParticle,
734
- simulationSpace,
735
- gravity,
736
- } = props;
737
-
738
- const {
739
- lastWorldPosition,
740
- currentWorldPosition,
741
- worldPositionChange,
742
- lastWorldQuaternion,
743
- worldQuaternion,
744
- worldEuler,
745
- gravityVelocity,
746
- isEnabled,
747
- } = generalData;
748
-
749
- if (wrapper) generalData.wrapperQuaternion.copy(wrapper.parent.quaternion);
750
-
751
- const lastWorldPositionSnapshot = { ...lastWorldPosition };
752
-
753
- const lifetime = now - creationTime;
754
- particleSystem.material.uniforms.elapsed.value = elapsed;
755
-
756
- particleSystem.getWorldPosition(currentWorldPosition);
757
- if (lastWorldPosition.x !== -99999) {
758
- worldPositionChange.set(
759
- currentWorldPosition.x - lastWorldPosition.x,
760
- currentWorldPosition.y - lastWorldPosition.y,
761
- currentWorldPosition.z - lastWorldPosition.z
762
- );
763
- }
764
- generalData.distanceFromLastEmitByDistance += worldPositionChange.length();
765
- particleSystem.getWorldPosition(lastWorldPosition);
766
- particleSystem.getWorldQuaternion(worldQuaternion);
767
- if (
768
- lastWorldQuaternion.x === -99999 ||
769
- lastWorldQuaternion.x != worldQuaternion.x ||
770
- lastWorldQuaternion.y != worldQuaternion.y ||
771
- lastWorldQuaternion.z != worldQuaternion.z
772
- ) {
773
- worldEuler.setFromQuaternion(worldQuaternion);
774
- lastWorldQuaternion.copy(worldQuaternion);
775
- gravityVelocity.set(
776
- lastWorldPosition.x,
777
- lastWorldPosition.y + gravity,
778
- lastWorldPosition.z
779
- );
780
- particleSystem.worldToLocal(gravityVelocity);
781
- }
782
-
783
- generalData.creationTimes.forEach((entry, index) => {
784
- if (particleSystem.geometry.attributes.isActive.array[index]) {
785
- const particleLifetime = now - entry;
786
- if (
787
- particleLifetime >
788
- particleSystem.geometry.attributes.startLifetime.array[index]
789
- )
790
- deactivateParticle(index);
791
- else {
792
- const velocity = velocities[index];
793
- velocity.x -= gravityVelocity.x * delta;
794
- velocity.y -= gravityVelocity.y * delta;
795
- velocity.z -= gravityVelocity.z * delta;
796
-
797
- if (
798
- gravity !== 0 ||
799
- velocity.x !== 0 ||
800
- velocity.y !== 0 ||
801
- velocity.z !== 0 ||
802
- worldPositionChange.x !== 0 ||
803
- worldPositionChange.y !== 0 ||
804
- worldPositionChange.z !== 0
805
- ) {
806
- const positionIndex = index * 3;
807
- const positionArr =
808
- particleSystem.geometry.attributes.position.array;
809
-
810
- if (simulationSpace === SimulationSpace.WORLD) {
811
- positionArr[positionIndex] -= worldPositionChange.x;
812
- positionArr[positionIndex + 1] -= worldPositionChange.y;
813
- positionArr[positionIndex + 2] -= worldPositionChange.z;
814
- }
815
-
816
- positionArr[positionIndex] += velocity.x * delta;
817
- positionArr[positionIndex + 1] += velocity.y * delta;
818
- positionArr[positionIndex + 2] += velocity.z * delta;
819
- particleSystem.geometry.attributes.position.needsUpdate = true;
820
- }
821
-
822
- particleSystem.geometry.attributes.lifetime.array[index] =
823
- particleLifetime;
824
- particleSystem.geometry.attributes.lifetime.needsUpdate = true;
825
-
826
- const particleLifetimePercentage =
827
- particleLifetime /
828
- particleSystem.geometry.attributes.startLifetime.array[index];
829
- applyModifiers({
830
- delta,
831
- elapsed,
832
- noise: generalData.noise,
833
- startValues: generalData.startValues,
834
- lifetimeValues: generalData.lifetimeValues,
835
- hasOrbitalVelocity: generalData.hasOrbitalVelocity,
836
- orbitalVelocityData: generalData.orbitalVelocityData,
837
- normalizedConfig,
838
- attributes: particleSystem.geometry.attributes,
839
- particleLifetime,
840
- particleLifetimePercentage,
841
- particleIndex: index,
842
- });
843
- }
844
- }
845
- });
846
-
847
- if (isEnabled && (looping || lifetime < duration * 1000)) {
848
- const emissionDelta = now - lastEmissionTime;
849
- const neededParticlesByTime = Math.floor(
850
- emission.rateOverTime * (emissionDelta / 1000)
851
- );
852
- const neededParticlesByDistance =
853
- emission.rateOverDistance > 0 &&
854
- generalData.distanceFromLastEmitByDistance > 0
855
- ? Math.floor(
856
- generalData.distanceFromLastEmitByDistance /
857
- (1 / emission.rateOverDistance)
858
- )
859
- : 0;
860
- const distanceStep =
861
- neededParticlesByDistance > 0
862
- ? {
863
- x:
864
- (currentWorldPosition.x - lastWorldPositionSnapshot.x) /
865
- neededParticlesByDistance,
866
- y:
867
- (currentWorldPosition.y - lastWorldPositionSnapshot.y) /
868
- neededParticlesByDistance,
869
- z:
870
- (currentWorldPosition.z - lastWorldPositionSnapshot.z) /
871
- neededParticlesByDistance,
872
- }
873
- : null;
874
- const neededParticles = neededParticlesByTime + neededParticlesByDistance;
875
-
876
- if (emission.rateOverDistance > 0 && neededParticlesByDistance >= 1) {
877
- generalData.distanceFromLastEmitByDistance = 0;
878
- }
879
-
880
- if (neededParticles > 0) {
881
- let generatedParticlesByDistanceNeeds = 0;
882
- for (let i = 0; i < neededParticles; i++) {
883
- let particleIndex = -1;
884
- particleSystem.geometry.attributes.isActive.array.find(
885
- (isActive, index) => {
886
- if (!isActive) {
887
- particleIndex = index;
888
- return true;
889
- }
890
-
891
- return false;
892
- }
893
- );
894
-
895
- if (
896
- particleIndex !== -1 &&
897
- particleIndex <
898
- particleSystem.geometry.attributes.isActive.array.length
899
- ) {
900
- let position;
901
- if (generatedParticlesByDistanceNeeds < neededParticlesByDistance) {
902
- position =
903
- generatedParticlesByDistanceNeeds < neededParticlesByDistance
904
- ? {
905
- x: distanceStep.x * generatedParticlesByDistanceNeeds,
906
- y: distanceStep.y * generatedParticlesByDistanceNeeds,
907
- z: distanceStep.z * generatedParticlesByDistanceNeeds,
908
- }
909
- : null;
910
- generatedParticlesByDistanceNeeds++;
911
- }
912
- activateParticle({ particleIndex, activationTime: now, position });
913
- props.lastEmissionTime = now;
914
- }
915
- }
916
- }
917
-
918
- if (onUpdate)
919
- onUpdate({
920
- particleSystem,
921
- delta,
922
- elapsed,
923
- lifetime,
924
- iterationCount: iterationCount + 1,
925
- });
926
- } else if (onComplete)
927
- onComplete({
928
- particleSystem,
929
- });
930
- });
931
- };