@newkrok/three-particles 2.13.0 → 2.14.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 +1 -0
- package/dist/index.d.ts +124 -2
- package/dist/index.js +764 -128
- 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/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -535,6 +535,10 @@ var InstancedParticleFragmentShader = `
|
|
|
535
535
|
uniform bool discardBackgroundColor;
|
|
536
536
|
uniform vec3 backgroundColor;
|
|
537
537
|
uniform float backgroundColorTolerance;
|
|
538
|
+
uniform bool softParticlesEnabled;
|
|
539
|
+
uniform float softParticlesIntensity;
|
|
540
|
+
uniform sampler2D sceneDepthTexture;
|
|
541
|
+
uniform vec2 cameraNearFar;
|
|
538
542
|
|
|
539
543
|
varying vec2 vUv;
|
|
540
544
|
varying vec4 vColor;
|
|
@@ -542,10 +546,16 @@ var InstancedParticleFragmentShader = `
|
|
|
542
546
|
varying float vStartLifetime;
|
|
543
547
|
varying float vStartFrame;
|
|
544
548
|
varying float vRotation;
|
|
549
|
+
varying float vViewZ;
|
|
545
550
|
|
|
546
551
|
#include <common>
|
|
547
552
|
#include <logdepthbuf_pars_fragment>
|
|
548
553
|
|
|
554
|
+
float linearizeDepth(float depthSample, float near, float far) {
|
|
555
|
+
float z_ndc = 2.0 * depthSample - 1.0;
|
|
556
|
+
return 2.0 * near * far / (far + near - z_ndc * (far - near));
|
|
557
|
+
}
|
|
558
|
+
|
|
549
559
|
void main()
|
|
550
560
|
{
|
|
551
561
|
gl_FragColor = vColor;
|
|
@@ -588,6 +598,16 @@ var InstancedParticleFragmentShader = `
|
|
|
588
598
|
|
|
589
599
|
if (discardBackgroundColor && abs(length(rotatedTexture.rgb - backgroundColor.rgb)) < backgroundColorTolerance) discard;
|
|
590
600
|
|
|
601
|
+
if (softParticlesEnabled) {
|
|
602
|
+
vec2 screenUV = gl_FragCoord.xy / vec2(textureSize(sceneDepthTexture, 0));
|
|
603
|
+
float sceneDepthSample = texture2D(sceneDepthTexture, screenUV).r;
|
|
604
|
+
float sceneDepthLinear = linearizeDepth(sceneDepthSample, cameraNearFar.x, cameraNearFar.y);
|
|
605
|
+
float depthDiff = sceneDepthLinear - vViewZ;
|
|
606
|
+
float softFade = smoothstep(0.0, softParticlesIntensity, depthDiff);
|
|
607
|
+
gl_FragColor.a *= softFade;
|
|
608
|
+
if (gl_FragColor.a < 0.001) discard;
|
|
609
|
+
}
|
|
610
|
+
|
|
591
611
|
#include <logdepthbuf_fragment>
|
|
592
612
|
}
|
|
593
613
|
`;
|
|
@@ -614,6 +634,7 @@ var InstancedParticleVertexShader = `
|
|
|
614
634
|
varying float vStartLifetime;
|
|
615
635
|
varying float vStartFrame;
|
|
616
636
|
varying float vRotation;
|
|
637
|
+
varying float vViewZ;
|
|
617
638
|
|
|
618
639
|
#include <common>
|
|
619
640
|
#include <logdepthbuf_pars_vertex>
|
|
@@ -648,6 +669,7 @@ var InstancedParticleVertexShader = `
|
|
|
648
669
|
// identical to the Points renderer).
|
|
649
670
|
mvPosition.xy += position.xy * perspectiveSize;
|
|
650
671
|
|
|
672
|
+
vViewZ = -mvPosition.z;
|
|
651
673
|
gl_Position = projectionMatrix * mvPosition;
|
|
652
674
|
|
|
653
675
|
// Pass UV for texture sampling (quad ranges from -0.5..0.5, map to 0..1).
|
|
@@ -669,6 +691,10 @@ var MeshParticleFragmentShader = `
|
|
|
669
691
|
uniform bool discardBackgroundColor;
|
|
670
692
|
uniform vec3 backgroundColor;
|
|
671
693
|
uniform float backgroundColorTolerance;
|
|
694
|
+
uniform bool softParticlesEnabled;
|
|
695
|
+
uniform float softParticlesIntensity;
|
|
696
|
+
uniform sampler2D sceneDepthTexture;
|
|
697
|
+
uniform vec2 cameraNearFar;
|
|
672
698
|
|
|
673
699
|
varying vec4 vColor;
|
|
674
700
|
varying float vLifetime;
|
|
@@ -677,10 +703,16 @@ var MeshParticleFragmentShader = `
|
|
|
677
703
|
varying float vRotation;
|
|
678
704
|
varying vec3 vNormal;
|
|
679
705
|
varying vec2 vUv;
|
|
706
|
+
varying float vViewZ;
|
|
680
707
|
|
|
681
708
|
#include <common>
|
|
682
709
|
#include <logdepthbuf_pars_fragment>
|
|
683
710
|
|
|
711
|
+
float linearizeDepth(float depthSample, float near, float far) {
|
|
712
|
+
float z_ndc = 2.0 * depthSample - 1.0;
|
|
713
|
+
return 2.0 * near * far / (far + near - z_ndc * (far - near));
|
|
714
|
+
}
|
|
715
|
+
|
|
684
716
|
void main()
|
|
685
717
|
{
|
|
686
718
|
gl_FragColor = vColor;
|
|
@@ -716,6 +748,16 @@ var MeshParticleFragmentShader = `
|
|
|
716
748
|
float lightIntensity = 0.5 + 0.5 * max(dot(vNormal, vec3(0.0, 0.0, 1.0)), 0.0);
|
|
717
749
|
gl_FragColor.rgb *= lightIntensity;
|
|
718
750
|
|
|
751
|
+
if (softParticlesEnabled) {
|
|
752
|
+
vec2 screenUV = gl_FragCoord.xy / vec2(textureSize(sceneDepthTexture, 0));
|
|
753
|
+
float sceneDepthSample = texture2D(sceneDepthTexture, screenUV).r;
|
|
754
|
+
float sceneDepthLinear = linearizeDepth(sceneDepthSample, cameraNearFar.x, cameraNearFar.y);
|
|
755
|
+
float depthDiff = sceneDepthLinear - vViewZ;
|
|
756
|
+
float softFade = smoothstep(0.0, softParticlesIntensity, depthDiff);
|
|
757
|
+
gl_FragColor.a *= softFade;
|
|
758
|
+
if (gl_FragColor.a < 0.001) discard;
|
|
759
|
+
}
|
|
760
|
+
|
|
719
761
|
#include <logdepthbuf_fragment>
|
|
720
762
|
}
|
|
721
763
|
`;
|
|
@@ -742,6 +784,7 @@ var MeshParticleVertexShader = `
|
|
|
742
784
|
varying float vRotation;
|
|
743
785
|
varying vec3 vNormal;
|
|
744
786
|
varying vec2 vUv;
|
|
787
|
+
varying float vViewZ;
|
|
745
788
|
|
|
746
789
|
#include <common>
|
|
747
790
|
#include <logdepthbuf_pars_vertex>
|
|
@@ -769,6 +812,7 @@ var MeshParticleVertexShader = `
|
|
|
769
812
|
vec3 worldPos = scaledPosition + instanceOffset;
|
|
770
813
|
|
|
771
814
|
vec4 mvPosition = modelViewMatrix * vec4(worldPos, 1.0);
|
|
815
|
+
vViewZ = -mvPosition.z;
|
|
772
816
|
gl_Position = projectionMatrix * mvPosition;
|
|
773
817
|
|
|
774
818
|
// Transform normal by quaternion for lighting
|
|
@@ -792,16 +836,26 @@ var ParticleSystemFragmentShader = `
|
|
|
792
836
|
uniform bool discardBackgroundColor;
|
|
793
837
|
uniform vec3 backgroundColor;
|
|
794
838
|
uniform float backgroundColorTolerance;
|
|
839
|
+
uniform bool softParticlesEnabled;
|
|
840
|
+
uniform float softParticlesIntensity;
|
|
841
|
+
uniform sampler2D sceneDepthTexture;
|
|
842
|
+
uniform vec2 cameraNearFar;
|
|
795
843
|
|
|
796
844
|
varying vec4 vColor;
|
|
797
845
|
varying float vLifetime;
|
|
798
846
|
varying float vStartLifetime;
|
|
799
847
|
varying float vRotation;
|
|
800
848
|
varying float vStartFrame;
|
|
849
|
+
varying float vViewZ;
|
|
801
850
|
|
|
802
851
|
#include <common>
|
|
803
852
|
#include <logdepthbuf_pars_fragment>
|
|
804
853
|
|
|
854
|
+
float linearizeDepth(float depthSample, float near, float far) {
|
|
855
|
+
float z_ndc = 2.0 * depthSample - 1.0;
|
|
856
|
+
return 2.0 * near * far / (far + near - z_ndc * (far - near));
|
|
857
|
+
}
|
|
858
|
+
|
|
805
859
|
void main()
|
|
806
860
|
{
|
|
807
861
|
gl_FragColor = vColor;
|
|
@@ -849,7 +903,17 @@ var ParticleSystemFragmentShader = `
|
|
|
849
903
|
gl_FragColor = gl_FragColor * rotatedTexture;
|
|
850
904
|
|
|
851
905
|
if (discardBackgroundColor && abs(length(rotatedTexture.rgb - backgroundColor.rgb)) < backgroundColorTolerance) discard;
|
|
852
|
-
|
|
906
|
+
|
|
907
|
+
if (softParticlesEnabled) {
|
|
908
|
+
vec2 screenUV = gl_FragCoord.xy / vec2(textureSize(sceneDepthTexture, 0));
|
|
909
|
+
float sceneDepthSample = texture2D(sceneDepthTexture, screenUV).r;
|
|
910
|
+
float sceneDepthLinear = linearizeDepth(sceneDepthSample, cameraNearFar.x, cameraNearFar.y);
|
|
911
|
+
float depthDiff = sceneDepthLinear - vViewZ;
|
|
912
|
+
float softFade = smoothstep(0.0, softParticlesIntensity, depthDiff);
|
|
913
|
+
gl_FragColor.a *= softFade;
|
|
914
|
+
if (gl_FragColor.a < 0.001) discard;
|
|
915
|
+
}
|
|
916
|
+
|
|
853
917
|
#include <logdepthbuf_fragment>
|
|
854
918
|
}
|
|
855
919
|
`;
|
|
@@ -873,6 +937,7 @@ var ParticleSystemVertexShader = `
|
|
|
873
937
|
varying float vStartLifetime;
|
|
874
938
|
varying float vRotation;
|
|
875
939
|
varying float vStartFrame;
|
|
940
|
+
varying float vViewZ;
|
|
876
941
|
|
|
877
942
|
#include <common>
|
|
878
943
|
#include <logdepthbuf_pars_vertex>
|
|
@@ -887,6 +952,7 @@ var ParticleSystemVertexShader = `
|
|
|
887
952
|
|
|
888
953
|
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
|
|
889
954
|
gl_PointSize = size * (100.0 / length(mvPosition.xyz));
|
|
955
|
+
vViewZ = -mvPosition.z;
|
|
890
956
|
gl_Position = projectionMatrix * mvPosition;
|
|
891
957
|
|
|
892
958
|
#include <logdepthbuf_vertex>
|
|
@@ -901,14 +967,24 @@ var TrailFragmentShader = `
|
|
|
901
967
|
uniform bool discardBackgroundColor;
|
|
902
968
|
uniform vec3 backgroundColor;
|
|
903
969
|
uniform float backgroundColorTolerance;
|
|
970
|
+
uniform bool softParticlesEnabled;
|
|
971
|
+
uniform float softParticlesIntensity;
|
|
972
|
+
uniform sampler2D sceneDepthTexture;
|
|
973
|
+
uniform vec2 cameraNearFar;
|
|
904
974
|
|
|
905
975
|
varying float vAlpha;
|
|
906
976
|
varying vec4 vColor;
|
|
907
977
|
varying vec2 vUv;
|
|
978
|
+
varying float vViewZ;
|
|
908
979
|
|
|
909
980
|
#include <common>
|
|
910
981
|
#include <logdepthbuf_pars_fragment>
|
|
911
982
|
|
|
983
|
+
float linearizeDepth(float depthSample, float near, float far) {
|
|
984
|
+
float z_ndc = 2.0 * depthSample - 1.0;
|
|
985
|
+
return 2.0 * near * far / (far + near - z_ndc * (far - near));
|
|
986
|
+
}
|
|
987
|
+
|
|
912
988
|
void main()
|
|
913
989
|
{
|
|
914
990
|
// Soft edge: always fade near ribbon edges
|
|
@@ -929,6 +1005,16 @@ var TrailFragmentShader = `
|
|
|
929
1005
|
|
|
930
1006
|
if (gl_FragColor.a < 0.001) discard;
|
|
931
1007
|
|
|
1008
|
+
if (softParticlesEnabled) {
|
|
1009
|
+
vec2 screenUV = gl_FragCoord.xy / vec2(textureSize(sceneDepthTexture, 0));
|
|
1010
|
+
float sceneDepthSample = texture2D(sceneDepthTexture, screenUV).r;
|
|
1011
|
+
float sceneDepthLinear = linearizeDepth(sceneDepthSample, cameraNearFar.x, cameraNearFar.y);
|
|
1012
|
+
float depthDiff = sceneDepthLinear - vViewZ;
|
|
1013
|
+
float softFade = smoothstep(0.0, softParticlesIntensity, depthDiff);
|
|
1014
|
+
gl_FragColor.a *= softFade;
|
|
1015
|
+
if (gl_FragColor.a < 0.001) discard;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
932
1018
|
if (discardBackgroundColor && abs(length(gl_FragColor.rgb - backgroundColor.rgb)) < backgroundColorTolerance) discard;
|
|
933
1019
|
|
|
934
1020
|
#include <logdepthbuf_fragment>
|
|
@@ -948,6 +1034,7 @@ var TrailVertexShader = `
|
|
|
948
1034
|
varying float vAlpha;
|
|
949
1035
|
varying vec4 vColor;
|
|
950
1036
|
varying vec2 vUv;
|
|
1037
|
+
varying float vViewZ;
|
|
951
1038
|
|
|
952
1039
|
#include <common>
|
|
953
1040
|
#include <logdepthbuf_pars_vertex>
|
|
@@ -974,28 +1061,27 @@ var TrailVertexShader = `
|
|
|
974
1061
|
float perpLen = length(perp);
|
|
975
1062
|
|
|
976
1063
|
// When tangent is nearly parallel to view direction, the cross product
|
|
977
|
-
// collapses and the ribbon becomes edge-on (invisible).
|
|
978
|
-
// perpendicular from
|
|
979
|
-
//
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
upPerp = cross(tangent, vec3(1.0, 0.0, 0.0));
|
|
984
|
-
upPerpLen = length(upPerp);
|
|
985
|
-
}
|
|
986
|
-
upPerp = upPerp / max(upPerpLen, 0.0001);
|
|
1064
|
+
// collapses and the ribbon becomes edge-on (invisible). Build a stable
|
|
1065
|
+
// fallback perpendicular from the camera's right axis \u2014 this keeps the
|
|
1066
|
+
// ribbon in screen-space and prevents it from flipping into an arbitrary
|
|
1067
|
+
// plane when viewed edge-on.
|
|
1068
|
+
vec3 camRight = vec3(viewMatrix[0][0], viewMatrix[1][0], viewMatrix[2][0]);
|
|
1069
|
+
vec3 fallbackPerp = normalize(camRight - tangent * dot(camRight, tangent));
|
|
987
1070
|
|
|
988
1071
|
if (perpLen < 0.0001) {
|
|
989
|
-
perp =
|
|
1072
|
+
perp = fallbackPerp;
|
|
990
1073
|
} else {
|
|
991
1074
|
perp = perp / perpLen;
|
|
992
|
-
//
|
|
993
|
-
|
|
994
|
-
|
|
1075
|
+
// Smoothly blend toward the fallback when the billboard perp weakens.
|
|
1076
|
+
// The wide range (0..0.7) ensures a gradual transition so the ribbon
|
|
1077
|
+
// does not snap abruptly when rotating toward edge-on.
|
|
1078
|
+
float blendFactor = smoothstep(0.0, 0.7, perpLen);
|
|
1079
|
+
perp = normalize(mix(fallbackPerp, perp, blendFactor));
|
|
995
1080
|
}
|
|
996
1081
|
|
|
997
1082
|
vec3 offsetPos = position + perp * trailOffset * trailHalfWidth;
|
|
998
1083
|
vec4 mvPosition = modelViewMatrix * vec4(offsetPos, 1.0);
|
|
1084
|
+
vViewZ = -mvPosition.z;
|
|
999
1085
|
gl_Position = projectionMatrix * mvPosition;
|
|
1000
1086
|
|
|
1001
1087
|
#include <logdepthbuf_vertex>
|
|
@@ -1168,7 +1254,11 @@ var DEFAULT_PARTICLE_SYSTEM_CONFIG = {
|
|
|
1168
1254
|
backgroundColor: { r: 1, g: 1, b: 1 },
|
|
1169
1255
|
transparent: true,
|
|
1170
1256
|
depthTest: true,
|
|
1171
|
-
depthWrite: false
|
|
1257
|
+
depthWrite: false,
|
|
1258
|
+
softParticles: {
|
|
1259
|
+
enabled: false,
|
|
1260
|
+
intensity: 1
|
|
1261
|
+
}
|
|
1172
1262
|
},
|
|
1173
1263
|
velocityOverLifetime: {
|
|
1174
1264
|
isActive: false,
|
|
@@ -1598,7 +1688,13 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1598
1688
|
renderer.trail?.opacityOverTrail,
|
|
1599
1689
|
defaultTrailCurve
|
|
1600
1690
|
),
|
|
1601
|
-
colorOverTrail: renderer.trail?.colorOverTrail
|
|
1691
|
+
colorOverTrail: renderer.trail?.colorOverTrail,
|
|
1692
|
+
minVertexDistance: renderer.trail?.minVertexDistance ?? 0,
|
|
1693
|
+
maxTime: renderer.trail?.maxTime ?? 0,
|
|
1694
|
+
smoothing: renderer.trail?.smoothing ?? false,
|
|
1695
|
+
smoothingSubdivisions: renderer.trail?.smoothingSubdivisions ?? 3,
|
|
1696
|
+
twistPrevention: renderer.trail?.twistPrevention ?? false,
|
|
1697
|
+
ribbonId: renderer.trail?.ribbonId
|
|
1602
1698
|
} : void 0;
|
|
1603
1699
|
if (useTrail && trailConfig) {
|
|
1604
1700
|
const trailLength = trailConfig.length;
|
|
@@ -1608,9 +1704,21 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1608
1704
|
);
|
|
1609
1705
|
generalData.positionHistoryIndex = new Uint16Array(maxParticles);
|
|
1610
1706
|
generalData.positionHistoryCount = new Uint16Array(maxParticles);
|
|
1707
|
+
if (trailConfig.minVertexDistance > 0) {
|
|
1708
|
+
generalData.trailLastSampledPosition = new Float32Array(maxParticles * 3);
|
|
1709
|
+
}
|
|
1710
|
+
if (trailConfig.maxTime > 0) {
|
|
1711
|
+
generalData.trailSampleTimes = new Float64Array(
|
|
1712
|
+
maxParticles * trailLength
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
if (trailConfig.twistPrevention) {
|
|
1716
|
+
generalData.trailPrevNormal = new Float32Array(maxParticles * 3);
|
|
1717
|
+
}
|
|
1611
1718
|
}
|
|
1612
1719
|
const attr = (name) => useInstancedAttributes ? `instance${name.charAt(0).toUpperCase()}${name.slice(1)}` : name;
|
|
1613
1720
|
const posAttr = useInstancedAttributes ? "instanceOffset" : "position";
|
|
1721
|
+
const softParticlesEnabled = !!(renderer.softParticles?.enabled && renderer.softParticles?.depthTexture);
|
|
1614
1722
|
const sharedUniforms = {
|
|
1615
1723
|
elapsed: { value: 0 },
|
|
1616
1724
|
map: { value: particleMap },
|
|
@@ -1622,7 +1730,15 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1622
1730
|
backgroundColor: { value: renderer.backgroundColor },
|
|
1623
1731
|
discardBackgroundColor: { value: renderer.discardBackgroundColor },
|
|
1624
1732
|
backgroundColorTolerance: { value: renderer.backgroundColorTolerance },
|
|
1625
|
-
...useInstancing ? { viewportHeight: { value: 1 } } : {}
|
|
1733
|
+
...useInstancing ? { viewportHeight: { value: 1 } } : {},
|
|
1734
|
+
softParticlesEnabled: { value: softParticlesEnabled },
|
|
1735
|
+
softParticlesIntensity: {
|
|
1736
|
+
value: Math.max(renderer.softParticles?.intensity ?? 1, 1e-3)
|
|
1737
|
+
},
|
|
1738
|
+
sceneDepthTexture: {
|
|
1739
|
+
value: renderer.softParticles?.depthTexture ?? null
|
|
1740
|
+
},
|
|
1741
|
+
cameraNearFar: { value: new THREE4.Vector2(0.1, 1e3) }
|
|
1626
1742
|
};
|
|
1627
1743
|
const getVertexShader = () => {
|
|
1628
1744
|
if (useMesh) return mesh_particle_vertex_shader_glsl_default;
|
|
@@ -1820,6 +1936,18 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1820
1936
|
if (generalData.positionHistoryCount) {
|
|
1821
1937
|
generalData.positionHistoryCount[particleIndex] = 0;
|
|
1822
1938
|
generalData.positionHistoryIndex[particleIndex] = 0;
|
|
1939
|
+
if (generalData.trailLastSampledPosition) {
|
|
1940
|
+
const lsIdx = particleIndex * 3;
|
|
1941
|
+
generalData.trailLastSampledPosition[lsIdx] = 0;
|
|
1942
|
+
generalData.trailLastSampledPosition[lsIdx + 1] = 0;
|
|
1943
|
+
generalData.trailLastSampledPosition[lsIdx + 2] = 0;
|
|
1944
|
+
}
|
|
1945
|
+
if (generalData.trailPrevNormal) {
|
|
1946
|
+
const nIdx = particleIndex * 3;
|
|
1947
|
+
generalData.trailPrevNormal[nIdx] = 0;
|
|
1948
|
+
generalData.trailPrevNormal[nIdx + 1] = 0;
|
|
1949
|
+
generalData.trailPrevNormal[nIdx + 2] = 0;
|
|
1950
|
+
}
|
|
1823
1951
|
}
|
|
1824
1952
|
if (generalData.noise.offsets)
|
|
1825
1953
|
generalData.noise.offsets[particleIndex] = Math.random() * 100;
|
|
@@ -2085,7 +2213,15 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
2085
2213
|
useMap: { value: !!particleMap },
|
|
2086
2214
|
discardBackgroundColor: { value: renderer.discardBackgroundColor },
|
|
2087
2215
|
backgroundColor: { value: renderer.backgroundColor },
|
|
2088
|
-
backgroundColorTolerance: { value: renderer.backgroundColorTolerance }
|
|
2216
|
+
backgroundColorTolerance: { value: renderer.backgroundColorTolerance },
|
|
2217
|
+
softParticlesEnabled: { value: softParticlesEnabled },
|
|
2218
|
+
softParticlesIntensity: {
|
|
2219
|
+
value: Math.max(renderer.softParticles?.intensity ?? 1, 1e-3)
|
|
2220
|
+
},
|
|
2221
|
+
sceneDepthTexture: {
|
|
2222
|
+
value: renderer.softParticles?.depthTexture ?? null
|
|
2223
|
+
},
|
|
2224
|
+
cameraNearFar: { value: new THREE4.Vector2(0.1, 1e3) }
|
|
2089
2225
|
},
|
|
2090
2226
|
vertexShader: trail_vertex_shader_glsl_default,
|
|
2091
2227
|
fragmentShader: trail_fragment_shader_glsl_default,
|
|
@@ -2100,6 +2236,14 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
2100
2236
|
const trailCameraPos = new THREE4.Vector3();
|
|
2101
2237
|
trailMesh.onBeforeRender = (_renderer, _scene, camera) => {
|
|
2102
2238
|
camera.getWorldPosition(trailCameraPos);
|
|
2239
|
+
if (softParticlesEnabled && camera.isPerspectiveCamera) {
|
|
2240
|
+
const perspCam = camera;
|
|
2241
|
+
const trailUniforms = trailMaterial.uniforms;
|
|
2242
|
+
trailUniforms.cameraNearFar.value.set(
|
|
2243
|
+
perspCam.near,
|
|
2244
|
+
perspCam.far
|
|
2245
|
+
);
|
|
2246
|
+
}
|
|
2103
2247
|
};
|
|
2104
2248
|
generalData.trailCameraPosition = trailCameraPos;
|
|
2105
2249
|
trailWidthCurveFn = getCurveFunctionFromConfig(
|
|
@@ -2128,10 +2272,19 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
2128
2272
|
}
|
|
2129
2273
|
}
|
|
2130
2274
|
let particleSystem = useInstancing || useMesh ? new THREE4.Mesh(geometry, material) : new THREE4.Points(geometry, material);
|
|
2131
|
-
if (useInstancing) {
|
|
2132
|
-
particleSystem.onBeforeRender = (glRenderer) => {
|
|
2133
|
-
|
|
2134
|
-
|
|
2275
|
+
if (useInstancing || softParticlesEnabled) {
|
|
2276
|
+
particleSystem.onBeforeRender = (glRenderer, _scene, camera) => {
|
|
2277
|
+
if (useInstancing) {
|
|
2278
|
+
const size = glRenderer.getSize(new THREE4.Vector2());
|
|
2279
|
+
sharedUniforms.viewportHeight.value = size.y * glRenderer.getPixelRatio();
|
|
2280
|
+
}
|
|
2281
|
+
if (softParticlesEnabled && camera.isPerspectiveCamera) {
|
|
2282
|
+
const perspCam = camera;
|
|
2283
|
+
sharedUniforms.cameraNearFar.value.set(
|
|
2284
|
+
perspCam.near,
|
|
2285
|
+
perspCam.far
|
|
2286
|
+
);
|
|
2287
|
+
}
|
|
2135
2288
|
};
|
|
2136
2289
|
}
|
|
2137
2290
|
if (useTrail && trailMesh) {
|
|
@@ -2227,7 +2380,13 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
2227
2380
|
trailColorOverTrailFns,
|
|
2228
2381
|
trailConfig: {
|
|
2229
2382
|
length: trailConfig.length,
|
|
2230
|
-
width: trailConfig.width
|
|
2383
|
+
width: trailConfig.width,
|
|
2384
|
+
minVertexDistance: trailConfig.minVertexDistance,
|
|
2385
|
+
maxTime: trailConfig.maxTime,
|
|
2386
|
+
smoothing: trailConfig.smoothing,
|
|
2387
|
+
smoothingSubdivisions: trailConfig.smoothingSubdivisions,
|
|
2388
|
+
twistPrevention: trailConfig.twistPrevention,
|
|
2389
|
+
ribbonId: trailConfig.ribbonId
|
|
2231
2390
|
}
|
|
2232
2391
|
} : {}
|
|
2233
2392
|
};
|
|
@@ -2489,10 +2648,84 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
|
|
|
2489
2648
|
particleSystem
|
|
2490
2649
|
});
|
|
2491
2650
|
if (props.trailMesh) {
|
|
2492
|
-
updateTrailGeometry(props);
|
|
2651
|
+
updateTrailGeometry(props, now);
|
|
2493
2652
|
}
|
|
2494
2653
|
};
|
|
2495
|
-
var
|
|
2654
|
+
var catmullRom = (out, outIdx, p0x, p0y, p0z, p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z, t) => {
|
|
2655
|
+
const t2 = t * t;
|
|
2656
|
+
const t3 = t2 * t;
|
|
2657
|
+
out[outIdx] = 0.5 * (2 * p1x + (-p0x + p2x) * t + (2 * p0x - 5 * p1x + 4 * p2x - p3x) * t2 + (-p0x + 3 * p1x - 3 * p2x + p3x) * t3);
|
|
2658
|
+
out[outIdx + 1] = 0.5 * (2 * p1y + (-p0y + p2y) * t + (2 * p0y - 5 * p1y + 4 * p2y - p3y) * t2 + (-p0y + 3 * p1y - 3 * p2y + p3y) * t3);
|
|
2659
|
+
out[outIdx + 2] = 0.5 * (2 * p1z + (-p0z + p2z) * t + (2 * p0z - 5 * p1z + 4 * p2z - p3z) * t2 + (-p0z + 3 * p1z - 3 * p2z + p3z) * t3);
|
|
2660
|
+
};
|
|
2661
|
+
var clearTrailVertex = (vIdx, cIdx, aIdx, uvIdx, trailPosArr, trailNextArr, trailHalfWidthArr, trailUVArr, trailAlphaArr, trailColorArr, fallbackX, fallbackY, fallbackZ) => {
|
|
2662
|
+
trailPosArr[vIdx] = fallbackX;
|
|
2663
|
+
trailPosArr[vIdx + 1] = fallbackY;
|
|
2664
|
+
trailPosArr[vIdx + 2] = fallbackZ;
|
|
2665
|
+
trailPosArr[vIdx + 3] = fallbackX;
|
|
2666
|
+
trailPosArr[vIdx + 4] = fallbackY;
|
|
2667
|
+
trailPosArr[vIdx + 5] = fallbackZ;
|
|
2668
|
+
trailNextArr[vIdx] = fallbackX;
|
|
2669
|
+
trailNextArr[vIdx + 1] = fallbackY;
|
|
2670
|
+
trailNextArr[vIdx + 2] = fallbackZ;
|
|
2671
|
+
trailNextArr[vIdx + 3] = fallbackX;
|
|
2672
|
+
trailNextArr[vIdx + 4] = fallbackY;
|
|
2673
|
+
trailNextArr[vIdx + 5] = fallbackZ;
|
|
2674
|
+
trailHalfWidthArr[aIdx] = 0;
|
|
2675
|
+
trailHalfWidthArr[aIdx + 1] = 0;
|
|
2676
|
+
trailUVArr[uvIdx] = 0;
|
|
2677
|
+
trailUVArr[uvIdx + 1] = 0;
|
|
2678
|
+
trailUVArr[uvIdx + 2] = 0;
|
|
2679
|
+
trailUVArr[uvIdx + 3] = 0;
|
|
2680
|
+
trailAlphaArr[aIdx] = 0;
|
|
2681
|
+
trailAlphaArr[aIdx + 1] = 0;
|
|
2682
|
+
trailColorArr[cIdx] = 0;
|
|
2683
|
+
trailColorArr[cIdx + 1] = 0;
|
|
2684
|
+
trailColorArr[cIdx + 2] = 0;
|
|
2685
|
+
trailColorArr[cIdx + 3] = 0;
|
|
2686
|
+
trailColorArr[cIdx + 4] = 0;
|
|
2687
|
+
trailColorArr[cIdx + 5] = 0;
|
|
2688
|
+
trailColorArr[cIdx + 6] = 0;
|
|
2689
|
+
trailColorArr[cIdx + 7] = 0;
|
|
2690
|
+
};
|
|
2691
|
+
var writeTrailVertex = (vIdx, cIdx, aIdx, uvIdx, hx, hy, hz, nx, ny, nz, halfWidth, t, alpha, fr, fg, fb, ca, trailPosArr, trailNextArr, trailHalfWidthArr, trailUVArr, trailAlphaArr, trailColorArr) => {
|
|
2692
|
+
trailPosArr[vIdx] = hx;
|
|
2693
|
+
trailPosArr[vIdx + 1] = hy;
|
|
2694
|
+
trailPosArr[vIdx + 2] = hz;
|
|
2695
|
+
trailPosArr[vIdx + 3] = hx;
|
|
2696
|
+
trailPosArr[vIdx + 4] = hy;
|
|
2697
|
+
trailPosArr[vIdx + 5] = hz;
|
|
2698
|
+
trailNextArr[vIdx] = nx;
|
|
2699
|
+
trailNextArr[vIdx + 1] = ny;
|
|
2700
|
+
trailNextArr[vIdx + 2] = nz;
|
|
2701
|
+
trailNextArr[vIdx + 3] = nx;
|
|
2702
|
+
trailNextArr[vIdx + 4] = ny;
|
|
2703
|
+
trailNextArr[vIdx + 5] = nz;
|
|
2704
|
+
trailHalfWidthArr[aIdx] = halfWidth;
|
|
2705
|
+
trailHalfWidthArr[aIdx + 1] = halfWidth;
|
|
2706
|
+
trailUVArr[uvIdx] = 0;
|
|
2707
|
+
trailUVArr[uvIdx + 1] = t;
|
|
2708
|
+
trailUVArr[uvIdx + 2] = 1;
|
|
2709
|
+
trailUVArr[uvIdx + 3] = t;
|
|
2710
|
+
trailAlphaArr[aIdx] = alpha;
|
|
2711
|
+
trailAlphaArr[aIdx + 1] = alpha;
|
|
2712
|
+
trailColorArr[cIdx] = fr;
|
|
2713
|
+
trailColorArr[cIdx + 1] = fg;
|
|
2714
|
+
trailColorArr[cIdx + 2] = fb;
|
|
2715
|
+
trailColorArr[cIdx + 3] = ca;
|
|
2716
|
+
trailColorArr[cIdx + 4] = fr;
|
|
2717
|
+
trailColorArr[cIdx + 5] = fg;
|
|
2718
|
+
trailColorArr[cIdx + 6] = fb;
|
|
2719
|
+
trailColorArr[cIdx + 7] = ca;
|
|
2720
|
+
};
|
|
2721
|
+
var _rawPoints = null;
|
|
2722
|
+
var _rawPointsSize = 0;
|
|
2723
|
+
var _smoothedPoints = null;
|
|
2724
|
+
var _smoothedPointsSize = 0;
|
|
2725
|
+
var _ribbonIndices = null;
|
|
2726
|
+
var _ribbonIndicesSize = 0;
|
|
2727
|
+
var _ribbonCount = 0;
|
|
2728
|
+
var updateTrailGeometry = (props, now) => {
|
|
2496
2729
|
const {
|
|
2497
2730
|
generalData,
|
|
2498
2731
|
trailPositionAttr,
|
|
@@ -2510,13 +2743,23 @@ var updateTrailGeometry = (props) => {
|
|
|
2510
2743
|
const positionHistory = generalData.positionHistory;
|
|
2511
2744
|
const historyIndex = generalData.positionHistoryIndex;
|
|
2512
2745
|
const historyCount = generalData.positionHistoryCount;
|
|
2746
|
+
const sampleTimes = generalData.trailSampleTimes;
|
|
2747
|
+
const lastSampledPos = generalData.trailLastSampledPosition;
|
|
2748
|
+
const prevNormal = generalData.trailPrevNormal;
|
|
2749
|
+
const minVertexDist = trailConfig.minVertexDistance;
|
|
2750
|
+
const minVertexDistSq = minVertexDist * minVertexDist;
|
|
2751
|
+
const maxTime = trailConfig.maxTime;
|
|
2752
|
+
const maxTimeMs = maxTime * 1e3;
|
|
2753
|
+
const useSmoothing = trailConfig.smoothing;
|
|
2754
|
+
const subdivisions = trailConfig.smoothingSubdivisions;
|
|
2755
|
+
const useTwistPrevention = trailConfig.twistPrevention;
|
|
2756
|
+
const ribbonId = trailConfig.ribbonId;
|
|
2513
2757
|
const isActiveArr = ma.isActive.array;
|
|
2514
2758
|
const positionArr = ma.position.array;
|
|
2515
2759
|
const colorRArr = ma.colorR.array;
|
|
2516
2760
|
const colorGArr = ma.colorG.array;
|
|
2517
2761
|
const colorBArr = ma.colorB.array;
|
|
2518
2762
|
const colorAArr = ma.colorA.array;
|
|
2519
|
-
ma.size.array;
|
|
2520
2763
|
const trailPosArr = trailPositionAttr.array;
|
|
2521
2764
|
const trailAlphaArr = trailAlphaAttr.array;
|
|
2522
2765
|
const trailColorArr = trailColorAttr.array;
|
|
@@ -2527,115 +2770,329 @@ var updateTrailGeometry = (props) => {
|
|
|
2527
2770
|
const verticesPerParticle = trailLength * 2;
|
|
2528
2771
|
const creationTimesLength = generalData.creationTimes.length;
|
|
2529
2772
|
let hasUpdates = false;
|
|
2773
|
+
const useRibbon = ribbonId !== void 0;
|
|
2774
|
+
let ribbonLeader = -1;
|
|
2775
|
+
if (useRibbon) {
|
|
2776
|
+
if (!_ribbonIndices || _ribbonIndicesSize < creationTimesLength) {
|
|
2777
|
+
_ribbonIndices = new Uint16Array(creationTimesLength);
|
|
2778
|
+
_ribbonIndicesSize = creationTimesLength;
|
|
2779
|
+
}
|
|
2780
|
+
_ribbonCount = 0;
|
|
2781
|
+
for (let i = 0; i < creationTimesLength; i++) {
|
|
2782
|
+
if (isActiveArr[i]) _ribbonIndices[_ribbonCount++] = i;
|
|
2783
|
+
}
|
|
2784
|
+
for (let i = 1; i < _ribbonCount; i++) {
|
|
2785
|
+
const key = _ribbonIndices[i];
|
|
2786
|
+
const keyTime = generalData.creationTimes[key];
|
|
2787
|
+
let j = i - 1;
|
|
2788
|
+
while (j >= 0 && generalData.creationTimes[_ribbonIndices[j]] > keyTime) {
|
|
2789
|
+
_ribbonIndices[j + 1] = _ribbonIndices[j];
|
|
2790
|
+
j--;
|
|
2791
|
+
}
|
|
2792
|
+
_ribbonIndices[j + 1] = key;
|
|
2793
|
+
}
|
|
2794
|
+
if (_ribbonCount > 0) ribbonLeader = _ribbonIndices[0];
|
|
2795
|
+
}
|
|
2530
2796
|
for (let index = 0; index < creationTimesLength; index++) {
|
|
2531
2797
|
const vertBase = index * verticesPerParticle;
|
|
2532
2798
|
if (isActiveArr[index]) {
|
|
2799
|
+
if (useRibbon && _ribbonCount >= 2 && index !== ribbonLeader) {
|
|
2800
|
+
const posIdx2 = index * 3;
|
|
2801
|
+
const px2 = positionArr[posIdx2];
|
|
2802
|
+
const py2 = positionArr[posIdx2 + 1];
|
|
2803
|
+
const pz2 = positionArr[posIdx2 + 2];
|
|
2804
|
+
const histBase = (index * trailLength + historyIndex[index]) * 3;
|
|
2805
|
+
positionHistory[histBase] = px2;
|
|
2806
|
+
positionHistory[histBase + 1] = py2;
|
|
2807
|
+
positionHistory[histBase + 2] = pz2;
|
|
2808
|
+
if (sampleTimes) {
|
|
2809
|
+
sampleTimes[index * trailLength + historyIndex[index]] = now;
|
|
2810
|
+
}
|
|
2811
|
+
historyIndex[index] = (historyIndex[index] + 1) % trailLength;
|
|
2812
|
+
if (historyCount[index] < trailLength) historyCount[index]++;
|
|
2813
|
+
continue;
|
|
2814
|
+
}
|
|
2533
2815
|
hasUpdates = true;
|
|
2534
2816
|
const posIdx = index * 3;
|
|
2535
2817
|
const px = positionArr[posIdx];
|
|
2536
2818
|
const py = positionArr[posIdx + 1];
|
|
2537
2819
|
const pz = positionArr[posIdx + 2];
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2820
|
+
let shouldSample = true;
|
|
2821
|
+
if (minVertexDist > 0 && lastSampledPos && historyCount[index] > 0) {
|
|
2822
|
+
const lsIdx = index * 3;
|
|
2823
|
+
const dx = px - lastSampledPos[lsIdx];
|
|
2824
|
+
const dy = py - lastSampledPos[lsIdx + 1];
|
|
2825
|
+
const dz = pz - lastSampledPos[lsIdx + 2];
|
|
2826
|
+
if (dx * dx + dy * dy + dz * dz < minVertexDistSq) {
|
|
2827
|
+
shouldSample = false;
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
if (shouldSample) {
|
|
2831
|
+
const histBase = (index * trailLength + historyIndex[index]) * 3;
|
|
2832
|
+
positionHistory[histBase] = px;
|
|
2833
|
+
positionHistory[histBase + 1] = py;
|
|
2834
|
+
positionHistory[histBase + 2] = pz;
|
|
2835
|
+
if (sampleTimes) {
|
|
2836
|
+
sampleTimes[index * trailLength + historyIndex[index]] = now;
|
|
2837
|
+
}
|
|
2838
|
+
historyIndex[index] = (historyIndex[index] + 1) % trailLength;
|
|
2839
|
+
if (historyCount[index] < trailLength) historyCount[index]++;
|
|
2840
|
+
if (lastSampledPos) {
|
|
2841
|
+
const lsIdx = index * 3;
|
|
2842
|
+
lastSampledPos[lsIdx] = px;
|
|
2843
|
+
lastSampledPos[lsIdx + 1] = py;
|
|
2844
|
+
lastSampledPos[lsIdx + 2] = pz;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
let rawCount = historyCount[index];
|
|
2848
|
+
let effectiveCount = rawCount;
|
|
2849
|
+
if (maxTime > 0 && sampleTimes && rawCount > 0) {
|
|
2850
|
+
const sampleBase = index * trailLength;
|
|
2851
|
+
effectiveCount = 0;
|
|
2852
|
+
for (let s = 0; s < rawCount; s++) {
|
|
2853
|
+
const sampleSlot = (historyIndex[index] - 1 - s + trailLength * 2) % trailLength;
|
|
2854
|
+
const age = now - sampleTimes[sampleBase + sampleSlot];
|
|
2855
|
+
if (age <= maxTimeMs) {
|
|
2856
|
+
effectiveCount++;
|
|
2857
|
+
} else {
|
|
2858
|
+
break;
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
const count = effectiveCount;
|
|
2545
2863
|
const ribbonWidth = trailConfig.width;
|
|
2546
2864
|
const cr = colorRArr[index];
|
|
2547
2865
|
const cg = colorGArr[index];
|
|
2548
2866
|
const cb = colorBArr[index];
|
|
2549
2867
|
const ca = colorAArr[index];
|
|
2550
2868
|
const ringOff = index * trailLength * 3;
|
|
2869
|
+
const rawPtsSize = count * 3;
|
|
2870
|
+
if (!_rawPoints || _rawPointsSize < rawPtsSize) {
|
|
2871
|
+
_rawPoints = new Float32Array(rawPtsSize);
|
|
2872
|
+
_rawPointsSize = rawPtsSize;
|
|
2873
|
+
}
|
|
2874
|
+
const rawPts = _rawPoints;
|
|
2875
|
+
for (let s = 0; s < count; s++) {
|
|
2876
|
+
const histSlot = (historyIndex[index] - 1 - s + trailLength * 2) % trailLength * 3 + ringOff;
|
|
2877
|
+
rawPts[s * 3] = positionHistory[histSlot];
|
|
2878
|
+
rawPts[s * 3 + 1] = positionHistory[histSlot + 1];
|
|
2879
|
+
rawPts[s * 3 + 2] = positionHistory[histSlot + 2];
|
|
2880
|
+
}
|
|
2881
|
+
let finalPts;
|
|
2882
|
+
let finalCount;
|
|
2883
|
+
if (useSmoothing && count >= 3) {
|
|
2884
|
+
const segmentCount = count - 1;
|
|
2885
|
+
finalCount = segmentCount * subdivisions + 1;
|
|
2886
|
+
const neededSize = finalCount * 3;
|
|
2887
|
+
if (!_smoothedPoints || _smoothedPointsSize < neededSize) {
|
|
2888
|
+
_smoothedPoints = new Float32Array(neededSize);
|
|
2889
|
+
_smoothedPointsSize = neededSize;
|
|
2890
|
+
}
|
|
2891
|
+
finalPts = _smoothedPoints;
|
|
2892
|
+
for (let seg = 0; seg < segmentCount; seg++) {
|
|
2893
|
+
const i0 = Math.max(0, seg - 1);
|
|
2894
|
+
const i1 = seg;
|
|
2895
|
+
const i2 = Math.min(count - 1, seg + 1);
|
|
2896
|
+
const i3 = Math.min(count - 1, seg + 2);
|
|
2897
|
+
const p0x = rawPts[i0 * 3], p0y = rawPts[i0 * 3 + 1], p0z = rawPts[i0 * 3 + 2];
|
|
2898
|
+
const p1x = rawPts[i1 * 3], p1y = rawPts[i1 * 3 + 1], p1z = rawPts[i1 * 3 + 2];
|
|
2899
|
+
const p2x = rawPts[i2 * 3], p2y = rawPts[i2 * 3 + 1], p2z = rawPts[i2 * 3 + 2];
|
|
2900
|
+
const p3x = rawPts[i3 * 3], p3y = rawPts[i3 * 3 + 1], p3z = rawPts[i3 * 3 + 2];
|
|
2901
|
+
for (let sub = 0; sub < subdivisions; sub++) {
|
|
2902
|
+
const t = sub / subdivisions;
|
|
2903
|
+
const outIdx = (seg * subdivisions + sub) * 3;
|
|
2904
|
+
catmullRom(
|
|
2905
|
+
finalPts,
|
|
2906
|
+
outIdx,
|
|
2907
|
+
p0x,
|
|
2908
|
+
p0y,
|
|
2909
|
+
p0z,
|
|
2910
|
+
p1x,
|
|
2911
|
+
p1y,
|
|
2912
|
+
p1z,
|
|
2913
|
+
p2x,
|
|
2914
|
+
p2y,
|
|
2915
|
+
p2z,
|
|
2916
|
+
p3x,
|
|
2917
|
+
p3y,
|
|
2918
|
+
p3z,
|
|
2919
|
+
t
|
|
2920
|
+
);
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
const lastOutIdx = (finalCount - 1) * 3;
|
|
2924
|
+
finalPts[lastOutIdx] = rawPts[(count - 1) * 3];
|
|
2925
|
+
finalPts[lastOutIdx + 1] = rawPts[(count - 1) * 3 + 1];
|
|
2926
|
+
finalPts[lastOutIdx + 2] = rawPts[(count - 1) * 3 + 2];
|
|
2927
|
+
} else {
|
|
2928
|
+
finalPts = rawPts;
|
|
2929
|
+
finalCount = count;
|
|
2930
|
+
}
|
|
2931
|
+
if (finalCount > trailLength) finalCount = trailLength;
|
|
2932
|
+
if (useSmoothing && finalCount >= 2) {
|
|
2933
|
+
const MIN_SEG_DIST_SQ = 1e-4 * 1e-4;
|
|
2934
|
+
for (let d = 1; d < finalCount; d++) {
|
|
2935
|
+
const pi = (d - 1) * 3;
|
|
2936
|
+
const ci = d * 3;
|
|
2937
|
+
const dx = finalPts[ci] - finalPts[pi];
|
|
2938
|
+
const dy = finalPts[ci + 1] - finalPts[pi + 1];
|
|
2939
|
+
const dz = finalPts[ci + 2] - finalPts[pi + 2];
|
|
2940
|
+
if (dx * dx + dy * dy + dz * dz < MIN_SEG_DIST_SQ) {
|
|
2941
|
+
finalPts[ci] = finalPts[pi];
|
|
2942
|
+
finalPts[ci + 1] = finalPts[pi + 1];
|
|
2943
|
+
finalPts[ci + 2] = finalPts[pi + 2];
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2551
2947
|
for (let s = 0; s < trailLength; s++) {
|
|
2552
2948
|
const vIdx = (vertBase + s * 2) * 3;
|
|
2553
2949
|
const cIdx = (vertBase + s * 2) * 4;
|
|
2554
2950
|
const aIdx = vertBase + s * 2;
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
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;
|
|
2951
|
+
const uvIdxBase = (vertBase + s * 2) * 2;
|
|
2952
|
+
if (s >= finalCount) {
|
|
2953
|
+
clearTrailVertex(
|
|
2954
|
+
vIdx,
|
|
2955
|
+
cIdx,
|
|
2956
|
+
aIdx,
|
|
2957
|
+
uvIdxBase,
|
|
2958
|
+
trailPosArr,
|
|
2959
|
+
trailNextArr,
|
|
2960
|
+
trailHalfWidthArr,
|
|
2961
|
+
trailUVArr,
|
|
2962
|
+
trailAlphaArr,
|
|
2963
|
+
trailColorArr,
|
|
2964
|
+
px,
|
|
2965
|
+
py,
|
|
2966
|
+
pz
|
|
2967
|
+
);
|
|
2585
2968
|
continue;
|
|
2586
2969
|
}
|
|
2587
|
-
const
|
|
2588
|
-
const
|
|
2589
|
-
const
|
|
2590
|
-
const hz = positionHistory[histIdx + 2];
|
|
2970
|
+
const hx = finalPts[s * 3];
|
|
2971
|
+
const hy = finalPts[s * 3 + 1];
|
|
2972
|
+
const hz = finalPts[s * 3 + 2];
|
|
2591
2973
|
let nx, ny, nz;
|
|
2592
|
-
if (s <
|
|
2593
|
-
const
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2974
|
+
if (s > 0 && s < finalCount - 1) {
|
|
2975
|
+
const px2 = finalPts[(s - 1) * 3];
|
|
2976
|
+
const py2 = finalPts[(s - 1) * 3 + 1];
|
|
2977
|
+
const pz2 = finalPts[(s - 1) * 3 + 2];
|
|
2978
|
+
const nx2 = finalPts[(s + 1) * 3];
|
|
2979
|
+
const ny2 = finalPts[(s + 1) * 3 + 1];
|
|
2980
|
+
const nz2 = finalPts[(s + 1) * 3 + 2];
|
|
2981
|
+
const atx = nx2 - px2;
|
|
2982
|
+
const aty = ny2 - py2;
|
|
2983
|
+
const atz = nz2 - pz2;
|
|
2984
|
+
const atLen = Math.sqrt(atx * atx + aty * aty + atz * atz);
|
|
2985
|
+
if (atLen > 1e-4) {
|
|
2986
|
+
nx = hx + atx / atLen;
|
|
2987
|
+
ny = hy + aty / atLen;
|
|
2988
|
+
nz = hz + atz / atLen;
|
|
2989
|
+
} else {
|
|
2990
|
+
nx = finalPts[(s + 1) * 3];
|
|
2991
|
+
ny = finalPts[(s + 1) * 3 + 1];
|
|
2992
|
+
nz = finalPts[(s + 1) * 3 + 2];
|
|
2993
|
+
}
|
|
2994
|
+
} else if (s < finalCount - 1) {
|
|
2995
|
+
nx = finalPts[(s + 1) * 3];
|
|
2996
|
+
ny = finalPts[(s + 1) * 3 + 1];
|
|
2997
|
+
nz = finalPts[(s + 1) * 3 + 2];
|
|
2597
2998
|
} else {
|
|
2598
2999
|
nx = hx;
|
|
2599
3000
|
ny = hy + 1e-3;
|
|
2600
3001
|
nz = hz;
|
|
2601
3002
|
}
|
|
2602
|
-
const t =
|
|
3003
|
+
const t = finalCount > 1 ? s / (finalCount - 1) : 0;
|
|
3004
|
+
let timeFade = 1;
|
|
3005
|
+
if (maxTime > 0 && sampleTimes && effectiveCount > 0) {
|
|
3006
|
+
const rawS = useSmoothing ? Math.min(
|
|
3007
|
+
Math.floor(s / Math.max(finalCount - 1, 1) * (rawCount - 1)),
|
|
3008
|
+
rawCount - 1
|
|
3009
|
+
) : Math.min(s, rawCount - 1);
|
|
3010
|
+
const sampleSlot = (historyIndex[index] - 1 - rawS + trailLength * 2) % trailLength;
|
|
3011
|
+
const sampleBase = index * trailLength;
|
|
3012
|
+
const age = now - sampleTimes[sampleBase + sampleSlot];
|
|
3013
|
+
timeFade = 1 - Math.min(age / maxTimeMs, 1);
|
|
3014
|
+
}
|
|
2603
3015
|
const widthScale = trailWidthCurveFn(t);
|
|
2604
3016
|
const opacityScale = trailOpacityCurveFn(t);
|
|
2605
3017
|
const halfWidth = ribbonWidth * widthScale * 0.5;
|
|
2606
|
-
|
|
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;
|
|
3018
|
+
const alpha = ca * opacityScale * timeFade;
|
|
2628
3019
|
const fr = trailColorOverTrailFns ? cr * trailColorOverTrailFns.r(t) : cr;
|
|
2629
3020
|
const fg = trailColorOverTrailFns ? cg * trailColorOverTrailFns.g(t) : cg;
|
|
2630
3021
|
const fb = trailColorOverTrailFns ? cb * trailColorOverTrailFns.b(t) : cb;
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
3022
|
+
writeTrailVertex(
|
|
3023
|
+
vIdx,
|
|
3024
|
+
cIdx,
|
|
3025
|
+
aIdx,
|
|
3026
|
+
uvIdxBase,
|
|
3027
|
+
hx,
|
|
3028
|
+
hy,
|
|
3029
|
+
hz,
|
|
3030
|
+
nx,
|
|
3031
|
+
ny,
|
|
3032
|
+
nz,
|
|
3033
|
+
halfWidth,
|
|
3034
|
+
t,
|
|
3035
|
+
alpha,
|
|
3036
|
+
fr,
|
|
3037
|
+
fg,
|
|
3038
|
+
fb,
|
|
3039
|
+
ca,
|
|
3040
|
+
trailPosArr,
|
|
3041
|
+
trailNextArr,
|
|
3042
|
+
trailHalfWidthArr,
|
|
3043
|
+
trailUVArr,
|
|
3044
|
+
trailAlphaArr,
|
|
3045
|
+
trailColorArr
|
|
3046
|
+
);
|
|
3047
|
+
}
|
|
3048
|
+
if (useTwistPrevention && prevNormal && finalCount >= 2) {
|
|
3049
|
+
const nIdx = index * 3;
|
|
3050
|
+
const tx = finalPts[3] - finalPts[0];
|
|
3051
|
+
const ty = finalPts[4] - finalPts[1];
|
|
3052
|
+
const tz = finalPts[5] - finalPts[2];
|
|
3053
|
+
const tLen = Math.sqrt(tx * tx + ty * ty + tz * tz);
|
|
3054
|
+
if (tLen > 1e-4) {
|
|
3055
|
+
const ntx = tx / tLen;
|
|
3056
|
+
const nty = ty / tLen;
|
|
3057
|
+
const ntz = tz / tLen;
|
|
3058
|
+
let upx = 0, upy = 1, upz = 0;
|
|
3059
|
+
const dot = ntx * upx + nty * upy + ntz * upz;
|
|
3060
|
+
if (Math.abs(dot) > 0.999) {
|
|
3061
|
+
upx = 1;
|
|
3062
|
+
upy = 0;
|
|
3063
|
+
upz = 0;
|
|
3064
|
+
}
|
|
3065
|
+
let cnx = nty * upz - ntz * upy;
|
|
3066
|
+
let cny = ntz * upx - ntx * upz;
|
|
3067
|
+
let cnz = ntx * upy - nty * upx;
|
|
3068
|
+
const cnLen = Math.sqrt(cnx * cnx + cny * cny + cnz * cnz);
|
|
3069
|
+
if (cnLen > 1e-4) {
|
|
3070
|
+
cnx /= cnLen;
|
|
3071
|
+
cny /= cnLen;
|
|
3072
|
+
cnz /= cnLen;
|
|
3073
|
+
}
|
|
3074
|
+
const prevNx = prevNormal[nIdx];
|
|
3075
|
+
const prevNy = prevNormal[nIdx + 1];
|
|
3076
|
+
const prevNz = prevNormal[nIdx + 2];
|
|
3077
|
+
const hasPrev = prevNx !== 0 || prevNy !== 0 || prevNz !== 0;
|
|
3078
|
+
if (hasPrev) {
|
|
3079
|
+
const normalDot = cnx * prevNx + cny * prevNy + cnz * prevNz;
|
|
3080
|
+
if (normalDot < 0) {
|
|
3081
|
+
for (let s = 0; s < Math.min(finalCount, trailLength); s++) {
|
|
3082
|
+
const aIdx = vertBase + s * 2;
|
|
3083
|
+
const hw = trailHalfWidthArr[aIdx];
|
|
3084
|
+
trailHalfWidthArr[aIdx] = -hw;
|
|
3085
|
+
trailHalfWidthArr[aIdx + 1] = -hw;
|
|
3086
|
+
}
|
|
3087
|
+
cnx = -cnx;
|
|
3088
|
+
cny = -cny;
|
|
3089
|
+
cnz = -cnz;
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
prevNormal[nIdx] = cnx;
|
|
3093
|
+
prevNormal[nIdx + 1] = cny;
|
|
3094
|
+
prevNormal[nIdx + 2] = cnz;
|
|
3095
|
+
}
|
|
2639
3096
|
}
|
|
2640
3097
|
} else if (historyCount[index] > 0) {
|
|
2641
3098
|
hasUpdates = true;
|
|
@@ -2645,30 +3102,209 @@ var updateTrailGeometry = (props) => {
|
|
|
2645
3102
|
const vIdx = (vertBase + s * 2) * 3;
|
|
2646
3103
|
const cIdx = (vertBase + s * 2) * 4;
|
|
2647
3104
|
const aIdx = vertBase + s * 2;
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
3105
|
+
const uvIdxBase = (vertBase + s * 2) * 2;
|
|
3106
|
+
clearTrailVertex(
|
|
3107
|
+
vIdx,
|
|
3108
|
+
cIdx,
|
|
3109
|
+
aIdx,
|
|
3110
|
+
uvIdxBase,
|
|
3111
|
+
trailPosArr,
|
|
3112
|
+
trailNextArr,
|
|
3113
|
+
trailHalfWidthArr,
|
|
3114
|
+
trailUVArr,
|
|
3115
|
+
trailAlphaArr,
|
|
3116
|
+
trailColorArr,
|
|
3117
|
+
0,
|
|
3118
|
+
0,
|
|
3119
|
+
0
|
|
3120
|
+
);
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
if (useRibbon && _ribbonCount >= 2 && _ribbonIndices) {
|
|
3125
|
+
hasUpdates = true;
|
|
3126
|
+
const leader = _ribbonIndices[0];
|
|
3127
|
+
const leaderVertBase = leader * verticesPerParticle;
|
|
3128
|
+
const controlCount = _ribbonCount;
|
|
3129
|
+
const filledCount = Math.min(
|
|
3130
|
+
trailLength,
|
|
3131
|
+
Math.max(controlCount * 4, controlCount)
|
|
3132
|
+
);
|
|
3133
|
+
const chainSize = filledCount * 3;
|
|
3134
|
+
if (!_rawPoints || _rawPointsSize < chainSize) {
|
|
3135
|
+
_rawPoints = new Float32Array(chainSize);
|
|
3136
|
+
_rawPointsSize = chainSize;
|
|
3137
|
+
}
|
|
3138
|
+
if (controlCount === 2) {
|
|
3139
|
+
const p0Idx = _ribbonIndices[0] * 3;
|
|
3140
|
+
const p1Idx = _ribbonIndices[1] * 3;
|
|
3141
|
+
for (let i = 0; i < filledCount; i++) {
|
|
3142
|
+
const t = i / (filledCount - 1);
|
|
3143
|
+
_rawPoints[i * 3] = positionArr[p0Idx] + t * (positionArr[p1Idx] - positionArr[p0Idx]);
|
|
3144
|
+
_rawPoints[i * 3 + 1] = positionArr[p0Idx + 1] + t * (positionArr[p1Idx + 1] - positionArr[p0Idx + 1]);
|
|
3145
|
+
_rawPoints[i * 3 + 2] = positionArr[p0Idx + 2] + t * (positionArr[p1Idx + 2] - positionArr[p0Idx + 2]);
|
|
3146
|
+
}
|
|
3147
|
+
} else {
|
|
3148
|
+
const segments = controlCount - 1;
|
|
3149
|
+
const ptsPerSeg = Math.max(1, Math.floor((filledCount - 1) / segments));
|
|
3150
|
+
let wi = 0;
|
|
3151
|
+
for (let seg = 0; seg < segments && wi < filledCount; seg++) {
|
|
3152
|
+
const i0 = Math.max(0, seg - 1);
|
|
3153
|
+
const i1 = seg;
|
|
3154
|
+
const i2 = Math.min(controlCount - 1, seg + 1);
|
|
3155
|
+
const i3 = Math.min(controlCount - 1, seg + 2);
|
|
3156
|
+
const p0i = _ribbonIndices[i0] * 3;
|
|
3157
|
+
const p1i = _ribbonIndices[i1] * 3;
|
|
3158
|
+
const p2i = _ribbonIndices[i2] * 3;
|
|
3159
|
+
const p3i = _ribbonIndices[i3] * 3;
|
|
3160
|
+
const subCount = seg === segments - 1 ? filledCount - wi : ptsPerSeg;
|
|
3161
|
+
for (let sub = 0; sub < subCount && wi < filledCount; sub++) {
|
|
3162
|
+
const t = sub / subCount;
|
|
3163
|
+
catmullRom(
|
|
3164
|
+
_rawPoints,
|
|
3165
|
+
wi * 3,
|
|
3166
|
+
positionArr[p0i],
|
|
3167
|
+
positionArr[p0i + 1],
|
|
3168
|
+
positionArr[p0i + 2],
|
|
3169
|
+
positionArr[p1i],
|
|
3170
|
+
positionArr[p1i + 1],
|
|
3171
|
+
positionArr[p1i + 2],
|
|
3172
|
+
positionArr[p2i],
|
|
3173
|
+
positionArr[p2i + 1],
|
|
3174
|
+
positionArr[p2i + 2],
|
|
3175
|
+
positionArr[p3i],
|
|
3176
|
+
positionArr[p3i + 1],
|
|
3177
|
+
positionArr[p3i + 2],
|
|
3178
|
+
t
|
|
3179
|
+
);
|
|
3180
|
+
wi++;
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
if (wi > 0) {
|
|
3184
|
+
const lastPIdx = _ribbonIndices[controlCount - 1] * 3;
|
|
3185
|
+
_rawPoints[(wi - 1) * 3] = positionArr[lastPIdx];
|
|
3186
|
+
_rawPoints[(wi - 1) * 3 + 1] = positionArr[lastPIdx + 1];
|
|
3187
|
+
_rawPoints[(wi - 1) * 3 + 2] = positionArr[lastPIdx + 2];
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
const leaderCr = colorRArr[leader];
|
|
3191
|
+
const leaderCg = colorGArr[leader];
|
|
3192
|
+
const leaderCb = colorBArr[leader];
|
|
3193
|
+
const leaderCa = colorAArr[leader];
|
|
3194
|
+
for (let s = 0; s < trailLength; s++) {
|
|
3195
|
+
const vIdx = (leaderVertBase + s * 2) * 3;
|
|
3196
|
+
const cIdx = (leaderVertBase + s * 2) * 4;
|
|
3197
|
+
const aIdx = leaderVertBase + s * 2;
|
|
3198
|
+
const uvIdxBase = (leaderVertBase + s * 2) * 2;
|
|
3199
|
+
if (s >= filledCount) {
|
|
3200
|
+
clearTrailVertex(
|
|
3201
|
+
vIdx,
|
|
3202
|
+
cIdx,
|
|
3203
|
+
aIdx,
|
|
3204
|
+
uvIdxBase,
|
|
3205
|
+
trailPosArr,
|
|
3206
|
+
trailNextArr,
|
|
3207
|
+
trailHalfWidthArr,
|
|
3208
|
+
trailUVArr,
|
|
3209
|
+
trailAlphaArr,
|
|
3210
|
+
trailColorArr,
|
|
3211
|
+
0,
|
|
3212
|
+
0,
|
|
3213
|
+
0
|
|
3214
|
+
);
|
|
3215
|
+
continue;
|
|
3216
|
+
}
|
|
3217
|
+
const ptIdx = s * 3;
|
|
3218
|
+
const ptx = _rawPoints[ptIdx];
|
|
3219
|
+
const pty = _rawPoints[ptIdx + 1];
|
|
3220
|
+
const ptz = _rawPoints[ptIdx + 2];
|
|
3221
|
+
let nx, ny, nz;
|
|
3222
|
+
if (s > 0 && s < filledCount - 1) {
|
|
3223
|
+
const px2 = _rawPoints[(s - 1) * 3];
|
|
3224
|
+
const py2 = _rawPoints[(s - 1) * 3 + 1];
|
|
3225
|
+
const pz2 = _rawPoints[(s - 1) * 3 + 2];
|
|
3226
|
+
const nx2 = _rawPoints[(s + 1) * 3];
|
|
3227
|
+
const ny2 = _rawPoints[(s + 1) * 3 + 1];
|
|
3228
|
+
const nz2 = _rawPoints[(s + 1) * 3 + 2];
|
|
3229
|
+
const atx = nx2 - px2;
|
|
3230
|
+
const aty = ny2 - py2;
|
|
3231
|
+
const atz = nz2 - pz2;
|
|
3232
|
+
const atLen = Math.sqrt(atx * atx + aty * aty + atz * atz);
|
|
3233
|
+
if (atLen > 1e-4) {
|
|
3234
|
+
nx = ptx + atx / atLen;
|
|
3235
|
+
ny = pty + aty / atLen;
|
|
3236
|
+
nz = ptz + atz / atLen;
|
|
3237
|
+
} else {
|
|
3238
|
+
nx = _rawPoints[(s + 1) * 3];
|
|
3239
|
+
ny = _rawPoints[(s + 1) * 3 + 1];
|
|
3240
|
+
nz = _rawPoints[(s + 1) * 3 + 2];
|
|
3241
|
+
}
|
|
3242
|
+
} else if (s < filledCount - 1) {
|
|
3243
|
+
nx = _rawPoints[(s + 1) * 3];
|
|
3244
|
+
ny = _rawPoints[(s + 1) * 3 + 1];
|
|
3245
|
+
nz = _rawPoints[(s + 1) * 3 + 2];
|
|
3246
|
+
} else {
|
|
3247
|
+
nx = ptx;
|
|
3248
|
+
ny = pty + 1e-3;
|
|
3249
|
+
nz = ptz;
|
|
3250
|
+
}
|
|
3251
|
+
const t = filledCount > 1 ? s / (filledCount - 1) : 0;
|
|
3252
|
+
const widthScale = trailWidthCurveFn(t);
|
|
3253
|
+
const opacityScale = trailOpacityCurveFn(t);
|
|
3254
|
+
const halfWidth = trailConfig.width * widthScale * 0.5;
|
|
3255
|
+
const alpha = leaderCa * opacityScale;
|
|
3256
|
+
const fr = trailColorOverTrailFns ? leaderCr * trailColorOverTrailFns.r(t) : leaderCr;
|
|
3257
|
+
const fg = trailColorOverTrailFns ? leaderCg * trailColorOverTrailFns.g(t) : leaderCg;
|
|
3258
|
+
const fb = trailColorOverTrailFns ? leaderCb * trailColorOverTrailFns.b(t) : leaderCb;
|
|
3259
|
+
writeTrailVertex(
|
|
3260
|
+
vIdx,
|
|
3261
|
+
cIdx,
|
|
3262
|
+
aIdx,
|
|
3263
|
+
uvIdxBase,
|
|
3264
|
+
ptx,
|
|
3265
|
+
pty,
|
|
3266
|
+
ptz,
|
|
3267
|
+
nx,
|
|
3268
|
+
ny,
|
|
3269
|
+
nz,
|
|
3270
|
+
halfWidth,
|
|
3271
|
+
t,
|
|
3272
|
+
alpha,
|
|
3273
|
+
fr,
|
|
3274
|
+
fg,
|
|
3275
|
+
fb,
|
|
3276
|
+
leaderCa,
|
|
3277
|
+
trailPosArr,
|
|
3278
|
+
trailNextArr,
|
|
3279
|
+
trailHalfWidthArr,
|
|
3280
|
+
trailUVArr,
|
|
3281
|
+
trailAlphaArr,
|
|
3282
|
+
trailColorArr
|
|
3283
|
+
);
|
|
3284
|
+
}
|
|
3285
|
+
for (let ri = 1; ri < _ribbonCount; ri++) {
|
|
3286
|
+
const pIdx = _ribbonIndices[ri];
|
|
3287
|
+
const pVertBase = pIdx * verticesPerParticle;
|
|
3288
|
+
for (let s = 0; s < trailLength; s++) {
|
|
3289
|
+
const vIdx = (pVertBase + s * 2) * 3;
|
|
3290
|
+
const cIdx = (pVertBase + s * 2) * 4;
|
|
3291
|
+
const aIdx = pVertBase + s * 2;
|
|
3292
|
+
const uvIdxBase = (pVertBase + s * 2) * 2;
|
|
3293
|
+
clearTrailVertex(
|
|
3294
|
+
vIdx,
|
|
3295
|
+
cIdx,
|
|
3296
|
+
aIdx,
|
|
3297
|
+
uvIdxBase,
|
|
3298
|
+
trailPosArr,
|
|
3299
|
+
trailNextArr,
|
|
3300
|
+
trailHalfWidthArr,
|
|
3301
|
+
trailUVArr,
|
|
3302
|
+
trailAlphaArr,
|
|
3303
|
+
trailColorArr,
|
|
3304
|
+
0,
|
|
3305
|
+
0,
|
|
3306
|
+
0
|
|
3307
|
+
);
|
|
2672
3308
|
}
|
|
2673
3309
|
}
|
|
2674
3310
|
}
|