@newkrok/three-particles 2.12.0 → 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 +1 -0
- package/dist/index.d.ts +59 -2
- package/dist/index.js +227 -22
- 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 +37 -1
- package/llms.txt +20 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ Particle system for ThreeJS.
|
|
|
21
21
|
* Serialization support for saving and loading particle system configs.
|
|
22
22
|
* GPU instancing renderer (`RendererType.INSTANCED`) — removes `gl_PointSize` hardware limit, ideal for large particles or high particle counts.
|
|
23
23
|
* Trail / Ribbon renderer (`RendererType.TRAIL`) — continuous ribbon trails behind particles with configurable width, opacity, and color tapering.
|
|
24
|
+
* Mesh particle renderer (`RendererType.MESH`) — render each particle as a 3D mesh (debris, gems, coins) using GPU instancing with full 3D rotation and simple directional lighting.
|
|
24
25
|
* TypeDoc API documentation available.
|
|
25
26
|
|
|
26
27
|
# Live Demo & Examples
|
package/dist/index.d.ts
CHANGED
|
@@ -180,7 +180,23 @@ declare const enum RendererType {
|
|
|
180
180
|
*
|
|
181
181
|
* Configure trail-specific properties via {@link TrailConfig} on the renderer.
|
|
182
182
|
*/
|
|
183
|
-
TRAIL = "TRAIL"
|
|
183
|
+
TRAIL = "TRAIL",
|
|
184
|
+
/**
|
|
185
|
+
* Render each particle as a 3D mesh using GPU instancing (`InstancedBufferGeometry`).
|
|
186
|
+
* Instead of flat billboard sprites, particles are rendered as real 3D geometry
|
|
187
|
+
* (e.g., cubes, spheres, tori, or any custom `THREE.BufferGeometry`).
|
|
188
|
+
*
|
|
189
|
+
* Key differences from billboard renderers:
|
|
190
|
+
* - **3D rotation**: Particles rotate in all three axes (quaternion-based).
|
|
191
|
+
* - **Normals**: Mesh geometry retains normals, enabling basic lighting.
|
|
192
|
+
* - **Arbitrary geometry**: Any `THREE.BufferGeometry` can be used per particle.
|
|
193
|
+
*
|
|
194
|
+
* All existing modifiers (sizeOverLifetime, colorOverLifetime, noise, force fields,
|
|
195
|
+
* sub-emitters) work with mesh particles.
|
|
196
|
+
*
|
|
197
|
+
* Configure mesh-specific properties via {@link MeshConfig} on the renderer.
|
|
198
|
+
*/
|
|
199
|
+
MESH = "MESH"
|
|
184
200
|
}
|
|
185
201
|
/**
|
|
186
202
|
* Defines how force diminishes with distance from a POINT force field center.
|
|
@@ -682,6 +698,31 @@ type TrailConfig = {
|
|
|
682
698
|
b: LifetimeCurve;
|
|
683
699
|
};
|
|
684
700
|
};
|
|
701
|
+
/**
|
|
702
|
+
* Configuration for the mesh particle renderer.
|
|
703
|
+
* Controls which 3D geometry is used when `rendererType` is `RendererType.MESH`.
|
|
704
|
+
*
|
|
705
|
+
* @property geometry - A `THREE.BufferGeometry` to render for each particle.
|
|
706
|
+
* Built-in Three.js primitives like `BoxGeometry`, `SphereGeometry`, `TorusGeometry`
|
|
707
|
+
* all work. The geometry's own normals and UVs are preserved.
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* // Cube mesh particles
|
|
712
|
+
* mesh: {
|
|
713
|
+
* geometry: new THREE.BoxGeometry(1, 1, 1),
|
|
714
|
+
* }
|
|
715
|
+
*
|
|
716
|
+
* // Icosahedron mesh particles
|
|
717
|
+
* mesh: {
|
|
718
|
+
* geometry: new THREE.IcosahedronGeometry(0.5, 0),
|
|
719
|
+
* }
|
|
720
|
+
* ```
|
|
721
|
+
*/
|
|
722
|
+
type MeshConfig = {
|
|
723
|
+
/** The geometry to render for each particle. */
|
|
724
|
+
geometry: THREE.BufferGeometry;
|
|
725
|
+
};
|
|
685
726
|
/**
|
|
686
727
|
* Configuration for the particle system renderer, controlling blending, transparency, depth, and background color behavior.
|
|
687
728
|
*
|
|
@@ -742,6 +783,13 @@ type Renderer = {
|
|
|
742
783
|
* @see TrailConfig
|
|
743
784
|
*/
|
|
744
785
|
trail?: TrailConfig;
|
|
786
|
+
/**
|
|
787
|
+
* Mesh particle renderer configuration.
|
|
788
|
+
* Only used when `rendererType` is `RendererType.MESH`.
|
|
789
|
+
*
|
|
790
|
+
* @see MeshConfig
|
|
791
|
+
*/
|
|
792
|
+
mesh?: MeshConfig;
|
|
745
793
|
};
|
|
746
794
|
/**
|
|
747
795
|
* Configuration for noise effects applied to particles in a particle system.
|
|
@@ -1585,6 +1633,8 @@ type MappedAttributes = {
|
|
|
1585
1633
|
colorG: AnyBufferAttribute;
|
|
1586
1634
|
colorB: AnyBufferAttribute;
|
|
1587
1635
|
colorA: AnyBufferAttribute;
|
|
1636
|
+
/** Packed quaternion vec4 for 3D mesh rotation (only present for RendererType.MESH). */
|
|
1637
|
+
quat?: AnyBufferAttribute;
|
|
1588
1638
|
};
|
|
1589
1639
|
type ParticleSystemInstance = {
|
|
1590
1640
|
particleSystem: THREE.Points | THREE.Mesh;
|
|
@@ -2028,6 +2078,13 @@ declare const calculateRandomPositionAndVelocityOnRectangle: (position: THREE.Ve
|
|
|
2028
2078
|
rotation: Point3D;
|
|
2029
2079
|
scale: Point3D;
|
|
2030
2080
|
}) => void;
|
|
2081
|
+
/**
|
|
2082
|
+
* Creates a solid white 1x1 texture for mesh particles.
|
|
2083
|
+
* Unlike the circle texture used by point/billboard renderers, mesh particles
|
|
2084
|
+
* need a neutral texture so the geometry shape is visible.
|
|
2085
|
+
* @returns {THREE.CanvasTexture | null} The generated texture or null if context fails.
|
|
2086
|
+
*/
|
|
2087
|
+
declare const createDefaultMeshTexture: () => THREE.CanvasTexture | null;
|
|
2031
2088
|
/**
|
|
2032
2089
|
* Creates a default white circle texture using CanvasTexture.
|
|
2033
2090
|
* @returns {THREE.CanvasTexture | null} The generated texture or null if context fails.
|
|
@@ -2142,4 +2199,4 @@ declare const getDefaultParticleSystemConfig: () => any;
|
|
|
2142
2199
|
declare const createParticleSystem: (config?: ParticleSystemConfig, externalNow?: number) => ParticleSystem;
|
|
2143
2200
|
declare const updateParticleSystems: (cycleData: CycleData) => void;
|
|
2144
2201
|
|
|
2145
|
-
export { type BezierCurve, type BezierPoint, type Box, type Burst, type BurstState, type Circle, type Cone, type Constant, type CurveBase, type CurveFunction, CurveFunctionId, type CycleData, type EasingCurve, type Emission, EmitFrom, type ForceFieldConfig, ForceFieldFalloff, ForceFieldType, type GeneralData, LifeTimeCurve, type LifetimeCurve, type MappedAttributes, type MinMaxColor, type Noise, type NoiseConfig, type NormalizedForceFieldConfig, type NormalizedParticleSystemConfig, type ParticleSystem, type ParticleSystemConfig, type ParticleSystemInstance, type Point3D, type RandomBetweenTwoConstants, type Rectangle, type Renderer, RendererType, type Rgb, Shape, type ShapeConfig, SimulationSpace, type Sphere, type SubEmitterConfig, SubEmitterTrigger, type TextureSheetAnimation, TimeMode, type TrailConfig, type Transform, type VelocityOverLifetime, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
|
|
2202
|
+
export { type BezierCurve, type BezierPoint, type Box, type Burst, type BurstState, type Circle, type Cone, type Constant, type CurveBase, type CurveFunction, CurveFunctionId, type CycleData, type EasingCurve, type Emission, EmitFrom, type ForceFieldConfig, ForceFieldFalloff, ForceFieldType, type GeneralData, LifeTimeCurve, type LifetimeCurve, type MappedAttributes, type MeshConfig, type MinMaxColor, type Noise, type NoiseConfig, type NormalizedForceFieldConfig, type NormalizedParticleSystemConfig, type ParticleSystem, type ParticleSystemConfig, type ParticleSystemInstance, type Point3D, type RandomBetweenTwoConstants, type Rectangle, type Renderer, RendererType, type Rgb, Shape, type ShapeConfig, SimulationSpace, type Sphere, type SubEmitterConfig, SubEmitterTrigger, type TextureSheetAnimation, TimeMode, type TrailConfig, type Transform, type VelocityOverLifetime, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultMeshTexture, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
|
package/dist/index.js
CHANGED
|
@@ -174,6 +174,7 @@ var RendererType = /* @__PURE__ */ ((RendererType2) => {
|
|
|
174
174
|
RendererType2["POINTS"] = "POINTS";
|
|
175
175
|
RendererType2["INSTANCED"] = "INSTANCED";
|
|
176
176
|
RendererType2["TRAIL"] = "TRAIL";
|
|
177
|
+
RendererType2["MESH"] = "MESH";
|
|
177
178
|
return RendererType2;
|
|
178
179
|
})(RendererType || {});
|
|
179
180
|
var ForceFieldFalloff = /* @__PURE__ */ ((ForceFieldFalloff2) => {
|
|
@@ -310,6 +311,24 @@ var calculateRandomPositionAndVelocityOnRectangle = (position, quaternion, veloc
|
|
|
310
311
|
velocity.set(0, 0, speed);
|
|
311
312
|
velocity.applyQuaternion(quaternion);
|
|
312
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
|
+
};
|
|
313
332
|
var createDefaultParticleTexture = () => {
|
|
314
333
|
try {
|
|
315
334
|
const canvas = document.createElement("canvas");
|
|
@@ -494,6 +513,16 @@ var applyModifiers = ({
|
|
|
494
513
|
positionArr[positionIndex + 2] += noiseOnPosition * noisePower * positionAmount;
|
|
495
514
|
attributes.position.needsUpdate = true;
|
|
496
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
|
+
}
|
|
497
526
|
};
|
|
498
527
|
|
|
499
528
|
// src/js/effects/three-particles/shaders/instanced-particle-fragment-shader.glsl.ts
|
|
@@ -630,6 +659,129 @@ var InstancedParticleVertexShader = `
|
|
|
630
659
|
`;
|
|
631
660
|
var instanced_particle_vertex_shader_glsl_default = InstancedParticleVertexShader;
|
|
632
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
|
+
|
|
633
785
|
// src/js/effects/three-particles/shaders/particle-system-fragment-shader.glsl.ts
|
|
634
786
|
var ParticleSystemFragmentShader = `
|
|
635
787
|
uniform sampler2D map;
|
|
@@ -1239,7 +1391,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1239
1391
|
config,
|
|
1240
1392
|
{ applyToFirstObject: false, skippedProperties: [] }
|
|
1241
1393
|
);
|
|
1242
|
-
let particleMap = normalizedConfig.map || createDefaultParticleTexture();
|
|
1394
|
+
let particleMap = normalizedConfig.map || (normalizedConfig.renderer.rendererType === "MESH" /* MESH */ ? createDefaultMeshTexture() : createDefaultParticleTexture());
|
|
1243
1395
|
const {
|
|
1244
1396
|
transform,
|
|
1245
1397
|
duration,
|
|
@@ -1424,7 +1576,9 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1424
1576
|
}));
|
|
1425
1577
|
}
|
|
1426
1578
|
const useTrail = renderer.rendererType === "TRAIL" /* TRAIL */;
|
|
1427
|
-
const
|
|
1579
|
+
const useMesh = renderer.rendererType === "MESH" /* MESH */;
|
|
1580
|
+
const useInstancing = !useTrail && !useMesh && renderer.rendererType === "INSTANCED" /* INSTANCED */;
|
|
1581
|
+
const useInstancedAttributes = useInstancing || useMesh;
|
|
1428
1582
|
const defaultTrailCurve = {
|
|
1429
1583
|
type: "BEZIER" /* BEZIER */,
|
|
1430
1584
|
scale: 1,
|
|
@@ -1455,8 +1609,8 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1455
1609
|
generalData.positionHistoryIndex = new Uint16Array(maxParticles);
|
|
1456
1610
|
generalData.positionHistoryCount = new Uint16Array(maxParticles);
|
|
1457
1611
|
}
|
|
1458
|
-
const attr = (name) =>
|
|
1459
|
-
const posAttr =
|
|
1612
|
+
const attr = (name) => useInstancedAttributes ? `instance${name.charAt(0).toUpperCase()}${name.slice(1)}` : name;
|
|
1613
|
+
const posAttr = useInstancedAttributes ? "instanceOffset" : "position";
|
|
1460
1614
|
const sharedUniforms = {
|
|
1461
1615
|
elapsed: { value: 0 },
|
|
1462
1616
|
map: { value: particleMap },
|
|
@@ -1470,17 +1624,46 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1470
1624
|
backgroundColorTolerance: { value: renderer.backgroundColorTolerance },
|
|
1471
1625
|
...useInstancing ? { viewportHeight: { value: 1 } } : {}
|
|
1472
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
|
+
};
|
|
1473
1637
|
const material = new THREE4.ShaderMaterial({
|
|
1474
1638
|
uniforms: sharedUniforms,
|
|
1475
|
-
vertexShader:
|
|
1476
|
-
fragmentShader:
|
|
1639
|
+
vertexShader: getVertexShader(),
|
|
1640
|
+
fragmentShader: getFragmentShader(),
|
|
1477
1641
|
transparent: renderer.transparent,
|
|
1478
1642
|
blending: renderer.blending,
|
|
1479
1643
|
depthTest: renderer.depthTest,
|
|
1480
1644
|
depthWrite: renderer.depthWrite
|
|
1481
1645
|
});
|
|
1482
1646
|
let geometry;
|
|
1483
|
-
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) {
|
|
1484
1667
|
const instancedGeometry = new THREE4.InstancedBufferGeometry();
|
|
1485
1668
|
const quadPositions = new Float32Array([
|
|
1486
1669
|
-0.5,
|
|
@@ -1521,28 +1704,28 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1521
1704
|
positionArray[i * 3 + 1] = startPositions[i].y;
|
|
1522
1705
|
positionArray[i * 3 + 2] = startPositions[i].z;
|
|
1523
1706
|
}
|
|
1524
|
-
const positionAttribute =
|
|
1707
|
+
const positionAttribute = useInstancedAttributes ? new THREE4.InstancedBufferAttribute(positionArray, 3) : new THREE4.BufferAttribute(positionArray, 3);
|
|
1525
1708
|
geometry.setAttribute(posAttr, positionAttribute);
|
|
1526
1709
|
createFloat32Attributes({
|
|
1527
1710
|
geometry,
|
|
1528
1711
|
propertyName: attr("isActive"),
|
|
1529
1712
|
maxParticles,
|
|
1530
1713
|
factory: 0,
|
|
1531
|
-
instanced:
|
|
1714
|
+
instanced: useInstancedAttributes
|
|
1532
1715
|
});
|
|
1533
1716
|
createFloat32Attributes({
|
|
1534
1717
|
geometry,
|
|
1535
1718
|
propertyName: attr("lifetime"),
|
|
1536
1719
|
maxParticles,
|
|
1537
1720
|
factory: 0,
|
|
1538
|
-
instanced:
|
|
1721
|
+
instanced: useInstancedAttributes
|
|
1539
1722
|
});
|
|
1540
1723
|
createFloat32Attributes({
|
|
1541
1724
|
geometry,
|
|
1542
1725
|
propertyName: attr("startLifetime"),
|
|
1543
1726
|
maxParticles,
|
|
1544
1727
|
factory: () => calculateValue(generalData.particleSystemId, startLifetime, 0) * 1e3,
|
|
1545
|
-
instanced:
|
|
1728
|
+
instanced: useInstancedAttributes
|
|
1546
1729
|
});
|
|
1547
1730
|
createFloat32Attributes({
|
|
1548
1731
|
geometry,
|
|
@@ -1553,21 +1736,21 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1553
1736
|
textureSheetAnimation.startFrame,
|
|
1554
1737
|
0
|
|
1555
1738
|
) : 0,
|
|
1556
|
-
instanced:
|
|
1739
|
+
instanced: useInstancedAttributes
|
|
1557
1740
|
});
|
|
1558
1741
|
createFloat32Attributes({
|
|
1559
1742
|
geometry,
|
|
1560
1743
|
propertyName: attr("size"),
|
|
1561
1744
|
maxParticles,
|
|
1562
1745
|
factory: (_, index) => generalData.startValues.startSize[index],
|
|
1563
|
-
instanced:
|
|
1746
|
+
instanced: useInstancedAttributes
|
|
1564
1747
|
});
|
|
1565
1748
|
createFloat32Attributes({
|
|
1566
1749
|
geometry,
|
|
1567
1750
|
propertyName: attr("rotation"),
|
|
1568
1751
|
maxParticles,
|
|
1569
1752
|
factory: 0,
|
|
1570
|
-
instanced:
|
|
1753
|
+
instanced: useInstancedAttributes
|
|
1571
1754
|
});
|
|
1572
1755
|
const colorRandomRatio = Math.random();
|
|
1573
1756
|
createFloat32Attributes({
|
|
@@ -1575,29 +1758,39 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1575
1758
|
propertyName: attr("colorR"),
|
|
1576
1759
|
maxParticles,
|
|
1577
1760
|
factory: () => startColor.min.r + colorRandomRatio * (startColor.max.r - startColor.min.r),
|
|
1578
|
-
instanced:
|
|
1761
|
+
instanced: useInstancedAttributes
|
|
1579
1762
|
});
|
|
1580
1763
|
createFloat32Attributes({
|
|
1581
1764
|
geometry,
|
|
1582
1765
|
propertyName: attr("colorG"),
|
|
1583
1766
|
maxParticles,
|
|
1584
1767
|
factory: () => startColor.min.g + colorRandomRatio * (startColor.max.g - startColor.min.g),
|
|
1585
|
-
instanced:
|
|
1768
|
+
instanced: useInstancedAttributes
|
|
1586
1769
|
});
|
|
1587
1770
|
createFloat32Attributes({
|
|
1588
1771
|
geometry,
|
|
1589
1772
|
propertyName: attr("colorB"),
|
|
1590
1773
|
maxParticles,
|
|
1591
1774
|
factory: () => startColor.min.b + colorRandomRatio * (startColor.max.b - startColor.min.b),
|
|
1592
|
-
instanced:
|
|
1775
|
+
instanced: useInstancedAttributes
|
|
1593
1776
|
});
|
|
1594
1777
|
createFloat32Attributes({
|
|
1595
1778
|
geometry,
|
|
1596
1779
|
propertyName: attr("colorA"),
|
|
1597
1780
|
maxParticles,
|
|
1598
1781
|
factory: 0,
|
|
1599
|
-
instanced:
|
|
1782
|
+
instanced: useInstancedAttributes
|
|
1600
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
|
+
}
|
|
1601
1794
|
const a = geometry.attributes;
|
|
1602
1795
|
const aIsActive = a[attr("isActive")];
|
|
1603
1796
|
const aColorR = a[attr("colorR")];
|
|
@@ -1610,6 +1803,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1610
1803
|
const aRotation = a[attr("rotation")];
|
|
1611
1804
|
const aLifetime = a[attr("lifetime")];
|
|
1612
1805
|
const aPosition = a[posAttr];
|
|
1806
|
+
const aQuat = useMesh ? a[attr("quat")] : void 0;
|
|
1613
1807
|
const deactivateParticle = (particleIndex) => {
|
|
1614
1808
|
aIsActive.array[particleIndex] = 0;
|
|
1615
1809
|
aColorA.array[particleIndex] = 0;
|
|
@@ -1671,6 +1865,16 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1671
1865
|
generalData.normalizedLifetimePercentage
|
|
1672
1866
|
);
|
|
1673
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
|
+
}
|
|
1674
1878
|
if (normalizedConfig.rotationOverLifetime.isActive)
|
|
1675
1879
|
generalData.lifetimeValues.rotationOverLifetime[particleIndex] = THREE4.MathUtils.randFloat(
|
|
1676
1880
|
normalizedConfig.rotationOverLifetime.min,
|
|
@@ -1796,7 +2000,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1796
2000
|
},
|
|
1797
2001
|
renderer: {
|
|
1798
2002
|
...subConfig.config.renderer ?? {},
|
|
1799
|
-
rendererType: renderer.rendererType
|
|
2003
|
+
...subConfig.config.renderer?.rendererType ? {} : renderer.rendererType === "MESH" /* MESH */ || renderer.rendererType === "TRAIL" /* TRAIL */ ? {} : { rendererType: renderer.rendererType }
|
|
1800
2004
|
},
|
|
1801
2005
|
...inheritVelocity > 0 ? {
|
|
1802
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
|
|
@@ -1923,7 +2127,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1923
2127
|
};
|
|
1924
2128
|
}
|
|
1925
2129
|
}
|
|
1926
|
-
let particleSystem = useInstancing ? new THREE4.Mesh(geometry, material) : new THREE4.Points(geometry, material);
|
|
2130
|
+
let particleSystem = useInstancing || useMesh ? new THREE4.Mesh(geometry, material) : new THREE4.Points(geometry, material);
|
|
1927
2131
|
if (useInstancing) {
|
|
1928
2132
|
particleSystem.onBeforeRender = (glRenderer) => {
|
|
1929
2133
|
const size = glRenderer.getSize(new THREE4.Vector2());
|
|
@@ -1950,7 +2154,8 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
|
|
|
1950
2154
|
colorR: aColorR,
|
|
1951
2155
|
colorG: aColorG,
|
|
1952
2156
|
colorB: aColorB,
|
|
1953
|
-
colorA: aColorA
|
|
2157
|
+
colorA: aColorA,
|
|
2158
|
+
...useMesh ? { quat: aQuat } : {}
|
|
1954
2159
|
};
|
|
1955
2160
|
const calculatedCreationTime = now + calculateValue(generalData.particleSystemId, startDelay) * 1e3;
|
|
1956
2161
|
let wrapper;
|
|
@@ -2491,6 +2696,6 @@ var updateParticleSystems = (cycleData) => {
|
|
|
2491
2696
|
);
|
|
2492
2697
|
};
|
|
2493
2698
|
|
|
2494
|
-
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 };
|
|
2495
2700
|
//# sourceMappingURL=index.js.map
|
|
2496
2701
|
//# sourceMappingURL=index.js.map
|