@newkrok/three-particles 2.11.2 → 2.13.0
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.
- package/README.md +2 -0
- package/dist/index.d.ts +165 -2
- package/dist/index.js +724 -23
- package/dist/index.js.map +1 -1
- package/dist/three-particles.min.js +1 -1
- package/dist/three-particles.min.js.map +1 -1
- package/llms-full.txt +95 -1
- package/llms.txt +47 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -173,6 +173,8 @@ var ForceFieldType = /* @__PURE__ */ ((ForceFieldType2) => {
|
|
|
173
173
|
var RendererType = /* @__PURE__ */ ((RendererType2) => {
|
|
174
174
|
RendererType2["POINTS"] = "POINTS";
|
|
175
175
|
RendererType2["INSTANCED"] = "INSTANCED";
|
|
176
|
+
RendererType2["TRAIL"] = "TRAIL";
|
|
177
|
+
RendererType2["MESH"] = "MESH";
|
|
176
178
|
return RendererType2;
|
|
177
179
|
})(RendererType || {});
|
|
178
180
|
var ForceFieldFalloff = /* @__PURE__ */ ((ForceFieldFalloff2) => {
|
|
@@ -309,6 +311,24 @@ var calculateRandomPositionAndVelocityOnRectangle = (position, quaternion, veloc
|
|
|
309
311
|
velocity.set(0, 0, speed);
|
|
310
312
|
velocity.applyQuaternion(quaternion);
|
|
311
313
|
};
|
|
314
|
+
var createDefaultMeshTexture = () => {
|
|
315
|
+
try {
|
|
316
|
+
const canvas = document.createElement("canvas");
|
|
317
|
+
canvas.width = 1;
|
|
318
|
+
canvas.height = 1;
|
|
319
|
+
const context = canvas.getContext("2d");
|
|
320
|
+
if (context) {
|
|
321
|
+
context.fillStyle = "white";
|
|
322
|
+
context.fillRect(0, 0, 1, 1);
|
|
323
|
+
const texture = new THREE4.CanvasTexture(canvas);
|
|
324
|
+
texture.needsUpdate = true;
|
|
325
|
+
return texture;
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
} catch {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
};
|
|
312
332
|
var createDefaultParticleTexture = () => {
|
|
313
333
|
try {
|
|
314
334
|
const canvas = document.createElement("canvas");
|
|
@@ -493,6 +513,16 @@ var applyModifiers = ({
|
|
|
493
513
|
positionArr[positionIndex + 2] += noiseOnPosition * noisePower * positionAmount;
|
|
494
514
|
attributes.position.needsUpdate = true;
|
|
495
515
|
}
|
|
516
|
+
if (attributes.quat) {
|
|
517
|
+
const rotZ = attributes.rotation.array[particleIndex];
|
|
518
|
+
const halfZ = rotZ * 0.5;
|
|
519
|
+
const qi = particleIndex * 4;
|
|
520
|
+
attributes.quat.array[qi] = 0;
|
|
521
|
+
attributes.quat.array[qi + 1] = 0;
|
|
522
|
+
attributes.quat.array[qi + 2] = Math.sin(halfZ);
|
|
523
|
+
attributes.quat.array[qi + 3] = Math.cos(halfZ);
|
|
524
|
+
attributes.quat.needsUpdate = true;
|
|
525
|
+
}
|
|
496
526
|
};
|
|
497
527
|
|
|
498
528
|
// src/js/effects/three-particles/shaders/instanced-particle-fragment-shader.glsl.ts
|
|
@@ -629,6 +659,129 @@ var InstancedParticleVertexShader = `
|
|
|
629
659
|
`;
|
|
630
660
|
var instanced_particle_vertex_shader_glsl_default = InstancedParticleVertexShader;
|
|
631
661
|
|
|
662
|
+
// src/js/effects/three-particles/shaders/mesh-particle-fragment-shader.glsl.ts
|
|
663
|
+
var MeshParticleFragmentShader = `
|
|
664
|
+
uniform sampler2D map;
|
|
665
|
+
uniform float elapsed;
|
|
666
|
+
uniform float fps;
|
|
667
|
+
uniform bool useFPSForFrameIndex;
|
|
668
|
+
uniform vec2 tiles;
|
|
669
|
+
uniform bool discardBackgroundColor;
|
|
670
|
+
uniform vec3 backgroundColor;
|
|
671
|
+
uniform float backgroundColorTolerance;
|
|
672
|
+
|
|
673
|
+
varying vec4 vColor;
|
|
674
|
+
varying float vLifetime;
|
|
675
|
+
varying float vStartLifetime;
|
|
676
|
+
varying float vStartFrame;
|
|
677
|
+
varying float vRotation;
|
|
678
|
+
varying vec3 vNormal;
|
|
679
|
+
varying vec2 vUv;
|
|
680
|
+
|
|
681
|
+
#include <common>
|
|
682
|
+
#include <logdepthbuf_pars_fragment>
|
|
683
|
+
|
|
684
|
+
void main()
|
|
685
|
+
{
|
|
686
|
+
gl_FragColor = vColor;
|
|
687
|
+
|
|
688
|
+
// Use mesh UVs directly for texture sampling
|
|
689
|
+
vec2 uvPoint = vUv;
|
|
690
|
+
|
|
691
|
+
// Apply texture sheet animation if tiles > 1x1
|
|
692
|
+
if (tiles.x > 1.0 || tiles.y > 1.0) {
|
|
693
|
+
float frameIndex = round(vStartFrame) + (
|
|
694
|
+
useFPSForFrameIndex == true
|
|
695
|
+
? fps == 0.0
|
|
696
|
+
? 0.0
|
|
697
|
+
: max((vLifetime / 1000.0) * fps, 0.0)
|
|
698
|
+
: max(min(floor(min(vLifetime / vStartLifetime, 1.0) * (tiles.x * tiles.y)), tiles.x * tiles.y - 1.0), 0.0)
|
|
699
|
+
);
|
|
700
|
+
|
|
701
|
+
float spriteXIndex = floor(mod(frameIndex, tiles.x));
|
|
702
|
+
float spriteYIndex = floor(mod(frameIndex / tiles.x, tiles.y));
|
|
703
|
+
|
|
704
|
+
uvPoint = vec2(
|
|
705
|
+
vUv.x / tiles.x + spriteXIndex / tiles.x,
|
|
706
|
+
vUv.y / tiles.y + spriteYIndex / tiles.y
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
vec4 texColor = texture2D(map, uvPoint);
|
|
711
|
+
gl_FragColor = gl_FragColor * texColor;
|
|
712
|
+
|
|
713
|
+
if (discardBackgroundColor && abs(length(texColor.rgb - backgroundColor.rgb)) < backgroundColorTolerance) discard;
|
|
714
|
+
|
|
715
|
+
// Simple directional lighting from camera direction
|
|
716
|
+
float lightIntensity = 0.5 + 0.5 * max(dot(vNormal, vec3(0.0, 0.0, 1.0)), 0.0);
|
|
717
|
+
gl_FragColor.rgb *= lightIntensity;
|
|
718
|
+
|
|
719
|
+
#include <logdepthbuf_fragment>
|
|
720
|
+
}
|
|
721
|
+
`;
|
|
722
|
+
var mesh_particle_fragment_shader_glsl_default = MeshParticleFragmentShader;
|
|
723
|
+
|
|
724
|
+
// src/js/effects/three-particles/shaders/mesh-particle-vertex-shader.glsl.ts
|
|
725
|
+
var MeshParticleVertexShader = `
|
|
726
|
+
attribute float instanceSize;
|
|
727
|
+
attribute float instanceColorR;
|
|
728
|
+
attribute float instanceColorG;
|
|
729
|
+
attribute float instanceColorB;
|
|
730
|
+
attribute float instanceColorA;
|
|
731
|
+
attribute float instanceLifetime;
|
|
732
|
+
attribute float instanceStartLifetime;
|
|
733
|
+
attribute float instanceRotation;
|
|
734
|
+
attribute float instanceStartFrame;
|
|
735
|
+
attribute vec3 instanceOffset;
|
|
736
|
+
attribute vec4 instanceQuat;
|
|
737
|
+
|
|
738
|
+
varying vec4 vColor;
|
|
739
|
+
varying float vLifetime;
|
|
740
|
+
varying float vStartLifetime;
|
|
741
|
+
varying float vStartFrame;
|
|
742
|
+
varying float vRotation;
|
|
743
|
+
varying vec3 vNormal;
|
|
744
|
+
varying vec2 vUv;
|
|
745
|
+
|
|
746
|
+
#include <common>
|
|
747
|
+
#include <logdepthbuf_pars_vertex>
|
|
748
|
+
|
|
749
|
+
vec3 applyQuaternion(vec3 v, vec4 q) {
|
|
750
|
+
vec3 t = 2.0 * cross(q.xyz, v);
|
|
751
|
+
return v + q.w * t + cross(q.xyz, t);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
void main()
|
|
755
|
+
{
|
|
756
|
+
vColor = vec4(instanceColorR, instanceColorG, instanceColorB, instanceColorA);
|
|
757
|
+
vLifetime = instanceLifetime;
|
|
758
|
+
vStartLifetime = instanceStartLifetime;
|
|
759
|
+
vStartFrame = instanceStartFrame;
|
|
760
|
+
vRotation = instanceRotation;
|
|
761
|
+
|
|
762
|
+
// Apply quaternion rotation to the mesh vertex position
|
|
763
|
+
vec3 rotatedPosition = applyQuaternion(position, instanceQuat);
|
|
764
|
+
|
|
765
|
+
// Scale mesh by particle size
|
|
766
|
+
vec3 scaledPosition = rotatedPosition * instanceSize;
|
|
767
|
+
|
|
768
|
+
// Apply instance offset (particle world position)
|
|
769
|
+
vec3 worldPos = scaledPosition + instanceOffset;
|
|
770
|
+
|
|
771
|
+
vec4 mvPosition = modelViewMatrix * vec4(worldPos, 1.0);
|
|
772
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
773
|
+
|
|
774
|
+
// Transform normal by quaternion for lighting
|
|
775
|
+
vNormal = normalize((modelViewMatrix * vec4(applyQuaternion(normal, instanceQuat), 0.0)).xyz);
|
|
776
|
+
|
|
777
|
+
// Pass through UVs from the mesh geometry
|
|
778
|
+
vUv = uv;
|
|
779
|
+
|
|
780
|
+
#include <logdepthbuf_vertex>
|
|
781
|
+
}
|
|
782
|
+
`;
|
|
783
|
+
var mesh_particle_vertex_shader_glsl_default = MeshParticleVertexShader;
|
|
784
|
+
|
|
632
785
|
// src/js/effects/three-particles/shaders/particle-system-fragment-shader.glsl.ts
|
|
633
786
|
var ParticleSystemFragmentShader = `
|
|
634
787
|
uniform sampler2D map;
|
|
@@ -740,6 +893,115 @@ var ParticleSystemVertexShader = `
|
|
|
740
893
|
}
|
|
741
894
|
`;
|
|
742
895
|
var particle_system_vertex_shader_glsl_default = ParticleSystemVertexShader;
|
|
896
|
+
|
|
897
|
+
// src/js/effects/three-particles/shaders/trail-fragment-shader.glsl.ts
|
|
898
|
+
var TrailFragmentShader = `
|
|
899
|
+
uniform sampler2D map;
|
|
900
|
+
uniform bool useMap;
|
|
901
|
+
uniform bool discardBackgroundColor;
|
|
902
|
+
uniform vec3 backgroundColor;
|
|
903
|
+
uniform float backgroundColorTolerance;
|
|
904
|
+
|
|
905
|
+
varying float vAlpha;
|
|
906
|
+
varying vec4 vColor;
|
|
907
|
+
varying vec2 vUv;
|
|
908
|
+
|
|
909
|
+
#include <common>
|
|
910
|
+
#include <logdepthbuf_pars_fragment>
|
|
911
|
+
|
|
912
|
+
void main()
|
|
913
|
+
{
|
|
914
|
+
// Soft edge: always fade near ribbon edges
|
|
915
|
+
float edgeDist = 1.0 - abs(vUv.x * 2.0 - 1.0);
|
|
916
|
+
float softEdge = smoothstep(0.0, 0.4, edgeDist);
|
|
917
|
+
|
|
918
|
+
gl_FragColor = vColor;
|
|
919
|
+
|
|
920
|
+
if (useMap) {
|
|
921
|
+
// Use texture luminance as brightness modulation on top of soft edge
|
|
922
|
+
vec4 texColor = texture2D(map, vUv);
|
|
923
|
+
float texBrightness = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));
|
|
924
|
+
gl_FragColor.rgb *= (0.5 + texBrightness * 0.5);
|
|
925
|
+
gl_FragColor.a *= texColor.a;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
gl_FragColor.a *= vAlpha * softEdge;
|
|
929
|
+
|
|
930
|
+
if (gl_FragColor.a < 0.001) discard;
|
|
931
|
+
|
|
932
|
+
if (discardBackgroundColor && abs(length(gl_FragColor.rgb - backgroundColor.rgb)) < backgroundColorTolerance) discard;
|
|
933
|
+
|
|
934
|
+
#include <logdepthbuf_fragment>
|
|
935
|
+
}
|
|
936
|
+
`;
|
|
937
|
+
var trail_fragment_shader_glsl_default = TrailFragmentShader;
|
|
938
|
+
|
|
939
|
+
// src/js/effects/three-particles/shaders/trail-vertex-shader.glsl.ts
|
|
940
|
+
var TrailVertexShader = `
|
|
941
|
+
attribute float trailAlpha;
|
|
942
|
+
attribute vec4 trailColor;
|
|
943
|
+
attribute float trailOffset;
|
|
944
|
+
attribute float trailHalfWidth;
|
|
945
|
+
attribute vec3 trailNext;
|
|
946
|
+
attribute vec2 trailUV;
|
|
947
|
+
|
|
948
|
+
varying float vAlpha;
|
|
949
|
+
varying vec4 vColor;
|
|
950
|
+
varying vec2 vUv;
|
|
951
|
+
|
|
952
|
+
#include <common>
|
|
953
|
+
#include <logdepthbuf_pars_vertex>
|
|
954
|
+
|
|
955
|
+
void main()
|
|
956
|
+
{
|
|
957
|
+
vAlpha = trailAlpha;
|
|
958
|
+
vColor = trailColor;
|
|
959
|
+
vUv = trailUV;
|
|
960
|
+
|
|
961
|
+
// Compute tangent from current position to next sample
|
|
962
|
+
vec3 tangent = trailNext - position;
|
|
963
|
+
float tangentLen = length(tangent);
|
|
964
|
+
if (tangentLen < 0.0001) {
|
|
965
|
+
tangent = vec3(0.0, 1.0, 0.0);
|
|
966
|
+
} else {
|
|
967
|
+
tangent = tangent / tangentLen;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// Billboard: perpendicular = cross(tangent, viewDirection)
|
|
971
|
+
vec3 worldPos = (modelMatrix * vec4(position, 1.0)).xyz;
|
|
972
|
+
vec3 viewDir = normalize(cameraPosition - worldPos);
|
|
973
|
+
vec3 perp = cross(tangent, viewDir);
|
|
974
|
+
float perpLen = length(perp);
|
|
975
|
+
|
|
976
|
+
// When tangent is nearly parallel to view direction, the cross product
|
|
977
|
+
// collapses and the ribbon becomes edge-on (invisible). Use a secondary
|
|
978
|
+
// perpendicular from cross(tangent, up) and blend it in to guarantee
|
|
979
|
+
// a minimum visible width.
|
|
980
|
+
vec3 upPerp = cross(tangent, vec3(0.0, 1.0, 0.0));
|
|
981
|
+
float upPerpLen = length(upPerp);
|
|
982
|
+
if (upPerpLen < 0.0001) {
|
|
983
|
+
upPerp = cross(tangent, vec3(1.0, 0.0, 0.0));
|
|
984
|
+
upPerpLen = length(upPerp);
|
|
985
|
+
}
|
|
986
|
+
upPerp = upPerp / max(upPerpLen, 0.0001);
|
|
987
|
+
|
|
988
|
+
if (perpLen < 0.0001) {
|
|
989
|
+
perp = upPerp;
|
|
990
|
+
} else {
|
|
991
|
+
perp = perp / perpLen;
|
|
992
|
+
// Blend in the secondary perp when billboard perp gets weak
|
|
993
|
+
float blendFactor = smoothstep(0.0, 0.5, perpLen);
|
|
994
|
+
perp = normalize(mix(upPerp, perp, blendFactor));
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
vec3 offsetPos = position + perp * trailOffset * trailHalfWidth;
|
|
998
|
+
vec4 mvPosition = modelViewMatrix * vec4(offsetPos, 1.0);
|
|
999
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
1000
|
+
|
|
1001
|
+
#include <logdepthbuf_vertex>
|
|
1002
|
+
}
|
|
1003
|
+
`;
|
|
1004
|
+
var trail_vertex_shader_glsl_default = TrailVertexShader;
|
|
743
1005
|
var _forceDirection = new THREE4.Vector3();
|
|
744
1006
|
var applyPointForce = (field, strength, velocity, positionArr, positionIndex, delta) => {
|
|
745
1007
|
_forceDirection.set(
|
|
@@ -811,10 +1073,21 @@ var applyForceFields = ({
|
|
|
811
1073
|
};
|
|
812
1074
|
|
|
813
1075
|
// src/js/effects/three-particles/three-particles.ts
|
|
1076
|
+
var normalizeTrailCurve = (curve, defaultCurve) => {
|
|
1077
|
+
if (!curve) return defaultCurve;
|
|
1078
|
+
const raw = curve;
|
|
1079
|
+
if (!raw.type && Array.isArray(raw.bezierPoints)) {
|
|
1080
|
+
return { type: "BEZIER" /* BEZIER */, ...raw };
|
|
1081
|
+
}
|
|
1082
|
+
return curve;
|
|
1083
|
+
};
|
|
814
1084
|
var _particleSystemId = 0;
|
|
815
1085
|
var createdParticleSystems = [];
|
|
816
1086
|
var _subEmitterPosition = new THREE4.Vector3();
|
|
817
1087
|
var _lastWorldPositionSnapshot = new THREE4.Vector3();
|
|
1088
|
+
new THREE4.Vector3();
|
|
1089
|
+
new THREE4.Vector3();
|
|
1090
|
+
new THREE4.Vector3();
|
|
818
1091
|
var _distanceStep = { x: 0, y: 0, z: 0 };
|
|
819
1092
|
var _tempPosition = { x: 0, y: 0, z: 0 };
|
|
820
1093
|
var _modifierParams = {
|
|
@@ -1059,12 +1332,20 @@ var destroyParticleSystem = (particleSystem) => {
|
|
|
1059
1332
|
({
|
|
1060
1333
|
particleSystem: savedParticleSystem,
|
|
1061
1334
|
wrapper,
|
|
1335
|
+
trailMesh,
|
|
1062
1336
|
generalData: { particleSystemId }
|
|
1063
1337
|
}) => {
|
|
1064
1338
|
if (savedParticleSystem !== particleSystem && wrapper !== particleSystem) {
|
|
1065
1339
|
return true;
|
|
1066
1340
|
}
|
|
1067
1341
|
removeBezierCurveFunction(particleSystemId);
|
|
1342
|
+
if (trailMesh) {
|
|
1343
|
+
trailMesh.geometry.dispose();
|
|
1344
|
+
if (Array.isArray(trailMesh.material))
|
|
1345
|
+
trailMesh.material.forEach((m) => m.dispose());
|
|
1346
|
+
else trailMesh.material.dispose();
|
|
1347
|
+
if (trailMesh.parent) trailMesh.parent.remove(trailMesh);
|
|
1348
|
+
}
|
|
1068
1349
|
savedParticleSystem.geometry.dispose();
|
|
1069
1350
|
if (Array.isArray(savedParticleSystem.material))
|
|
1070
1351
|
savedParticleSystem.material.forEach((material) => material.dispose());
|
|
@@ -1110,7 +1391,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1110
1391
|
config,
|
|
1111
1392
|
{ applyToFirstObject: false, skippedProperties: [] }
|
|
1112
1393
|
);
|
|
1113
|
-
let particleMap = normalizedConfig.map || createDefaultParticleTexture();
|
|
1394
|
+
let particleMap = normalizedConfig.map || (normalizedConfig.renderer.rendererType === "MESH" /* MESH */ ? createDefaultMeshTexture() : createDefaultParticleTexture());
|
|
1114
1395
|
const {
|
|
1115
1396
|
transform,
|
|
1116
1397
|
duration,
|
|
@@ -1294,9 +1575,42 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1294
1575
|
probabilityPassed: false
|
|
1295
1576
|
}));
|
|
1296
1577
|
}
|
|
1297
|
-
const
|
|
1298
|
-
const
|
|
1299
|
-
const
|
|
1578
|
+
const useTrail = renderer.rendererType === "TRAIL" /* TRAIL */;
|
|
1579
|
+
const useMesh = renderer.rendererType === "MESH" /* MESH */;
|
|
1580
|
+
const useInstancing = !useTrail && !useMesh && renderer.rendererType === "INSTANCED" /* INSTANCED */;
|
|
1581
|
+
const useInstancedAttributes = useInstancing || useMesh;
|
|
1582
|
+
const defaultTrailCurve = {
|
|
1583
|
+
type: "BEZIER" /* BEZIER */,
|
|
1584
|
+
scale: 1,
|
|
1585
|
+
bezierPoints: [
|
|
1586
|
+
{ x: 0, y: 1, percentage: 0 },
|
|
1587
|
+
{ x: 1, y: 0, percentage: 1 }
|
|
1588
|
+
]
|
|
1589
|
+
};
|
|
1590
|
+
const trailConfig = useTrail ? {
|
|
1591
|
+
length: renderer.trail?.length ?? 20,
|
|
1592
|
+
width: renderer.trail?.width ?? 1,
|
|
1593
|
+
widthOverTrail: normalizeTrailCurve(
|
|
1594
|
+
renderer.trail?.widthOverTrail,
|
|
1595
|
+
defaultTrailCurve
|
|
1596
|
+
),
|
|
1597
|
+
opacityOverTrail: normalizeTrailCurve(
|
|
1598
|
+
renderer.trail?.opacityOverTrail,
|
|
1599
|
+
defaultTrailCurve
|
|
1600
|
+
),
|
|
1601
|
+
colorOverTrail: renderer.trail?.colorOverTrail
|
|
1602
|
+
} : void 0;
|
|
1603
|
+
if (useTrail && trailConfig) {
|
|
1604
|
+
const trailLength = trailConfig.length;
|
|
1605
|
+
generalData.trailLength = trailLength;
|
|
1606
|
+
generalData.positionHistory = new Float32Array(
|
|
1607
|
+
maxParticles * trailLength * 3
|
|
1608
|
+
);
|
|
1609
|
+
generalData.positionHistoryIndex = new Uint16Array(maxParticles);
|
|
1610
|
+
generalData.positionHistoryCount = new Uint16Array(maxParticles);
|
|
1611
|
+
}
|
|
1612
|
+
const attr = (name) => useInstancedAttributes ? `instance${name.charAt(0).toUpperCase()}${name.slice(1)}` : name;
|
|
1613
|
+
const posAttr = useInstancedAttributes ? "instanceOffset" : "position";
|
|
1300
1614
|
const sharedUniforms = {
|
|
1301
1615
|
elapsed: { value: 0 },
|
|
1302
1616
|
map: { value: particleMap },
|
|
@@ -1310,17 +1624,46 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1310
1624
|
backgroundColorTolerance: { value: renderer.backgroundColorTolerance },
|
|
1311
1625
|
...useInstancing ? { viewportHeight: { value: 1 } } : {}
|
|
1312
1626
|
};
|
|
1627
|
+
const getVertexShader = () => {
|
|
1628
|
+
if (useMesh) return mesh_particle_vertex_shader_glsl_default;
|
|
1629
|
+
if (useInstancing) return instanced_particle_vertex_shader_glsl_default;
|
|
1630
|
+
return particle_system_vertex_shader_glsl_default;
|
|
1631
|
+
};
|
|
1632
|
+
const getFragmentShader = () => {
|
|
1633
|
+
if (useMesh) return mesh_particle_fragment_shader_glsl_default;
|
|
1634
|
+
if (useInstancing) return instanced_particle_fragment_shader_glsl_default;
|
|
1635
|
+
return particle_system_fragment_shader_glsl_default;
|
|
1636
|
+
};
|
|
1313
1637
|
const material = new THREE4.ShaderMaterial({
|
|
1314
1638
|
uniforms: sharedUniforms,
|
|
1315
|
-
vertexShader:
|
|
1316
|
-
fragmentShader:
|
|
1639
|
+
vertexShader: getVertexShader(),
|
|
1640
|
+
fragmentShader: getFragmentShader(),
|
|
1317
1641
|
transparent: renderer.transparent,
|
|
1318
1642
|
blending: renderer.blending,
|
|
1319
1643
|
depthTest: renderer.depthTest,
|
|
1320
1644
|
depthWrite: renderer.depthWrite
|
|
1321
1645
|
});
|
|
1322
1646
|
let geometry;
|
|
1323
|
-
if (
|
|
1647
|
+
if (useMesh) {
|
|
1648
|
+
const meshConfig = renderer.mesh;
|
|
1649
|
+
if (!meshConfig?.geometry) {
|
|
1650
|
+
throw new Error(
|
|
1651
|
+
"RendererType.MESH requires a mesh configuration with a geometry. Set renderer.mesh.geometry to a THREE.BufferGeometry instance."
|
|
1652
|
+
);
|
|
1653
|
+
}
|
|
1654
|
+
const instancedGeometry = new THREE4.InstancedBufferGeometry();
|
|
1655
|
+
const sourceGeom = meshConfig.geometry;
|
|
1656
|
+
const srcPos = sourceGeom.getAttribute("position");
|
|
1657
|
+
if (srcPos) instancedGeometry.setAttribute("position", srcPos);
|
|
1658
|
+
const srcNormal = sourceGeom.getAttribute("normal");
|
|
1659
|
+
if (srcNormal) instancedGeometry.setAttribute("normal", srcNormal);
|
|
1660
|
+
const srcUv = sourceGeom.getAttribute("uv");
|
|
1661
|
+
if (srcUv) instancedGeometry.setAttribute("uv", srcUv);
|
|
1662
|
+
const srcIndex = sourceGeom.getIndex();
|
|
1663
|
+
if (srcIndex) instancedGeometry.setIndex(srcIndex);
|
|
1664
|
+
instancedGeometry.instanceCount = maxParticles;
|
|
1665
|
+
geometry = instancedGeometry;
|
|
1666
|
+
} else if (useInstancing) {
|
|
1324
1667
|
const instancedGeometry = new THREE4.InstancedBufferGeometry();
|
|
1325
1668
|
const quadPositions = new Float32Array([
|
|
1326
1669
|
-0.5,
|
|
@@ -1361,28 +1704,28 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1361
1704
|
positionArray[i * 3 + 1] = startPositions[i].y;
|
|
1362
1705
|
positionArray[i * 3 + 2] = startPositions[i].z;
|
|
1363
1706
|
}
|
|
1364
|
-
const positionAttribute =
|
|
1707
|
+
const positionAttribute = useInstancedAttributes ? new THREE4.InstancedBufferAttribute(positionArray, 3) : new THREE4.BufferAttribute(positionArray, 3);
|
|
1365
1708
|
geometry.setAttribute(posAttr, positionAttribute);
|
|
1366
1709
|
createFloat32Attributes({
|
|
1367
1710
|
geometry,
|
|
1368
1711
|
propertyName: attr("isActive"),
|
|
1369
1712
|
maxParticles,
|
|
1370
1713
|
factory: 0,
|
|
1371
|
-
instanced:
|
|
1714
|
+
instanced: useInstancedAttributes
|
|
1372
1715
|
});
|
|
1373
1716
|
createFloat32Attributes({
|
|
1374
1717
|
geometry,
|
|
1375
1718
|
propertyName: attr("lifetime"),
|
|
1376
1719
|
maxParticles,
|
|
1377
1720
|
factory: 0,
|
|
1378
|
-
instanced:
|
|
1721
|
+
instanced: useInstancedAttributes
|
|
1379
1722
|
});
|
|
1380
1723
|
createFloat32Attributes({
|
|
1381
1724
|
geometry,
|
|
1382
1725
|
propertyName: attr("startLifetime"),
|
|
1383
1726
|
maxParticles,
|
|
1384
1727
|
factory: () => calculateValue(generalData.particleSystemId, startLifetime, 0) * 1e3,
|
|
1385
|
-
instanced:
|
|
1728
|
+
instanced: useInstancedAttributes
|
|
1386
1729
|
});
|
|
1387
1730
|
createFloat32Attributes({
|
|
1388
1731
|
geometry,
|
|
@@ -1393,21 +1736,21 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1393
1736
|
textureSheetAnimation.startFrame,
|
|
1394
1737
|
0
|
|
1395
1738
|
) : 0,
|
|
1396
|
-
instanced:
|
|
1739
|
+
instanced: useInstancedAttributes
|
|
1397
1740
|
});
|
|
1398
1741
|
createFloat32Attributes({
|
|
1399
1742
|
geometry,
|
|
1400
1743
|
propertyName: attr("size"),
|
|
1401
1744
|
maxParticles,
|
|
1402
1745
|
factory: (_, index) => generalData.startValues.startSize[index],
|
|
1403
|
-
instanced:
|
|
1746
|
+
instanced: useInstancedAttributes
|
|
1404
1747
|
});
|
|
1405
1748
|
createFloat32Attributes({
|
|
1406
1749
|
geometry,
|
|
1407
1750
|
propertyName: attr("rotation"),
|
|
1408
1751
|
maxParticles,
|
|
1409
1752
|
factory: 0,
|
|
1410
|
-
instanced:
|
|
1753
|
+
instanced: useInstancedAttributes
|
|
1411
1754
|
});
|
|
1412
1755
|
const colorRandomRatio = Math.random();
|
|
1413
1756
|
createFloat32Attributes({
|
|
@@ -1415,29 +1758,39 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1415
1758
|
propertyName: attr("colorR"),
|
|
1416
1759
|
maxParticles,
|
|
1417
1760
|
factory: () => startColor.min.r + colorRandomRatio * (startColor.max.r - startColor.min.r),
|
|
1418
|
-
instanced:
|
|
1761
|
+
instanced: useInstancedAttributes
|
|
1419
1762
|
});
|
|
1420
1763
|
createFloat32Attributes({
|
|
1421
1764
|
geometry,
|
|
1422
1765
|
propertyName: attr("colorG"),
|
|
1423
1766
|
maxParticles,
|
|
1424
1767
|
factory: () => startColor.min.g + colorRandomRatio * (startColor.max.g - startColor.min.g),
|
|
1425
|
-
instanced:
|
|
1768
|
+
instanced: useInstancedAttributes
|
|
1426
1769
|
});
|
|
1427
1770
|
createFloat32Attributes({
|
|
1428
1771
|
geometry,
|
|
1429
1772
|
propertyName: attr("colorB"),
|
|
1430
1773
|
maxParticles,
|
|
1431
1774
|
factory: () => startColor.min.b + colorRandomRatio * (startColor.max.b - startColor.min.b),
|
|
1432
|
-
instanced:
|
|
1775
|
+
instanced: useInstancedAttributes
|
|
1433
1776
|
});
|
|
1434
1777
|
createFloat32Attributes({
|
|
1435
1778
|
geometry,
|
|
1436
1779
|
propertyName: attr("colorA"),
|
|
1437
1780
|
maxParticles,
|
|
1438
1781
|
factory: 0,
|
|
1439
|
-
instanced:
|
|
1782
|
+
instanced: useInstancedAttributes
|
|
1440
1783
|
});
|
|
1784
|
+
if (useMesh) {
|
|
1785
|
+
const quatArray = new Float32Array(maxParticles * 4);
|
|
1786
|
+
for (let i = 0; i < maxParticles; i++) {
|
|
1787
|
+
quatArray[i * 4 + 3] = 1;
|
|
1788
|
+
}
|
|
1789
|
+
geometry.setAttribute(
|
|
1790
|
+
attr("quat"),
|
|
1791
|
+
new THREE4.InstancedBufferAttribute(quatArray, 4)
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1441
1794
|
const a = geometry.attributes;
|
|
1442
1795
|
const aIsActive = a[attr("isActive")];
|
|
1443
1796
|
const aColorR = a[attr("colorR")];
|
|
@@ -1450,6 +1803,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1450
1803
|
const aRotation = a[attr("rotation")];
|
|
1451
1804
|
const aLifetime = a[attr("lifetime")];
|
|
1452
1805
|
const aPosition = a[posAttr];
|
|
1806
|
+
const aQuat = useMesh ? a[attr("quat")] : void 0;
|
|
1453
1807
|
const deactivateParticle = (particleIndex) => {
|
|
1454
1808
|
aIsActive.array[particleIndex] = 0;
|
|
1455
1809
|
aColorA.array[particleIndex] = 0;
|
|
@@ -1463,6 +1817,10 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1463
1817
|
}) => {
|
|
1464
1818
|
aIsActive.array[particleIndex] = 1;
|
|
1465
1819
|
generalData.creationTimes[particleIndex] = activationTime;
|
|
1820
|
+
if (generalData.positionHistoryCount) {
|
|
1821
|
+
generalData.positionHistoryCount[particleIndex] = 0;
|
|
1822
|
+
generalData.positionHistoryIndex[particleIndex] = 0;
|
|
1823
|
+
}
|
|
1466
1824
|
if (generalData.noise.offsets)
|
|
1467
1825
|
generalData.noise.offsets[particleIndex] = Math.random() * 100;
|
|
1468
1826
|
const colorRandomRatio2 = Math.random();
|
|
@@ -1507,6 +1865,16 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1507
1865
|
generalData.normalizedLifetimePercentage
|
|
1508
1866
|
);
|
|
1509
1867
|
aRotation.needsUpdate = true;
|
|
1868
|
+
if (aQuat) {
|
|
1869
|
+
const rotZ = aRotation.array[particleIndex];
|
|
1870
|
+
const halfZ = rotZ * 0.5;
|
|
1871
|
+
const qi = particleIndex * 4;
|
|
1872
|
+
aQuat.array[qi] = 0;
|
|
1873
|
+
aQuat.array[qi + 1] = 0;
|
|
1874
|
+
aQuat.array[qi + 2] = Math.sin(halfZ);
|
|
1875
|
+
aQuat.array[qi + 3] = Math.cos(halfZ);
|
|
1876
|
+
aQuat.needsUpdate = true;
|
|
1877
|
+
}
|
|
1510
1878
|
if (normalizedConfig.rotationOverLifetime.isActive)
|
|
1511
1879
|
generalData.lifetimeValues.rotationOverLifetime[particleIndex] = THREE4.MathUtils.randFloat(
|
|
1512
1880
|
normalizedConfig.rotationOverLifetime.min,
|
|
@@ -1632,7 +2000,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1632
2000
|
},
|
|
1633
2001
|
renderer: {
|
|
1634
2002
|
...subConfig.config.renderer ?? {},
|
|
1635
|
-
rendererType: renderer.rendererType
|
|
2003
|
+
...subConfig.config.renderer?.rendererType ? {} : renderer.rendererType === "MESH" /* MESH */ || renderer.rendererType === "TRAIL" /* TRAIL */ ? {} : { rendererType: renderer.rendererType }
|
|
1636
2004
|
},
|
|
1637
2005
|
...inheritVelocity > 0 ? {
|
|
1638
2006
|
startSpeed: (typeof subConfig.config.startSpeed === "number" ? subConfig.config.startSpeed : typeof subConfig.config.startSpeed === "object" && subConfig.config.startSpeed !== null && "min" in subConfig.config.startSpeed ? subConfig.config.startSpeed.min ?? 0 : 0) + velocity.length() * inheritVelocity
|
|
@@ -1645,13 +2013,131 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1645
2013
|
instances.push(subSystem);
|
|
1646
2014
|
}
|
|
1647
2015
|
};
|
|
1648
|
-
let
|
|
2016
|
+
let trailMesh;
|
|
2017
|
+
let trailGeometry;
|
|
2018
|
+
let trailPositionAttr;
|
|
2019
|
+
let trailAlphaAttr;
|
|
2020
|
+
let trailColorAttr;
|
|
2021
|
+
let trailIndexAttr;
|
|
2022
|
+
let trailWidthCurveFn;
|
|
2023
|
+
let trailOpacityCurveFn;
|
|
2024
|
+
let trailColorOverTrailFns;
|
|
2025
|
+
if (useTrail && trailConfig) {
|
|
2026
|
+
const trailLength = trailConfig.length;
|
|
2027
|
+
const verticesPerParticle = trailLength * 2;
|
|
2028
|
+
const totalVertices = maxParticles * verticesPerParticle;
|
|
2029
|
+
const indicesPerParticle = (trailLength - 1) * 6;
|
|
2030
|
+
const totalIndices = maxParticles * indicesPerParticle;
|
|
2031
|
+
trailGeometry = new THREE4.BufferGeometry();
|
|
2032
|
+
const trailPositions = new Float32Array(totalVertices * 3);
|
|
2033
|
+
const trailNextPositions = new Float32Array(totalVertices * 3);
|
|
2034
|
+
const trailAlphas = new Float32Array(totalVertices);
|
|
2035
|
+
const trailColors = new Float32Array(totalVertices * 4);
|
|
2036
|
+
const trailOffsets = new Float32Array(totalVertices);
|
|
2037
|
+
const trailHalfWidths = new Float32Array(totalVertices);
|
|
2038
|
+
const trailUVs = new Float32Array(totalVertices * 2);
|
|
2039
|
+
const trailIndices = new Uint32Array(totalIndices);
|
|
2040
|
+
for (let p = 0; p < maxParticles; p++) {
|
|
2041
|
+
const vertBase = p * verticesPerParticle;
|
|
2042
|
+
const idxBase = p * indicesPerParticle;
|
|
2043
|
+
for (let s = 0; s < trailLength; s++) {
|
|
2044
|
+
trailOffsets[vertBase + s * 2] = -1;
|
|
2045
|
+
trailOffsets[vertBase + s * 2 + 1] = 1;
|
|
2046
|
+
}
|
|
2047
|
+
for (let s = 0; s < trailLength - 1; s++) {
|
|
2048
|
+
const i = idxBase + s * 6;
|
|
2049
|
+
const v = vertBase + s * 2;
|
|
2050
|
+
trailIndices[i] = v;
|
|
2051
|
+
trailIndices[i + 1] = v + 1;
|
|
2052
|
+
trailIndices[i + 2] = v + 2;
|
|
2053
|
+
trailIndices[i + 3] = v + 1;
|
|
2054
|
+
trailIndices[i + 4] = v + 3;
|
|
2055
|
+
trailIndices[i + 5] = v + 2;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
trailPositionAttr = new THREE4.BufferAttribute(trailPositions, 3);
|
|
2059
|
+
trailPositionAttr.setUsage(THREE4.DynamicDrawUsage);
|
|
2060
|
+
const trailNextAttr = new THREE4.BufferAttribute(trailNextPositions, 3);
|
|
2061
|
+
trailNextAttr.setUsage(THREE4.DynamicDrawUsage);
|
|
2062
|
+
trailAlphaAttr = new THREE4.BufferAttribute(trailAlphas, 1);
|
|
2063
|
+
trailAlphaAttr.setUsage(THREE4.DynamicDrawUsage);
|
|
2064
|
+
trailColorAttr = new THREE4.BufferAttribute(trailColors, 4);
|
|
2065
|
+
trailColorAttr.setUsage(THREE4.DynamicDrawUsage);
|
|
2066
|
+
const trailHalfWidthAttr = new THREE4.BufferAttribute(trailHalfWidths, 1);
|
|
2067
|
+
trailHalfWidthAttr.setUsage(THREE4.DynamicDrawUsage);
|
|
2068
|
+
const trailUVAttr = new THREE4.BufferAttribute(trailUVs, 2);
|
|
2069
|
+
trailUVAttr.setUsage(THREE4.DynamicDrawUsage);
|
|
2070
|
+
trailIndexAttr = new THREE4.BufferAttribute(trailIndices, 1);
|
|
2071
|
+
trailGeometry.setAttribute("position", trailPositionAttr);
|
|
2072
|
+
trailGeometry.setAttribute("trailNext", trailNextAttr);
|
|
2073
|
+
trailGeometry.setAttribute("trailAlpha", trailAlphaAttr);
|
|
2074
|
+
trailGeometry.setAttribute("trailColor", trailColorAttr);
|
|
2075
|
+
trailGeometry.setAttribute(
|
|
2076
|
+
"trailOffset",
|
|
2077
|
+
new THREE4.BufferAttribute(trailOffsets, 1)
|
|
2078
|
+
);
|
|
2079
|
+
trailGeometry.setAttribute("trailHalfWidth", trailHalfWidthAttr);
|
|
2080
|
+
trailGeometry.setAttribute("trailUV", trailUVAttr);
|
|
2081
|
+
trailGeometry.setIndex(trailIndexAttr);
|
|
2082
|
+
const trailMaterial = new THREE4.ShaderMaterial({
|
|
2083
|
+
uniforms: {
|
|
2084
|
+
map: { value: particleMap },
|
|
2085
|
+
useMap: { value: !!particleMap },
|
|
2086
|
+
discardBackgroundColor: { value: renderer.discardBackgroundColor },
|
|
2087
|
+
backgroundColor: { value: renderer.backgroundColor },
|
|
2088
|
+
backgroundColorTolerance: { value: renderer.backgroundColorTolerance }
|
|
2089
|
+
},
|
|
2090
|
+
vertexShader: trail_vertex_shader_glsl_default,
|
|
2091
|
+
fragmentShader: trail_fragment_shader_glsl_default,
|
|
2092
|
+
transparent: renderer.transparent,
|
|
2093
|
+
blending: renderer.blending,
|
|
2094
|
+
depthTest: renderer.depthTest,
|
|
2095
|
+
depthWrite: renderer.depthWrite,
|
|
2096
|
+
side: THREE4.DoubleSide
|
|
2097
|
+
});
|
|
2098
|
+
trailMesh = new THREE4.Mesh(trailGeometry, trailMaterial);
|
|
2099
|
+
trailMesh.frustumCulled = false;
|
|
2100
|
+
const trailCameraPos = new THREE4.Vector3();
|
|
2101
|
+
trailMesh.onBeforeRender = (_renderer, _scene, camera) => {
|
|
2102
|
+
camera.getWorldPosition(trailCameraPos);
|
|
2103
|
+
};
|
|
2104
|
+
generalData.trailCameraPosition = trailCameraPos;
|
|
2105
|
+
trailWidthCurveFn = getCurveFunctionFromConfig(
|
|
2106
|
+
generalData.particleSystemId,
|
|
2107
|
+
trailConfig.widthOverTrail
|
|
2108
|
+
);
|
|
2109
|
+
trailOpacityCurveFn = getCurveFunctionFromConfig(
|
|
2110
|
+
generalData.particleSystemId,
|
|
2111
|
+
trailConfig.opacityOverTrail
|
|
2112
|
+
);
|
|
2113
|
+
if (trailConfig.colorOverTrail?.isActive) {
|
|
2114
|
+
trailColorOverTrailFns = {
|
|
2115
|
+
r: getCurveFunctionFromConfig(
|
|
2116
|
+
generalData.particleSystemId,
|
|
2117
|
+
normalizeTrailCurve(trailConfig.colorOverTrail.r, defaultTrailCurve)
|
|
2118
|
+
),
|
|
2119
|
+
g: getCurveFunctionFromConfig(
|
|
2120
|
+
generalData.particleSystemId,
|
|
2121
|
+
normalizeTrailCurve(trailConfig.colorOverTrail.g, defaultTrailCurve)
|
|
2122
|
+
),
|
|
2123
|
+
b: getCurveFunctionFromConfig(
|
|
2124
|
+
generalData.particleSystemId,
|
|
2125
|
+
normalizeTrailCurve(trailConfig.colorOverTrail.b, defaultTrailCurve)
|
|
2126
|
+
)
|
|
2127
|
+
};
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
let particleSystem = useInstancing || useMesh ? new THREE4.Mesh(geometry, material) : new THREE4.Points(geometry, material);
|
|
1649
2131
|
if (useInstancing) {
|
|
1650
2132
|
particleSystem.onBeforeRender = (glRenderer) => {
|
|
1651
2133
|
const size = glRenderer.getSize(new THREE4.Vector2());
|
|
1652
2134
|
sharedUniforms.viewportHeight.value = size.y * glRenderer.getPixelRatio();
|
|
1653
2135
|
};
|
|
1654
2136
|
}
|
|
2137
|
+
if (useTrail && trailMesh) {
|
|
2138
|
+
material.visible = false;
|
|
2139
|
+
particleSystem.add(trailMesh);
|
|
2140
|
+
}
|
|
1655
2141
|
particleSystem.position.copy(transform.position);
|
|
1656
2142
|
particleSystem.rotation.x = THREE4.MathUtils.degToRad(transform.rotation.x);
|
|
1657
2143
|
particleSystem.rotation.y = THREE4.MathUtils.degToRad(transform.rotation.y);
|
|
@@ -1668,7 +2154,8 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1668
2154
|
colorR: aColorR,
|
|
1669
2155
|
colorG: aColorG,
|
|
1670
2156
|
colorB: aColorB,
|
|
1671
|
-
colorA: aColorA
|
|
2157
|
+
colorA: aColorA,
|
|
2158
|
+
...useMesh ? { quat: aQuat } : {}
|
|
1672
2159
|
};
|
|
1673
2160
|
const calculatedCreationTime = now + calculateValue(generalData.particleSystemId, startDelay) * 1e3;
|
|
1674
2161
|
let wrapper;
|
|
@@ -1729,7 +2216,20 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1729
2216
|
deactivateParticle,
|
|
1730
2217
|
activateParticle,
|
|
1731
2218
|
onParticleDeath,
|
|
1732
|
-
onParticleBirth
|
|
2219
|
+
onParticleBirth,
|
|
2220
|
+
...useTrail ? {
|
|
2221
|
+
trailMesh,
|
|
2222
|
+
trailPositionAttr,
|
|
2223
|
+
trailAlphaAttr,
|
|
2224
|
+
trailColorAttr,
|
|
2225
|
+
trailWidthCurveFn,
|
|
2226
|
+
trailOpacityCurveFn,
|
|
2227
|
+
trailColorOverTrailFns,
|
|
2228
|
+
trailConfig: {
|
|
2229
|
+
length: trailConfig.length,
|
|
2230
|
+
width: trailConfig.width
|
|
2231
|
+
}
|
|
2232
|
+
} : {}
|
|
1733
2233
|
};
|
|
1734
2234
|
createdParticleSystems.push(instanceData);
|
|
1735
2235
|
const resumeEmitter = () => generalData.isEnabled = true;
|
|
@@ -1988,6 +2488,207 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
|
|
|
1988
2488
|
onComplete({
|
|
1989
2489
|
particleSystem
|
|
1990
2490
|
});
|
|
2491
|
+
if (props.trailMesh) {
|
|
2492
|
+
updateTrailGeometry(props);
|
|
2493
|
+
}
|
|
2494
|
+
};
|
|
2495
|
+
var updateTrailGeometry = (props) => {
|
|
2496
|
+
const {
|
|
2497
|
+
generalData,
|
|
2498
|
+
trailPositionAttr,
|
|
2499
|
+
trailAlphaAttr,
|
|
2500
|
+
trailColorAttr,
|
|
2501
|
+
trailWidthCurveFn,
|
|
2502
|
+
trailOpacityCurveFn,
|
|
2503
|
+
trailColorOverTrailFns,
|
|
2504
|
+
trailConfig,
|
|
2505
|
+
mappedAttributes: ma
|
|
2506
|
+
} = props;
|
|
2507
|
+
if (!trailPositionAttr || !trailAlphaAttr || !trailColorAttr || !trailWidthCurveFn || !trailOpacityCurveFn || !trailConfig || !generalData.positionHistory || !generalData.positionHistoryIndex || !generalData.positionHistoryCount)
|
|
2508
|
+
return;
|
|
2509
|
+
const trailLength = trailConfig.length;
|
|
2510
|
+
const positionHistory = generalData.positionHistory;
|
|
2511
|
+
const historyIndex = generalData.positionHistoryIndex;
|
|
2512
|
+
const historyCount = generalData.positionHistoryCount;
|
|
2513
|
+
const isActiveArr = ma.isActive.array;
|
|
2514
|
+
const positionArr = ma.position.array;
|
|
2515
|
+
const colorRArr = ma.colorR.array;
|
|
2516
|
+
const colorGArr = ma.colorG.array;
|
|
2517
|
+
const colorBArr = ma.colorB.array;
|
|
2518
|
+
const colorAArr = ma.colorA.array;
|
|
2519
|
+
ma.size.array;
|
|
2520
|
+
const trailPosArr = trailPositionAttr.array;
|
|
2521
|
+
const trailAlphaArr = trailAlphaAttr.array;
|
|
2522
|
+
const trailColorArr = trailColorAttr.array;
|
|
2523
|
+
const trailMesh = props.trailMesh;
|
|
2524
|
+
const trailNextArr = trailMesh.geometry.getAttribute("trailNext").array;
|
|
2525
|
+
const trailUVArr = trailMesh.geometry.getAttribute("trailUV").array;
|
|
2526
|
+
const trailHalfWidthArr = trailMesh.geometry.getAttribute("trailHalfWidth").array;
|
|
2527
|
+
const verticesPerParticle = trailLength * 2;
|
|
2528
|
+
const creationTimesLength = generalData.creationTimes.length;
|
|
2529
|
+
let hasUpdates = false;
|
|
2530
|
+
for (let index = 0; index < creationTimesLength; index++) {
|
|
2531
|
+
const vertBase = index * verticesPerParticle;
|
|
2532
|
+
if (isActiveArr[index]) {
|
|
2533
|
+
hasUpdates = true;
|
|
2534
|
+
const posIdx = index * 3;
|
|
2535
|
+
const px = positionArr[posIdx];
|
|
2536
|
+
const py = positionArr[posIdx + 1];
|
|
2537
|
+
const pz = positionArr[posIdx + 2];
|
|
2538
|
+
const histBase = (index * trailLength + historyIndex[index]) * 3;
|
|
2539
|
+
positionHistory[histBase] = px;
|
|
2540
|
+
positionHistory[histBase + 1] = py;
|
|
2541
|
+
positionHistory[histBase + 2] = pz;
|
|
2542
|
+
historyIndex[index] = (historyIndex[index] + 1) % trailLength;
|
|
2543
|
+
if (historyCount[index] < trailLength) historyCount[index]++;
|
|
2544
|
+
const count = historyCount[index];
|
|
2545
|
+
const ribbonWidth = trailConfig.width;
|
|
2546
|
+
const cr = colorRArr[index];
|
|
2547
|
+
const cg = colorGArr[index];
|
|
2548
|
+
const cb = colorBArr[index];
|
|
2549
|
+
const ca = colorAArr[index];
|
|
2550
|
+
const ringOff = index * trailLength * 3;
|
|
2551
|
+
for (let s = 0; s < trailLength; s++) {
|
|
2552
|
+
const vIdx = (vertBase + s * 2) * 3;
|
|
2553
|
+
const cIdx = (vertBase + s * 2) * 4;
|
|
2554
|
+
const aIdx = vertBase + s * 2;
|
|
2555
|
+
if (s >= count) {
|
|
2556
|
+
trailPosArr[vIdx] = px;
|
|
2557
|
+
trailPosArr[vIdx + 1] = py;
|
|
2558
|
+
trailPosArr[vIdx + 2] = pz;
|
|
2559
|
+
trailPosArr[vIdx + 3] = px;
|
|
2560
|
+
trailPosArr[vIdx + 4] = py;
|
|
2561
|
+
trailPosArr[vIdx + 5] = pz;
|
|
2562
|
+
trailNextArr[vIdx] = px;
|
|
2563
|
+
trailNextArr[vIdx + 1] = py;
|
|
2564
|
+
trailNextArr[vIdx + 2] = pz;
|
|
2565
|
+
trailNextArr[vIdx + 3] = px;
|
|
2566
|
+
trailNextArr[vIdx + 4] = py;
|
|
2567
|
+
trailNextArr[vIdx + 5] = pz;
|
|
2568
|
+
trailHalfWidthArr[aIdx] = 0;
|
|
2569
|
+
trailHalfWidthArr[aIdx + 1] = 0;
|
|
2570
|
+
const uvIdx2 = (vertBase + s * 2) * 2;
|
|
2571
|
+
trailUVArr[uvIdx2] = 0;
|
|
2572
|
+
trailUVArr[uvIdx2 + 1] = 0;
|
|
2573
|
+
trailUVArr[uvIdx2 + 2] = 0;
|
|
2574
|
+
trailUVArr[uvIdx2 + 3] = 0;
|
|
2575
|
+
trailAlphaArr[aIdx] = 0;
|
|
2576
|
+
trailAlphaArr[aIdx + 1] = 0;
|
|
2577
|
+
trailColorArr[cIdx] = 0;
|
|
2578
|
+
trailColorArr[cIdx + 1] = 0;
|
|
2579
|
+
trailColorArr[cIdx + 2] = 0;
|
|
2580
|
+
trailColorArr[cIdx + 3] = 0;
|
|
2581
|
+
trailColorArr[cIdx + 4] = 0;
|
|
2582
|
+
trailColorArr[cIdx + 5] = 0;
|
|
2583
|
+
trailColorArr[cIdx + 6] = 0;
|
|
2584
|
+
trailColorArr[cIdx + 7] = 0;
|
|
2585
|
+
continue;
|
|
2586
|
+
}
|
|
2587
|
+
const histIdx = (historyIndex[index] - 1 - s + trailLength * 2) % trailLength * 3 + ringOff;
|
|
2588
|
+
const hx = positionHistory[histIdx];
|
|
2589
|
+
const hy = positionHistory[histIdx + 1];
|
|
2590
|
+
const hz = positionHistory[histIdx + 2];
|
|
2591
|
+
let nx, ny, nz;
|
|
2592
|
+
if (s < count - 1) {
|
|
2593
|
+
const ni = (historyIndex[index] - 2 - s + trailLength * 2) % trailLength * 3 + ringOff;
|
|
2594
|
+
nx = positionHistory[ni];
|
|
2595
|
+
ny = positionHistory[ni + 1];
|
|
2596
|
+
nz = positionHistory[ni + 2];
|
|
2597
|
+
} else {
|
|
2598
|
+
nx = hx;
|
|
2599
|
+
ny = hy + 1e-3;
|
|
2600
|
+
nz = hz;
|
|
2601
|
+
}
|
|
2602
|
+
const t = count > 1 ? s / (count - 1) : 0;
|
|
2603
|
+
const widthScale = trailWidthCurveFn(t);
|
|
2604
|
+
const opacityScale = trailOpacityCurveFn(t);
|
|
2605
|
+
const halfWidth = ribbonWidth * widthScale * 0.5;
|
|
2606
|
+
trailPosArr[vIdx] = hx;
|
|
2607
|
+
trailPosArr[vIdx + 1] = hy;
|
|
2608
|
+
trailPosArr[vIdx + 2] = hz;
|
|
2609
|
+
trailPosArr[vIdx + 3] = hx;
|
|
2610
|
+
trailPosArr[vIdx + 4] = hy;
|
|
2611
|
+
trailPosArr[vIdx + 5] = hz;
|
|
2612
|
+
trailNextArr[vIdx] = nx;
|
|
2613
|
+
trailNextArr[vIdx + 1] = ny;
|
|
2614
|
+
trailNextArr[vIdx + 2] = nz;
|
|
2615
|
+
trailNextArr[vIdx + 3] = nx;
|
|
2616
|
+
trailNextArr[vIdx + 4] = ny;
|
|
2617
|
+
trailNextArr[vIdx + 5] = nz;
|
|
2618
|
+
trailHalfWidthArr[aIdx] = halfWidth;
|
|
2619
|
+
trailHalfWidthArr[aIdx + 1] = halfWidth;
|
|
2620
|
+
const uvIdx = (vertBase + s * 2) * 2;
|
|
2621
|
+
trailUVArr[uvIdx] = 0;
|
|
2622
|
+
trailUVArr[uvIdx + 1] = t;
|
|
2623
|
+
trailUVArr[uvIdx + 2] = 1;
|
|
2624
|
+
trailUVArr[uvIdx + 3] = t;
|
|
2625
|
+
const alpha = ca * opacityScale;
|
|
2626
|
+
trailAlphaArr[aIdx] = alpha;
|
|
2627
|
+
trailAlphaArr[aIdx + 1] = alpha;
|
|
2628
|
+
const fr = trailColorOverTrailFns ? cr * trailColorOverTrailFns.r(t) : cr;
|
|
2629
|
+
const fg = trailColorOverTrailFns ? cg * trailColorOverTrailFns.g(t) : cg;
|
|
2630
|
+
const fb = trailColorOverTrailFns ? cb * trailColorOverTrailFns.b(t) : cb;
|
|
2631
|
+
trailColorArr[cIdx] = fr;
|
|
2632
|
+
trailColorArr[cIdx + 1] = fg;
|
|
2633
|
+
trailColorArr[cIdx + 2] = fb;
|
|
2634
|
+
trailColorArr[cIdx + 3] = ca;
|
|
2635
|
+
trailColorArr[cIdx + 4] = fr;
|
|
2636
|
+
trailColorArr[cIdx + 5] = fg;
|
|
2637
|
+
trailColorArr[cIdx + 6] = fb;
|
|
2638
|
+
trailColorArr[cIdx + 7] = ca;
|
|
2639
|
+
}
|
|
2640
|
+
} else if (historyCount[index] > 0) {
|
|
2641
|
+
hasUpdates = true;
|
|
2642
|
+
historyCount[index] = 0;
|
|
2643
|
+
historyIndex[index] = 0;
|
|
2644
|
+
for (let s = 0; s < trailLength; s++) {
|
|
2645
|
+
const vIdx = (vertBase + s * 2) * 3;
|
|
2646
|
+
const cIdx = (vertBase + s * 2) * 4;
|
|
2647
|
+
const aIdx = vertBase + s * 2;
|
|
2648
|
+
trailPosArr[vIdx] = 0;
|
|
2649
|
+
trailPosArr[vIdx + 1] = 0;
|
|
2650
|
+
trailPosArr[vIdx + 2] = 0;
|
|
2651
|
+
trailPosArr[vIdx + 3] = 0;
|
|
2652
|
+
trailPosArr[vIdx + 4] = 0;
|
|
2653
|
+
trailPosArr[vIdx + 5] = 0;
|
|
2654
|
+
trailNextArr[vIdx] = 0;
|
|
2655
|
+
trailNextArr[vIdx + 1] = 0;
|
|
2656
|
+
trailNextArr[vIdx + 2] = 0;
|
|
2657
|
+
trailNextArr[vIdx + 3] = 0;
|
|
2658
|
+
trailNextArr[vIdx + 4] = 0;
|
|
2659
|
+
trailNextArr[vIdx + 5] = 0;
|
|
2660
|
+
trailHalfWidthArr[aIdx] = 0;
|
|
2661
|
+
trailHalfWidthArr[aIdx + 1] = 0;
|
|
2662
|
+
trailAlphaArr[aIdx] = 0;
|
|
2663
|
+
trailAlphaArr[aIdx + 1] = 0;
|
|
2664
|
+
trailColorArr[cIdx] = 0;
|
|
2665
|
+
trailColorArr[cIdx + 1] = 0;
|
|
2666
|
+
trailColorArr[cIdx + 2] = 0;
|
|
2667
|
+
trailColorArr[cIdx + 3] = 0;
|
|
2668
|
+
trailColorArr[cIdx + 4] = 0;
|
|
2669
|
+
trailColorArr[cIdx + 5] = 0;
|
|
2670
|
+
trailColorArr[cIdx + 6] = 0;
|
|
2671
|
+
trailColorArr[cIdx + 7] = 0;
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
if (hasUpdates) {
|
|
2676
|
+
trailPositionAttr.needsUpdate = true;
|
|
2677
|
+
trailAlphaAttr.needsUpdate = true;
|
|
2678
|
+
trailColorAttr.needsUpdate = true;
|
|
2679
|
+
const nextAttr = trailMesh.geometry.getAttribute(
|
|
2680
|
+
"trailNext"
|
|
2681
|
+
);
|
|
2682
|
+
const hwAttr = trailMesh.geometry.getAttribute(
|
|
2683
|
+
"trailHalfWidth"
|
|
2684
|
+
);
|
|
2685
|
+
nextAttr.needsUpdate = true;
|
|
2686
|
+
hwAttr.needsUpdate = true;
|
|
2687
|
+
const uvAttr = trailMesh.geometry.getAttribute(
|
|
2688
|
+
"trailUV"
|
|
2689
|
+
);
|
|
2690
|
+
uvAttr.needsUpdate = true;
|
|
2691
|
+
}
|
|
1991
2692
|
};
|
|
1992
2693
|
var updateParticleSystems = (cycleData) => {
|
|
1993
2694
|
createdParticleSystems.forEach(
|
|
@@ -1995,6 +2696,6 @@ var updateParticleSystems = (cycleData) => {
|
|
|
1995
2696
|
);
|
|
1996
2697
|
};
|
|
1997
2698
|
|
|
1998
|
-
export { CurveFunctionId, EmitFrom, ForceFieldFalloff, ForceFieldType, LifeTimeCurve, RendererType, Shape, SimulationSpace, SubEmitterTrigger, TimeMode, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
|
|
2699
|
+
export { CurveFunctionId, EmitFrom, ForceFieldFalloff, ForceFieldType, LifeTimeCurve, RendererType, Shape, SimulationSpace, SubEmitterTrigger, TimeMode, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultMeshTexture, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
|
|
1999
2700
|
//# sourceMappingURL=index.js.map
|
|
2000
2701
|
//# sourceMappingURL=index.js.map
|