sparcoon 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/emitter/FXEmitter.Internal.d.ts +4 -0
  2. package/dist/emitter/FXEmitter.Internal.js +20 -1
  3. package/dist/emitter/FXEmitter.d.ts +4 -4
  4. package/dist/emitter/FXEmitter.js +1 -2
  5. package/dist/emitter/behavior/{FXBehaviorModule.d.ts → FXBehavior.d.ts} +1 -1
  6. package/dist/emitter/behavior/{FXBehaviorModule.js → FXBehavior.js} +2 -2
  7. package/dist/emitter/behavior/FXBehaviorDirectionalGravity.d.ts +3 -3
  8. package/dist/emitter/behavior/FXBehaviorDirectionalGravity.js +2 -2
  9. package/dist/emitter/behavior/FXBehaviorPointGravity.d.ts +2 -2
  10. package/dist/emitter/behavior/FXBehaviorPointGravity.js +2 -2
  11. package/dist/emitter/behavior/FXBehaviorScaleOverLife.d.ts +3 -3
  12. package/dist/emitter/behavior/FXBehaviorScaleOverLife.js +2 -2
  13. package/dist/emitter/behavior/FXBehaviorTorqueDamping.d.ts +3 -3
  14. package/dist/emitter/behavior/FXBehaviorTorqueDamping.js +2 -2
  15. package/dist/emitter/behavior/FXBehaviorTorqueNoise.d.ts +2 -2
  16. package/dist/emitter/behavior/FXBehaviorTorqueNoise.js +2 -2
  17. package/dist/emitter/behavior/FXBehaviorVelocityDamping.d.ts +3 -3
  18. package/dist/emitter/behavior/FXBehaviorVelocityDamping.js +2 -2
  19. package/dist/emitter/behavior/FXBehaviorVelocityNoise.d.ts +2 -2
  20. package/dist/emitter/behavior/FXBehaviorVelocityNoise.js +2 -2
  21. package/dist/emitter/spawn/{FXSpawnModule.d.ts → FXSpawn.d.ts} +1 -1
  22. package/dist/emitter/spawn/{FXSpawnModule.js → FXSpawn.js} +2 -2
  23. package/dist/emitter/spawn/FXSpawnBox.d.ts +3 -3
  24. package/dist/emitter/spawn/FXSpawnBox.js +2 -2
  25. package/dist/emitter/spawn/{FXSpawnOffset.d.ts → FXSpawnPoint.d.ts} +3 -3
  26. package/dist/emitter/spawn/{FXSpawnOffset.js → FXSpawnPoint.js} +3 -3
  27. package/dist/emitter/spawn/FXSpawnRandomLifetime.d.ts +3 -3
  28. package/dist/emitter/spawn/FXSpawnRandomLifetime.js +2 -2
  29. package/dist/emitter/spawn/FXSpawnRandomRotation.d.ts +3 -3
  30. package/dist/emitter/spawn/FXSpawnRandomRotation.js +2 -2
  31. package/dist/emitter/spawn/FXSpawnRandomScale.d.ts +3 -3
  32. package/dist/emitter/spawn/FXSpawnRandomScale.js +2 -2
  33. package/dist/emitter/spawn/FXSpawnRandomTorque.d.ts +3 -3
  34. package/dist/emitter/spawn/FXSpawnRandomTorque.js +2 -2
  35. package/dist/emitter/spawn/FXSpawnRandomVelocity.d.ts +3 -3
  36. package/dist/emitter/spawn/FXSpawnRandomVelocity.js +2 -2
  37. package/dist/emitter/spawn/FXSpawnSphere.d.ts +2 -2
  38. package/dist/emitter/spawn/FXSpawnSphere.js +2 -2
  39. package/dist/index.d.ts +11 -7
  40. package/dist/index.js +10 -7
  41. package/dist/instancedParticle/FXInstancedParticle.Internal.d.ts +0 -4
  42. package/dist/instancedParticle/FXInstancedParticle.Internal.js +1 -19
  43. package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.Internal.d.ts +6 -8
  44. package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.Internal.js +84 -40
  45. package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.d.ts +11 -11
  46. package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.js +16 -8
  47. package/dist/materials/{FXMaterial.Internal.d.ts → FXMaterial/FXMaterial.Internal.d.ts} +3 -2
  48. package/dist/materials/{FXMaterial.Internal.js → FXMaterial/FXMaterial.Internal.js} +3 -3
  49. package/dist/materials/{FXMaterial.d.ts → FXMaterial/FXMaterial.d.ts} +7 -2
  50. package/dist/materials/FXMaterial/FXMaterial.js +25 -0
  51. package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.Internal.d.ts +5 -3
  52. package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.Internal.js +35 -20
  53. package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.d.ts +4 -9
  54. package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.js +2 -5
  55. package/dist/miscellaneous/miscellaneous.d.ts +1 -0
  56. package/dist/miscellaneous/miscellaneous.js +24 -1
  57. package/dist/{materials/color-nodes → nodes/color}/FXColorOverLifeNode.d.ts +0 -1
  58. package/dist/nodes/color/FXColorOverLifeNode.js +44 -0
  59. package/dist/nodes/normal/FXFlatNormalNode.d.ts +4 -0
  60. package/dist/nodes/normal/FXFlatNormalNode.js +14 -0
  61. package/dist/nodes/normal/FXNormalNode.d.ts +3 -0
  62. package/dist/nodes/normal/FXNormalNode.js +4 -0
  63. package/dist/nodes/normal/FXSphericalNormalNode.d.ts +4 -0
  64. package/dist/nodes/normal/FXSphericalNormalNode.js +19 -0
  65. package/dist/nodes/texture/FXAnimatedTextureNode.d.ts +12 -0
  66. package/dist/nodes/texture/FXAnimatedTextureNode.js +88 -0
  67. package/dist/nodes/texture/FXStaticTextureNode.d.ts +6 -0
  68. package/dist/nodes/texture/FXStaticTextureNode.js +34 -0
  69. package/dist/nodes/texture/FXTextureNode.d.ts +3 -0
  70. package/dist/nodes/texture/FXTextureNode.js +8 -0
  71. package/package.json +1 -1
  72. package/dist/materials/FXMaterial.js +0 -21
  73. package/dist/materials/color-nodes/FXAnimatedTextureNode.d.ts +0 -10
  74. package/dist/materials/color-nodes/FXAnimatedTextureNode.js +0 -41
  75. package/dist/materials/color-nodes/FXColorOverLifeNode.js +0 -38
  76. package/dist/materials/color-nodes/FXStaticTextureNode.d.ts +0 -5
  77. package/dist/materials/color-nodes/FXStaticTextureNode.js +0 -23
  78. package/dist/materials/miscellaneous.d.ts +0 -1
  79. package/dist/materials/miscellaneous.js +0 -25
  80. /package/dist/{materials/color-nodes → nodes/color}/FXColorNode.d.ts +0 -0
  81. /package/dist/{materials/color-nodes → nodes/color}/FXColorNode.js +0 -0
@@ -1,7 +1,7 @@
1
1
  import { MathUtils } from 'three';
2
2
  import { assertValidNonNegativeNumber, assertValidNumber } from '../../miscellaneous/asserts.js';
3
3
  import { BUILTIN_OFFSET_POSITION_X, BUILTIN_OFFSET_POSITION_Y, BUILTIN_OFFSET_POSITION_Z } from '../../miscellaneous/miscellaneous.js';
4
- import { FXSpawnModule } from './FXSpawnModule.js';
4
+ import { FXSpawn } from './FXSpawn.js';
5
5
 
6
6
  /**
7
7
  * Spawns particles at random positions within a spherical shell.
@@ -11,7 +11,7 @@ import { FXSpawnModule } from './FXSpawnModule.js';
11
11
  * - `Math.PI / 2` - full sphere
12
12
  * - Values in between produce a spherical band/zone
13
13
  */
14
- class FXSpawnSphere extends FXSpawnModule {
14
+ class FXSpawnSphere extends FXSpawn {
15
15
  /**
16
16
  * @param innerRadius - Minimum spawn radius (0 = spawn from center)
17
17
  * @param outerRadius - Maximum spawn radius
package/dist/index.d.ts CHANGED
@@ -7,18 +7,22 @@ export { FXBehaviorVelocityDamping } from "./emitter/behavior/FXBehaviorVelocity
7
7
  export { FXBehaviorVelocityNoise } from "./emitter/behavior/FXBehaviorVelocityNoise";
8
8
  export { FXEmitter } from "./emitter/FXEmitter";
9
9
  export { FXSpawnBox } from "./emitter/spawn/FXSpawnBox";
10
- export { FXSpawnOffset } from "./emitter/spawn/FXSpawnOffset";
10
+ export { FXSpawnPoint as FXSpawnOffset } from "./emitter/spawn/FXSpawnPoint";
11
11
  export { FXSpawnRandomLifetime } from "./emitter/spawn/FXSpawnRandomLifetime";
12
12
  export { FXSpawnRandomRotation } from "./emitter/spawn/FXSpawnRandomRotation";
13
13
  export { FXSpawnRandomScale } from "./emitter/spawn/FXSpawnRandomScale";
14
14
  export { FXSpawnRandomTorque } from "./emitter/spawn/FXSpawnRandomTorque";
15
15
  export { FXSpawnRandomVelocity } from "./emitter/spawn/FXSpawnRandomVelocity";
16
16
  export { FXSpawnSphere } from "./emitter/spawn/FXSpawnSphere";
17
- export { FXAnimatedTextureNode } from "./materials/color-nodes/FXAnimatedTextureNode";
18
- export { FXColorNode } from "./materials/color-nodes/FXColorNode";
19
- export { FXColorOverLifeNode } from "./materials/color-nodes/FXColorOverLifeNode";
20
- export { FXStaticTextureNode } from "./materials/color-nodes/FXStaticTextureNode";
21
- export { FXDiffuseMaterial, FXParticleNormalsMode, } from "./materials/FXDiffuseMaterial/FXDiffuseMaterial";
22
- export { FXMaterial } from "./materials/FXMaterial";
17
+ export { FXDiffuseMaterial } from "./materials/FXDiffuseMaterial/FXDiffuseMaterial";
18
+ export { FXMaterial } from "./materials/FXMaterial/FXMaterial";
23
19
  export { FXUnlitMaterial } from "./materials/FXUnlitMaterial/FXUnlitMaterial";
24
20
  export { FXColor } from "./miscellaneous/color/FXColor";
21
+ export { FXColorNode } from "./nodes/color/FXColorNode";
22
+ export { FXColorOverLifeNode } from "./nodes/color/FXColorOverLifeNode";
23
+ export { FXFlatNormalNode } from "./nodes/normal/FXFlatNormalNode";
24
+ export { FXNormalNode } from "./nodes/normal/FXNormalNode";
25
+ export { FXSphericalNormalNode } from "./nodes/normal/FXSphericalNormalNode";
26
+ export { FXAnimatedTextureNode } from "./nodes/texture/FXAnimatedTextureNode";
27
+ export { FXStaticTextureNode } from "./nodes/texture/FXStaticTextureNode";
28
+ export { FXTextureNode } from "./nodes/texture/FXTextureNode";
package/dist/index.js CHANGED
@@ -7,19 +7,22 @@ export { FXBehaviorVelocityDamping } from './emitter/behavior/FXBehaviorVelocity
7
7
  export { FXBehaviorVelocityNoise } from './emitter/behavior/FXBehaviorVelocityNoise.js';
8
8
  export { FXEmitter } from './emitter/FXEmitter.js';
9
9
  export { FXSpawnBox } from './emitter/spawn/FXSpawnBox.js';
10
- export { FXSpawnOffset } from './emitter/spawn/FXSpawnOffset.js';
10
+ export { FXSpawnPoint as FXSpawnOffset } from './emitter/spawn/FXSpawnPoint.js';
11
11
  export { FXSpawnRandomLifetime } from './emitter/spawn/FXSpawnRandomLifetime.js';
12
12
  export { FXSpawnRandomRotation } from './emitter/spawn/FXSpawnRandomRotation.js';
13
13
  export { FXSpawnRandomScale } from './emitter/spawn/FXSpawnRandomScale.js';
14
14
  export { FXSpawnRandomTorque } from './emitter/spawn/FXSpawnRandomTorque.js';
15
15
  export { FXSpawnRandomVelocity } from './emitter/spawn/FXSpawnRandomVelocity.js';
16
16
  export { FXSpawnSphere } from './emitter/spawn/FXSpawnSphere.js';
17
- export { FXAnimatedTextureNode } from './materials/color-nodes/FXAnimatedTextureNode.js';
18
- export { FXColorNode } from './materials/color-nodes/FXColorNode.js';
19
- export { FXColorOverLifeNode } from './materials/color-nodes/FXColorOverLifeNode.js';
20
- export { FXStaticTextureNode } from './materials/color-nodes/FXStaticTextureNode.js';
21
17
  export { FXDiffuseMaterial } from './materials/FXDiffuseMaterial/FXDiffuseMaterial.js';
22
- export { FXMaterial } from './materials/FXMaterial.js';
18
+ export { FXMaterial } from './materials/FXMaterial/FXMaterial.js';
23
19
  export { FXUnlitMaterial } from './materials/FXUnlitMaterial/FXUnlitMaterial.js';
24
20
  export { FXColor } from './miscellaneous/color/FXColor.js';
25
- export { FXParticleNormalsMode } from './materials/FXDiffuseMaterial/FXDiffuseMaterial.Internal.js';
21
+ export { FXColorNode } from './nodes/color/FXColorNode.js';
22
+ export { FXColorOverLifeNode } from './nodes/color/FXColorOverLifeNode.js';
23
+ export { FXFlatNormalNode } from './nodes/normal/FXFlatNormalNode.js';
24
+ export { FXNormalNode } from './nodes/normal/FXNormalNode.js';
25
+ export { FXSphericalNormalNode } from './nodes/normal/FXSphericalNormalNode.js';
26
+ export { FXAnimatedTextureNode } from './nodes/texture/FXAnimatedTextureNode.js';
27
+ export { FXStaticTextureNode } from './nodes/texture/FXStaticTextureNode.js';
28
+ export { FXTextureNode } from './nodes/texture/FXTextureNode.js';
@@ -1,6 +1,2 @@
1
1
  import { InstancedBufferGeometry } from "three";
2
- import type { FXPropertyName, GLTypeInfo } from "./shared";
3
2
  export declare const INSTANCED_PARTICLE_GEOMETRY: InstancedBufferGeometry;
4
- export declare function collectProperties(keeper: Record<string, GLTypeInfo>, modules: readonly {
5
- requiredProperties?: Record<string, FXPropertyName>;
6
- }[], debugContext: string): void;
@@ -1,5 +1,4 @@
1
1
  import { InstancedBufferGeometry, BufferAttribute, Float32BufferAttribute } from 'three';
2
- import { resolveGLSLTypeInfo } from './shared.js';
3
2
 
4
3
  const INSTANCED_PARTICLE_GEOMETRY = (() => {
5
4
  const geometry = new InstancedBufferGeometry();
@@ -11,22 +10,5 @@ const INSTANCED_PARTICLE_GEOMETRY = (() => {
11
10
  geometry.setAttribute("uv", new Float32BufferAttribute(uvs, 2));
12
11
  return geometry;
13
12
  })();
14
- function collectProperties(keeper, modules, debugContext) {
15
- for (const module of modules) {
16
- if (module.requiredProperties === undefined) {
17
- continue;
18
- }
19
- for (const key in module.requiredProperties) {
20
- const existingTypeInfo = keeper[key];
21
- const newTypeInfo = resolveGLSLTypeInfo(module.requiredProperties[key]);
22
- if (existingTypeInfo === undefined) {
23
- keeper[key] = newTypeInfo;
24
- }
25
- else if (existingTypeInfo.glslTypeName !== newTypeInfo.glslTypeName) {
26
- throw new Error(`${debugContext}: property conflict for "${key}"`);
27
- }
28
- }
29
- }
30
- }
31
13
 
32
- export { INSTANCED_PARTICLE_GEOMETRY, collectProperties };
14
+ export { INSTANCED_PARTICLE_GEOMETRY };
@@ -1,9 +1,7 @@
1
- import { MeshLambertMaterial, type Blending } from "three";
1
+ import type { Blending } from "three";
2
+ import { MeshLambertMaterial } from "three";
2
3
  import type { GLTypeInfo } from "../../instancedParticle/shared";
3
- import type { FXColorNode } from "../color-nodes/FXColorNode";
4
- export declare enum FXParticleNormalsMode {
5
- FLAT = 0,
6
- SPHERICAL = 1,
7
- TOWARDS_LIGHT = 2
8
- }
9
- export declare function buildFXDiffuseMaterial(varyings: Record<string, GLTypeInfo>, blending: Blending, useAlphaHashing: boolean, normalsMode: FXParticleNormalsMode, colorNodes: readonly FXColorNode[]): MeshLambertMaterial;
4
+ import type { FXColorNode } from "../../nodes/color/FXColorNode";
5
+ import type { FXNormalNode } from "../../nodes/normal/FXNormalNode";
6
+ import { FXTextureNode } from "../../nodes/texture/FXTextureNode";
7
+ export declare function buildFXDiffuseMaterial(varyings: Record<string, GLTypeInfo>, blending: Blending, useAlphaHashing: boolean, alphaTest: number, albedoNodes: readonly (FXColorNode | FXTextureNode)[], normalNodes: readonly (FXTextureNode | FXNormalNode)[], emissionNodes: readonly (FXColorNode | FXTextureNode)[]): MeshLambertMaterial;
@@ -1,13 +1,8 @@
1
- import { MeshLambertMaterial, DoubleSide } from 'three';
2
- import { PARTICLE_DEFINES } from '../miscellaneous.js';
1
+ import { MeshLambertMaterial, Color, DoubleSide } from 'three';
2
+ import { PARTICLE_DEFINES } from '../../miscellaneous/miscellaneous.js';
3
+ import { FXTextureNode } from '../../nodes/texture/FXTextureNode.js';
3
4
 
4
- var FXParticleNormalsMode;
5
- (function (FXParticleNormalsMode) {
6
- FXParticleNormalsMode[FXParticleNormalsMode["FLAT"] = 0] = "FLAT";
7
- FXParticleNormalsMode[FXParticleNormalsMode["SPHERICAL"] = 1] = "SPHERICAL";
8
- FXParticleNormalsMode[FXParticleNormalsMode["TOWARDS_LIGHT"] = 2] = "TOWARDS_LIGHT";
9
- })(FXParticleNormalsMode || (FXParticleNormalsMode = {}));
10
- function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, normalsMode, colorNodes) {
5
+ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest, albedoNodes, normalNodes, emissionNodes) {
11
6
  const attributeDeclarations = [];
12
7
  const varyingDeclarations = [];
13
8
  const vertexAssignments = [];
@@ -25,7 +20,8 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, normalsMode
25
20
  blending,
26
21
  side: DoubleSide,
27
22
  forceSinglePass: true,
28
- alphaTest: 1 / 255,
23
+ alphaTest,
24
+ emissive: emissionNodes.length > 0 ? new Color(1, 1, 1) : new Color(0, 0, 0),
29
25
  });
30
26
  material.onBeforeCompile = (shader) => {
31
27
  const vertexPreamble = [
@@ -49,60 +45,108 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, normalsMode
49
45
  "#endif",
50
46
  ].join("\n"))
51
47
  .replace("#include <project_vertex>", `
52
- vec2 p_bp = position.xy;
53
- p_bp.x *= PARTICLE_SCALE_X;
54
- p_bp.y *= PARTICLE_SCALE_Y;
55
- float p_cosR = cos(PARTICLE_ROTATION);
56
- float p_sinR = sin(PARTICLE_ROTATION);
57
- p_bp = vec2(
58
- p_bp.x * p_cosR - p_bp.y * p_sinR,
59
- p_bp.x * p_sinR + p_bp.y * p_cosR
48
+ // Scale and rotate the billboard offset in camera space
49
+ vec2 billboardOffset = position.xy;
50
+ billboardOffset.x *= PARTICLE_SCALE_X;
51
+ billboardOffset.y *= PARTICLE_SCALE_Y;
52
+
53
+ float cosRotation = cos(PARTICLE_ROTATION);
54
+ float sinRotation = sin(PARTICLE_ROTATION);
55
+ billboardOffset = vec2(
56
+ billboardOffset.x * cosRotation - billboardOffset.y * sinRotation,
57
+ billboardOffset.x * sinRotation + billboardOffset.y * cosRotation
60
58
  );
61
- vec3 p_c = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z);
62
- vec4 mvPosition = modelViewMatrix * vec4(p_c, 1.0);
63
- mvPosition.xy += p_bp;
59
+
60
+ // Move particle center to view space, then apply the billboard offset
61
+ vec3 particleCenter = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z);
62
+ vec4 mvPosition = modelViewMatrix * vec4(particleCenter, 1.0);
63
+ mvPosition.xy += billboardOffset;
64
64
  gl_Position = projectionMatrix * mvPosition;
65
65
  `)
66
66
  .replace("#include <worldpos_vertex>", `
67
67
  #if defined(USE_SHADOWMAP) || defined(USE_ENVMAP) || defined(DISTANCE) || (NUM_SPOT_LIGHT_COORDS > 0)
68
- vec3 p_cr = vec3(viewMatrix[0][0], viewMatrix[1][0], viewMatrix[2][0]);
69
- vec3 p_cu = vec3(viewMatrix[0][1], viewMatrix[1][1], viewMatrix[2][1]);
68
+ // Reconstruct world-space position for shadow/environment maps.
69
+ // Camera right and up are the first two rows of the view matrix rotation (transposed).
70
+ vec3 cameraRight = vec3(viewMatrix[0][0], viewMatrix[1][0], viewMatrix[2][0]);
71
+ vec3 cameraUp = vec3(viewMatrix[0][1], viewMatrix[1][1], viewMatrix[2][1]);
70
72
  vec4 worldPosition = vec4(
71
- (modelMatrix * vec4(p_c, 1.0)).xyz + p_cr * p_bp.x + p_cu * p_bp.y,
73
+ (modelMatrix * vec4(particleCenter, 1.0)).xyz + cameraRight * billboardOffset.x + cameraUp * billboardOffset.y,
72
74
  1.0
73
75
  );
74
76
  #endif
75
77
  `);
78
+ const blendReorientedNormalsHelper = normalNodes.length > 1
79
+ ? `
80
+ vec3 blendReorientedNormals(vec3 base, vec3 detail) {
81
+ base += vec3(0.0, 0.0, 1.0);
82
+ detail *= vec3(-1.0, -1.0, 1.0);
83
+ return normalize(base * dot(base, detail) / base.z - detail);
84
+ }
85
+ `
86
+ : "";
87
+ const seenCacheKeys = new Set();
88
+ const uniqueHelpers = (nodes) => nodes
89
+ .filter((n) => {
90
+ if (seenCacheKeys.has(n.cacheKey)) {
91
+ return false;
92
+ }
93
+ seenCacheKeys.add(n.cacheKey);
94
+ return true;
95
+ })
96
+ .map((n) => n.helperFunctions)
97
+ .join("\n");
76
98
  const fragmentPreamble = [
77
99
  PARTICLE_DEFINES,
78
100
  "varying vec2 p_uv;",
79
101
  varyingDeclarations.join("\n"),
80
- colorNodes.flatMap((n) => n.uniformDeclarations).join("\n"),
81
- colorNodes.map((n) => n.helperFunctions).join("\n"),
102
+ albedoNodes.flatMap((n) => n.uniformDeclarations).join("\n"),
103
+ uniqueHelpers(albedoNodes),
104
+ normalNodes.flatMap((n) => n.uniformDeclarations).join("\n"),
105
+ uniqueHelpers(normalNodes),
106
+ blendReorientedNormalsHelper,
107
+ emissionNodes.flatMap((n) => n.uniformDeclarations).join("\n"),
108
+ uniqueHelpers(emissionNodes),
82
109
  ].join("\n");
83
- for (const node of colorNodes) {
110
+ for (const node of albedoNodes) {
84
111
  Object.assign(shader.uniforms, node.uniforms);
85
112
  }
86
- let fragmentShader = shader.fragmentShader;
87
- if (normalsMode === FXParticleNormalsMode.SPHERICAL) {
88
- fragmentShader = fragmentShader.replace("#include <normal_fragment_begin>", `
89
- float faceDirection = gl_FrontFacing ? 1.0 : -1.0;
90
- vec2 p_sn = p_uv * 2.0 - 1.0;
91
- vec3 normal = normalize(vec3(p_sn, sqrt(max(0.0, 1.0 - dot(p_sn, p_sn)))));
92
- `);
113
+ for (const node of normalNodes) {
114
+ Object.assign(shader.uniforms, node.uniforms);
93
115
  }
94
- else if (normalsMode === FXParticleNormalsMode.TOWARDS_LIGHT) {
95
- fragmentShader = fragmentShader.replace("float dotNL = saturate( dot( geometryNormal, directLight.direction ) );", "float dotNL = 1.0;");
116
+ for (const node of emissionNodes) {
117
+ Object.assign(shader.uniforms, node.uniforms);
118
+ }
119
+ let fragmentShader = shader.fragmentShader;
120
+ if (normalNodes.length > 0) {
121
+ const normalExpressions = normalNodes.map((node) => {
122
+ if (node instanceof FXTextureNode) {
123
+ return `normalize(${node.colorExpression}.rgb * 2.0 - 1.0)`;
124
+ }
125
+ return node.normalExpression;
126
+ });
127
+ const blendLines = normalExpressions
128
+ .slice(1)
129
+ .map((expression) => `normal = blendReorientedNormals(normal, ${expression});`);
130
+ const normalCode = [
131
+ "float faceDirection = gl_FrontFacing ? 1.0 : -1.0;",
132
+ `vec3 normal = ${normalExpressions[0]};`,
133
+ ...blendLines,
134
+ ].join("\n");
135
+ fragmentShader = fragmentShader.replace("#include <normal_fragment_begin>", normalCode);
96
136
  }
97
- if (colorNodes.length > 0) {
98
- const combinedExpression = colorNodes.map((n) => n.colorExpression).join(" * ");
137
+ if (albedoNodes.length > 0) {
138
+ const combinedExpression = albedoNodes.map((n) => n.colorExpression).join(" * ");
99
139
  const discardLine = useAlphaHashing ? "" : "if (diffuseColor.a < 0.0035) discard;";
100
140
  fragmentShader = fragmentShader.replace("#include <map_fragment>", `diffuseColor = ${combinedExpression}; ${discardLine}`);
101
141
  }
142
+ if (emissionNodes.length > 0) {
143
+ const combinedExpression = emissionNodes.map((n) => n.colorExpression).join(" * ");
144
+ fragmentShader = fragmentShader.replace("#include <emissivemap_fragment>", `totalEmissiveRadiance = (${combinedExpression}).rgb;`);
145
+ }
102
146
  shader.fragmentShader = fragmentPreamble + "\n" + fragmentShader;
103
147
  };
104
- material.customProgramCacheKey = () => `fx-diffuse-${normalsMode}-${colorNodes.map((n) => n.cacheKey).join("-") || "none"}`;
148
+ material.customProgramCacheKey = () => `fx-diffuse-${albedoNodes.map((n) => n.cacheKey).join("-") || "none"}-${normalNodes.map((n) => n.cacheKey).join("-") || "none"}-${emissionNodes.map((n) => n.cacheKey).join("-") || "none"}`;
105
149
  return material;
106
150
  }
107
151
 
108
- export { FXParticleNormalsMode, buildFXDiffuseMaterial };
152
+ export { buildFXDiffuseMaterial };
@@ -1,15 +1,15 @@
1
- import { type Blending } from "three";
2
- import { FXMaterial, type FXMaterialOptions } from "../FXMaterial";
3
- import { FXParticleNormalsMode } from "./FXDiffuseMaterial.Internal";
4
- export { FXParticleNormalsMode };
1
+ import type { FXColorNode } from "../../nodes/color/FXColorNode";
2
+ import type { FXNormalNode } from "../../nodes/normal/FXNormalNode";
3
+ import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
4
+ import type { FXMaterialOptions } from "../FXMaterial/FXMaterial";
5
+ import { FXMaterial } from "../FXMaterial/FXMaterial";
5
6
  export interface FXDiffuseMaterialOptions extends FXMaterialOptions {
6
- blending: Blending;
7
- useAlphaHashing: boolean;
8
- normalsMode: FXParticleNormalsMode;
7
+ normalNodes?: (FXTextureNode | FXNormalNode)[];
8
+ emissionNodes?: (FXColorNode | FXTextureNode)[];
9
9
  }
10
10
  export declare class FXDiffuseMaterial extends FXMaterial {
11
- private readonly blending;
12
- private readonly useAlphaHashing;
13
- private readonly normalsMode;
14
- constructor(options?: Partial<FXDiffuseMaterialOptions>);
11
+ private readonly normalNodes;
12
+ private readonly emissionNodes;
13
+ constructor(options?: FXDiffuseMaterialOptions);
14
+ destroy(): void;
15
15
  }
@@ -1,18 +1,26 @@
1
- import { NormalBlending } from 'three';
2
- import { FXMaterial } from '../FXMaterial.js';
3
- import { FXParticleNormalsMode, buildFXDiffuseMaterial } from './FXDiffuseMaterial.Internal.js';
1
+ import { FXSphericalNormalNode } from '../../nodes/normal/FXSphericalNormalNode.js';
2
+ import { FXMaterial } from '../FXMaterial/FXMaterial.js';
3
+ import { buildFXDiffuseMaterial } from './FXDiffuseMaterial.Internal.js';
4
4
 
5
5
  class FXDiffuseMaterial extends FXMaterial {
6
6
  constructor(options = {}) {
7
7
  super(options);
8
- this._private_blending = options.blending ?? NormalBlending;
9
- this._private_useAlphaHashing = options.useAlphaHashing ?? false;
10
- this._private_normalsMode = options.normalsMode ?? FXParticleNormalsMode.SPHERICAL;
8
+ this._private_normalNodes = options.normalNodes ?? [new FXSphericalNormalNode()];
9
+ this._private_emissionNodes = options.emissionNodes ?? [];
10
+ }
11
+ destroy() {
12
+ super.destroy();
13
+ for (const node of this._private_normalNodes) {
14
+ node.destroy?.();
15
+ }
16
+ for (const node of this._private_emissionNodes) {
17
+ node.destroy?.();
18
+ }
11
19
  }
12
20
  /** @internal */
13
21
  buildThreeMaterial(varyings) {
14
- return buildFXDiffuseMaterial(varyings, this._private_blending, this._private_useAlphaHashing, this._private_normalsMode, this.colorNodes);
22
+ return buildFXDiffuseMaterial(varyings, this.blending, this.useAlphaHashing, this.alphaTest, this.albedoNodes, this._private_normalNodes, this._private_emissionNodes);
15
23
  }
16
24
  }
17
25
 
18
- export { FXDiffuseMaterial, FXParticleNormalsMode };
26
+ export { FXDiffuseMaterial };
@@ -1,4 +1,5 @@
1
1
  import { MeshDepthMaterial } from "three";
2
- import type { FXColorNode } from "./color-nodes/FXColorNode";
2
+ import type { FXColorNode } from "../../nodes/color/FXColorNode";
3
+ import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
3
4
  export declare const DEPTH_VERTEX_SHADER = "\n #define PARTICLE_POSITION_X a_builtin[0][0]\n #define PARTICLE_POSITION_Y a_builtin[0][1]\n #define PARTICLE_POSITION_Z a_builtin[0][2]\n\n #define PARTICLE_SCALE_X a_builtin[1][2]\n #define PARTICLE_SCALE_Y a_builtin[1][3]\n\n #define PARTICLE_ROTATION a_builtin[2][1]\n\n attribute mat4 a_builtin;\n varying mat4 p_builtin;\n varying vec2 p_uv;\n varying vec2 vHighPrecisionZW;\n varying float v_viewZ;\n #ifdef USE_ALPHAHASH\n varying vec3 vPosition;\n #endif\n\n void main() {\n p_builtin = a_builtin;\n p_uv = uv;\n #ifdef USE_ALPHAHASH\n vPosition = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z) + vec3(position.xy, 0.0);\n #endif\n\n vec2 transformedPosition = position.xy;\n transformedPosition.x *= PARTICLE_SCALE_X;\n transformedPosition.y *= PARTICLE_SCALE_Y;\n\n float cosR = cos(PARTICLE_ROTATION);\n float sinR = sin(PARTICLE_ROTATION);\n transformedPosition = vec2(\n transformedPosition.x * cosR - transformedPosition.y * sinR,\n transformedPosition.x * sinR + transformedPosition.y * cosR\n );\n\n vec3 center = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z);\n vec4 modelViewCenter = modelViewMatrix * vec4(center, 1.0);\n v_viewZ = modelViewCenter.z;\n modelViewCenter.xy += transformedPosition;\n gl_Position = projectionMatrix * modelViewCenter;\n vHighPrecisionZW = gl_Position.zw;\n }\n";
4
- export declare function buildDepthMaterial(colorNodes: readonly FXColorNode[], depthAlphaTest: number, useDepthAlphaHash: boolean, useSphericalDepth: boolean): MeshDepthMaterial;
5
+ export declare function buildDepthMaterial(albedoNodes: readonly (FXColorNode | FXTextureNode)[], depthAlphaTest: number, useDepthAlphaHash: boolean, useSphericalDepth: boolean): MeshDepthMaterial;
@@ -1,5 +1,5 @@
1
1
  import { MeshDepthMaterial, DoubleSide, RGBADepthPacking } from 'three';
2
- import { PARTICLE_DEFINES } from './miscellaneous.js';
2
+ import { PARTICLE_DEFINES } from '../../miscellaneous/miscellaneous.js';
3
3
 
4
4
  const DEPTH_VERTEX_SHADER = `
5
5
  #define PARTICLE_POSITION_X a_builtin[0][0]
@@ -62,8 +62,8 @@ const DEPTH_SPHERICAL_FRAG_COORD_Z = `
62
62
  float fragCoordZ = 0.5 * _ndc_z + 0.5;
63
63
  #endif
64
64
  `;
65
- function buildDepthMaterial(colorNodes, depthAlphaTest, useDepthAlphaHash, useSphericalDepth) {
66
- const depthNodes = colorNodes.filter((n) => n.affectsDepth);
65
+ function buildDepthMaterial(albedoNodes, depthAlphaTest, useDepthAlphaHash, useSphericalDepth) {
66
+ const depthNodes = albedoNodes.filter((n) => n.affectsDepth);
67
67
  const needsFragmentMod = depthNodes.length > 0 || useSphericalDepth;
68
68
  const material = new MeshDepthMaterial({
69
69
  depthPacking: RGBADepthPacking,
@@ -1,6 +1,11 @@
1
- import type { FXColorNode } from "./color-nodes/FXColorNode";
1
+ import type { Blending } from "three";
2
+ import type { FXColorNode } from "../../nodes/color/FXColorNode";
3
+ import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
2
4
  export interface FXMaterialOptions {
3
- colorNodes?: FXColorNode[];
5
+ albedoNodes?: (FXColorNode | FXTextureNode)[];
6
+ blending?: Blending;
7
+ useAlphaHashing?: boolean;
8
+ alphaTest?: number;
4
9
  depthAlphaTest?: number;
5
10
  useDepthAlphaHash?: boolean;
6
11
  useSphericalDepth?: boolean;
@@ -0,0 +1,25 @@
1
+ import { NormalBlending } from 'three';
2
+ import { buildDepthMaterial } from './FXMaterial.Internal.js';
3
+
4
+ class FXMaterial {
5
+ constructor(options = {}) {
6
+ this.albedoNodes = options.albedoNodes ?? [];
7
+ this.blending = options.blending ?? NormalBlending;
8
+ this.useAlphaHashing = options.useAlphaHashing ?? false;
9
+ this.alphaTest = options.alphaTest ?? 1 / 255;
10
+ this._private_depthAlphaTest = options.depthAlphaTest ?? 0.5;
11
+ this._private_useDepthAlphaHash = options.useDepthAlphaHash ?? false;
12
+ this._private_useSphericalDepth = options.useSphericalDepth ?? true;
13
+ }
14
+ destroy() {
15
+ for (const node of this.albedoNodes) {
16
+ node.destroy?.();
17
+ }
18
+ }
19
+ /** @internal */
20
+ buildDepthMaterial() {
21
+ return buildDepthMaterial(this.albedoNodes, this._private_depthAlphaTest, this._private_useDepthAlphaHash, this._private_useSphericalDepth);
22
+ }
23
+ }
24
+
25
+ export { FXMaterial };
@@ -1,4 +1,6 @@
1
- import { MeshBasicMaterial, type Blending } from "three";
1
+ import type { Blending } from "three";
2
+ import { MeshBasicMaterial } from "three";
2
3
  import type { GLTypeInfo } from "../../instancedParticle/shared";
3
- import type { FXColorNode } from "../color-nodes/FXColorNode";
4
- export declare function buildFXUnlitMaterial(varyings: Record<string, GLTypeInfo>, blending: Blending, useAlphaHashing: boolean, colorNodes: readonly FXColorNode[]): MeshBasicMaterial;
4
+ import type { FXColorNode } from "../../nodes/color/FXColorNode";
5
+ import type { FXTextureNode } from "../../nodes/texture/FXTextureNode";
6
+ export declare function buildFXUnlitMaterial(varyings: Record<string, GLTypeInfo>, blending: Blending, useAlphaHashing: boolean, alphaTest: number, albedoNodes: readonly (FXColorNode | FXTextureNode)[]): MeshBasicMaterial;
@@ -1,7 +1,7 @@
1
1
  import { MeshBasicMaterial, DoubleSide } from 'three';
2
- import { PARTICLE_DEFINES } from '../miscellaneous.js';
2
+ import { PARTICLE_DEFINES } from '../../miscellaneous/miscellaneous.js';
3
3
 
4
- function buildFXUnlitMaterial(varyings, blending, useAlphaHashing, colorNodes) {
4
+ function buildFXUnlitMaterial(varyings, blending, useAlphaHashing, alphaTest, albedoNodes) {
5
5
  const attributeDeclarations = [];
6
6
  const varyingDeclarations = [];
7
7
  const vertexAssignments = [];
@@ -19,7 +19,7 @@ function buildFXUnlitMaterial(varyings, blending, useAlphaHashing, colorNodes) {
19
19
  blending,
20
20
  side: DoubleSide,
21
21
  forceSinglePass: true,
22
- alphaTest: 1 / 255,
22
+ alphaTest,
23
23
  });
24
24
  material.onBeforeCompile = (shader) => {
25
25
  const vertexPreamble = [
@@ -41,39 +41,54 @@ function buildFXUnlitMaterial(varyings, blending, useAlphaHashing, colorNodes) {
41
41
  "#endif",
42
42
  ].join("\n"))
43
43
  .replace("#include <project_vertex>", `
44
- vec2 p_bp = position.xy;
45
- p_bp.x *= PARTICLE_SCALE_X;
46
- p_bp.y *= PARTICLE_SCALE_Y;
47
- float p_cosR = cos(PARTICLE_ROTATION);
48
- float p_sinR = sin(PARTICLE_ROTATION);
49
- p_bp = vec2(
50
- p_bp.x * p_cosR - p_bp.y * p_sinR,
51
- p_bp.x * p_sinR + p_bp.y * p_cosR
44
+ // Scale and rotate the billboard offset in camera space
45
+ vec2 billboardOffset = position.xy;
46
+ billboardOffset.x *= PARTICLE_SCALE_X;
47
+ billboardOffset.y *= PARTICLE_SCALE_Y;
48
+
49
+ float cosRotation = cos(PARTICLE_ROTATION);
50
+ float sinRotation = sin(PARTICLE_ROTATION);
51
+ billboardOffset = vec2(
52
+ billboardOffset.x * cosRotation - billboardOffset.y * sinRotation,
53
+ billboardOffset.x * sinRotation + billboardOffset.y * cosRotation
52
54
  );
53
- vec3 p_c = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z);
54
- vec4 mvPosition = modelViewMatrix * vec4(p_c, 1.0);
55
- mvPosition.xy += p_bp;
55
+
56
+ // Move particle center to view space, then apply the billboard offset
57
+ vec3 particleCenter = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z);
58
+ vec4 mvPosition = modelViewMatrix * vec4(particleCenter, 1.0);
59
+ mvPosition.xy += billboardOffset;
56
60
  gl_Position = projectionMatrix * mvPosition;
57
61
  `);
62
+ const seenCacheKeys = new Set();
63
+ const uniqueHelpers = (nodes) => nodes
64
+ .filter((n) => {
65
+ if (seenCacheKeys.has(n.cacheKey)) {
66
+ return false;
67
+ }
68
+ seenCacheKeys.add(n.cacheKey);
69
+ return true;
70
+ })
71
+ .map((n) => n.helperFunctions)
72
+ .join("\n");
58
73
  const fragmentPreamble = [
59
74
  PARTICLE_DEFINES,
60
75
  "varying vec2 p_uv;",
61
76
  varyingDeclarations.join("\n"),
62
- colorNodes.flatMap((n) => n.uniformDeclarations).join("\n"),
63
- colorNodes.map((n) => n.helperFunctions).join("\n"),
77
+ albedoNodes.flatMap((n) => n.uniformDeclarations).join("\n"),
78
+ uniqueHelpers(albedoNodes),
64
79
  ].join("\n");
65
- for (const node of colorNodes) {
80
+ for (const node of albedoNodes) {
66
81
  Object.assign(shader.uniforms, node.uniforms);
67
82
  }
68
83
  let fragmentShader = shader.fragmentShader;
69
- if (colorNodes.length > 0) {
70
- const combinedExpression = colorNodes.map((n) => n.colorExpression).join(" * ");
84
+ if (albedoNodes.length > 0) {
85
+ const combinedExpression = albedoNodes.map((n) => n.colorExpression).join(" * ");
71
86
  const discardLine = useAlphaHashing ? "" : "if (diffuseColor.a < 0.0035) discard;";
72
87
  fragmentShader = fragmentShader.replace("#include <map_fragment>", `diffuseColor = ${combinedExpression}; ${discardLine}`);
73
88
  }
74
89
  shader.fragmentShader = fragmentPreamble + "\n" + fragmentShader;
75
90
  };
76
- material.customProgramCacheKey = () => `fx-unlit-${colorNodes.map((n) => n.cacheKey).join("-") || "none"}`;
91
+ material.customProgramCacheKey = () => `fx-unlit-${albedoNodes.map((n) => n.cacheKey).join("-") || "none"}`;
77
92
  return material;
78
93
  }
79
94
 
@@ -1,11 +1,6 @@
1
- import { type Blending } from "three";
2
- import { FXMaterial, type FXMaterialOptions } from "../FXMaterial";
3
- export interface FXUnlitMaterialOptions extends FXMaterialOptions {
4
- blending: Blending;
5
- useAlphaHashing: boolean;
6
- }
1
+ import type { FXMaterialOptions } from "../FXMaterial/FXMaterial";
2
+ import { FXMaterial } from "../FXMaterial/FXMaterial";
3
+ export type FXUnlitMaterialOptions = FXMaterialOptions;
7
4
  export declare class FXUnlitMaterial extends FXMaterial {
8
- private readonly blending;
9
- private readonly useAlphaHashing;
10
- constructor(options?: Partial<FXUnlitMaterialOptions>);
5
+ constructor(options?: FXUnlitMaterialOptions);
11
6
  }
@@ -1,16 +1,13 @@
1
- import { NormalBlending } from 'three';
2
- import { FXMaterial } from '../FXMaterial.js';
1
+ import { FXMaterial } from '../FXMaterial/FXMaterial.js';
3
2
  import { buildFXUnlitMaterial } from './FXUnlitMaterial.Internal.js';
4
3
 
5
4
  class FXUnlitMaterial extends FXMaterial {
6
5
  constructor(options = {}) {
7
6
  super(options);
8
- this._private_blending = options.blending ?? NormalBlending;
9
- this._private_useAlphaHashing = options.useAlphaHashing ?? false;
10
7
  }
11
8
  /** @internal */
12
9
  buildThreeMaterial(varyings) {
13
- return buildFXUnlitMaterial(varyings, this._private_blending, this._private_useAlphaHashing, this.colorNodes);
10
+ return buildFXUnlitMaterial(varyings, this.blending, this.useAlphaHashing, this.alphaTest, this.albedoNodes);
14
11
  }
15
12
  }
16
13
 
@@ -30,3 +30,4 @@ export declare const BUILTIN_OFFSET_AGE = 12;
30
30
  export declare const BUILTIN_OFFSET_RANDOM_A = 13;
31
31
  export declare const BUILTIN_OFFSET_RANDOM_B = 14;
32
32
  export declare const BUILTIN_OFFSET_RANDOM_C = 15;
33
+ export declare const PARTICLE_DEFINES = "\n #define PARTICLE_POSITION_X p_builtin[0][0]\n #define PARTICLE_POSITION_Y p_builtin[0][1]\n #define PARTICLE_POSITION_Z p_builtin[0][2]\n\n #define PARTICLE_VELOCITY_X p_builtin[0][3]\n #define PARTICLE_VELOCITY_Y p_builtin[1][0]\n #define PARTICLE_VELOCITY_Z p_builtin[1][1]\n\n #define PARTICLE_SCALE_X p_builtin[1][2]\n #define PARTICLE_SCALE_Y p_builtin[1][3]\n #define PARTICLE_SCALE_Z p_builtin[2][0]\n\n #define PARTICLE_ROTATION p_builtin[2][1]\n #define PARTICLE_TORQUE p_builtin[2][2]\n\n #define PARTICLE_LIFETIME p_builtin[2][3]\n #define PARTICLE_AGE p_builtin[3][0]\n\n #define PARTICLE_RANDOM_A p_builtin[3][1]\n #define PARTICLE_RANDOM_B p_builtin[3][2]\n #define PARTICLE_RANDOM_C p_builtin[3][3]\n";
@@ -58,5 +58,28 @@ const BUILTIN_OFFSET_AGE = 12;
58
58
  const BUILTIN_OFFSET_RANDOM_A = 13;
59
59
  const BUILTIN_OFFSET_RANDOM_B = 14;
60
60
  const BUILTIN_OFFSET_RANDOM_C = 15;
61
+ const PARTICLE_DEFINES = `
62
+ #define PARTICLE_POSITION_X p_builtin[0][0]
63
+ #define PARTICLE_POSITION_Y p_builtin[0][1]
64
+ #define PARTICLE_POSITION_Z p_builtin[0][2]
61
65
 
62
- export { BUILTIN_OFFSET_AGE, BUILTIN_OFFSET_LIFETIME, BUILTIN_OFFSET_POSITION_X, BUILTIN_OFFSET_POSITION_Y, BUILTIN_OFFSET_POSITION_Z, BUILTIN_OFFSET_RANDOM_A, BUILTIN_OFFSET_RANDOM_B, BUILTIN_OFFSET_RANDOM_C, BUILTIN_OFFSET_ROTATION, BUILTIN_OFFSET_SCALE_X, BUILTIN_OFFSET_SCALE_Y, BUILTIN_OFFSET_TORQUE, BUILTIN_OFFSET_VELOCITY_X, BUILTIN_OFFSET_VELOCITY_Y, BUILTIN_OFFSET_VELOCITY_Z, buildGradientTexture, resolveAspect, resolveFXRangeConfig, resolveFXVector3Config };
66
+ #define PARTICLE_VELOCITY_X p_builtin[0][3]
67
+ #define PARTICLE_VELOCITY_Y p_builtin[1][0]
68
+ #define PARTICLE_VELOCITY_Z p_builtin[1][1]
69
+
70
+ #define PARTICLE_SCALE_X p_builtin[1][2]
71
+ #define PARTICLE_SCALE_Y p_builtin[1][3]
72
+ #define PARTICLE_SCALE_Z p_builtin[2][0]
73
+
74
+ #define PARTICLE_ROTATION p_builtin[2][1]
75
+ #define PARTICLE_TORQUE p_builtin[2][2]
76
+
77
+ #define PARTICLE_LIFETIME p_builtin[2][3]
78
+ #define PARTICLE_AGE p_builtin[3][0]
79
+
80
+ #define PARTICLE_RANDOM_A p_builtin[3][1]
81
+ #define PARTICLE_RANDOM_B p_builtin[3][2]
82
+ #define PARTICLE_RANDOM_C p_builtin[3][3]
83
+ `;
84
+
85
+ export { BUILTIN_OFFSET_AGE, BUILTIN_OFFSET_LIFETIME, BUILTIN_OFFSET_POSITION_X, BUILTIN_OFFSET_POSITION_Y, BUILTIN_OFFSET_POSITION_Z, BUILTIN_OFFSET_RANDOM_A, BUILTIN_OFFSET_RANDOM_B, BUILTIN_OFFSET_RANDOM_C, BUILTIN_OFFSET_ROTATION, BUILTIN_OFFSET_SCALE_X, BUILTIN_OFFSET_SCALE_Y, BUILTIN_OFFSET_TORQUE, BUILTIN_OFFSET_VELOCITY_X, BUILTIN_OFFSET_VELOCITY_Y, BUILTIN_OFFSET_VELOCITY_Z, PARTICLE_DEFINES, buildGradientTexture, resolveAspect, resolveFXRangeConfig, resolveFXVector3Config };
@@ -1,7 +1,6 @@
1
1
  import type { FXColor } from "../../miscellaneous/color/FXColor";
2
2
  import { FXColorNode } from "./FXColorNode";
3
3
  export declare class FXColorOverLifeNode extends FXColorNode {
4
- private readonly gradientTexture;
5
4
  constructor(colors: FXColor[]);
6
5
  destroy(): void;
7
6
  }