sparcoon 0.4.2 → 0.4.4

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/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ export { FXUnlitMaterial } from "./materials/FXUnlitMaterial/FXUnlitMaterial";
20
20
  export { FXColor } from "./miscellaneous/color/FXColor";
21
21
  export { FXColorNode } from "./nodes/color/FXColorNode";
22
22
  export { FXColorOverLifeNode } from "./nodes/color/FXColorOverLifeNode";
23
+ export { FXSphericalClipNode } from "./nodes/color/FXSphericalClipNode";
23
24
  export { FXFlatNormalNode } from "./nodes/normal/FXFlatNormalNode";
24
25
  export { FXNormalNode } from "./nodes/normal/FXNormalNode";
25
26
  export { FXSphericalNormalNode } from "./nodes/normal/FXSphericalNormalNode";
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ export { FXUnlitMaterial } from './materials/FXUnlitMaterial/FXUnlitMaterial.js'
20
20
  export { FXColor } from './miscellaneous/color/FXColor.js';
21
21
  export { FXColorNode } from './nodes/color/FXColorNode.js';
22
22
  export { FXColorOverLifeNode } from './nodes/color/FXColorOverLifeNode.js';
23
+ export { FXSphericalClipNode } from './nodes/color/FXSphericalClipNode.js';
23
24
  export { FXFlatNormalNode } from './nodes/normal/FXFlatNormalNode.js';
24
25
  export { FXNormalNode } from './nodes/normal/FXNormalNode.js';
25
26
  export { FXSphericalNormalNode } from './nodes/normal/FXSphericalNormalNode.js';
@@ -40,6 +40,7 @@ function wrapShadowCalls(source, uniformName) {
40
40
  function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest, premultipliedAlpha, albedoNodes, normalNodes, emissionNodes, scatterUniforms, shadowSensitivity) {
41
41
  const useScatter = scatterUniforms !== undefined;
42
42
  const useShadowSensitivity = shadowSensitivity !== undefined;
43
+ const useNormals = normalNodes.length > 0;
43
44
  const attributeDeclarations = [];
44
45
  const varyingDeclarations = [];
45
46
  const vertexAssignments = [];
@@ -67,7 +68,7 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest,
67
68
  PARTICLE_DEFINES,
68
69
  attributeDeclarations.join("\n"),
69
70
  "varying vec2 p_uv;",
70
- "varying float p_rotation;",
71
+ useNormals ? "varying vec2 p_billboardSinCos;" : "",
71
72
  useScatter ? "varying vec3 v_viewPosition;" : "",
72
73
  varyingDeclarations.join("\n"),
73
74
  ].join("\n");
@@ -79,7 +80,6 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest,
79
80
  .replace("#include <defaultnormal_vertex>", "vec3 transformedNormal = vec3(0.0, 0.0, 1.0);")
80
81
  .replace("#include <begin_vertex>", [
81
82
  "p_uv = uv;",
82
- "p_rotation = PARTICLE_ROTATION;",
83
83
  vertexAssignments.join("\n"),
84
84
  "vec3 transformed = position;",
85
85
  "#ifdef USE_ALPHAHASH",
@@ -98,6 +98,9 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest,
98
98
  " billboardOffset.x * sinRotation + billboardOffset.y * cosRotation",
99
99
  ");",
100
100
  "",
101
+ // Pass the exact sin/cos that rotated the billboard to the fragment shader.
102
+ useNormals ? "p_billboardSinCos = vec2(sinRotation, cosRotation);" : "",
103
+ "",
101
104
  "vec3 particleCenter = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z);",
102
105
  "vec4 mvPosition = modelViewMatrix * vec4(particleCenter, 1.0);",
103
106
  "mvPosition.xy += billboardOffset;",
@@ -155,7 +158,7 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest,
155
158
  const fragmentPreamble = [
156
159
  PARTICLE_DEFINES,
157
160
  "varying vec2 p_uv;",
158
- "varying float p_rotation;",
161
+ useNormals ? "varying vec2 p_billboardSinCos;" : "",
159
162
  varyingDeclarations.join("\n"),
160
163
  albedoNodes.flatMap((n) => n.uniformDeclarations).join("\n"),
161
164
  uniqueHelpers(albedoNodes),
@@ -186,7 +189,7 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest,
186
189
  Object.assign(shader.uniforms, node.uniforms);
187
190
  }
188
191
  let fragmentShader = shader.fragmentShader;
189
- if (normalNodes.length > 0) {
192
+ if (useNormals) {
190
193
  const normalExpressions = normalNodes.map((node) => {
191
194
  if (node instanceof FXTextureNode) {
192
195
  return `normalize(${node.colorExpression}.rgb * 2.0 - 1.0)`;
@@ -200,10 +203,17 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest,
200
203
  "float faceDirection = gl_FrontFacing ? 1.0 : -1.0;",
201
204
  `vec3 normal = ${normalExpressions[0]};`,
202
205
  ...blendLines,
203
- "// Rotate normal xy to match billboard PARTICLE_ROTATION",
204
- "float cosR = cos(p_rotation);",
205
- "float sinR = sin(p_rotation);",
206
- "normal = vec3(normal.x * cosR - normal.y * sinR, normal.x * sinR + normal.y * cosR, normal.z);",
206
+ "",
207
+ "// Rotate tangent-space normal XY into view space to match billboard rotation.",
208
+ "// p_billboardSinCos carries the exact sin/cos that rotated the quad vertices.",
209
+ "float sinR = p_billboardSinCos.x;",
210
+ "float cosR = p_billboardSinCos.y;",
211
+ "normal = vec3(",
212
+ " normal.x * cosR - normal.y * sinR,",
213
+ " normal.x * sinR + normal.y * cosR,",
214
+ " normal.z",
215
+ ");",
216
+ "",
207
217
  "normal *= faceDirection;",
208
218
  ].join("\n");
209
219
  fragmentShader = fragmentShader.replace("#include <normal_fragment_begin>", normalCode);
@@ -252,13 +262,6 @@ function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest,
252
262
  }
253
263
  #endif
254
264
 
255
- // calculateScatter() includes a "* alpha" density factor. Compositing
256
- // will apply another "* alpha" (via blend equation in straight mode,
257
- // or via premultiplied_alpha_fragment + One/OneMinusSrcAlpha blend).
258
- // Without correction, scatter would get alpha² while diffuse lighting
259
- // only gets alpha¹. Dividing diffuseColor.rgb by alpha cancels the
260
- // extra factor, so scatter composites at the same alpha power as
261
- // the rest of outgoingLight.
262
265
  vec3 albedo = diffuseColor.a > 0.001
263
266
  ? diffuseColor.rgb / diffuseColor.a
264
267
  : vec3(0.0);
@@ -0,0 +1,3 @@
1
+ import { FXColorNode } from "./FXColorNode";
2
+ export declare class FXSphericalClipNode extends FXColorNode {
3
+ }
@@ -0,0 +1,25 @@
1
+ import { FXColorNode } from './FXColorNode.js';
2
+
3
+ class FXSphericalClipNode extends FXColorNode {
4
+ constructor() {
5
+ super(...arguments);
6
+ /** @internal */
7
+ this.cacheKey = "spherical-clip";
8
+ /** @internal */
9
+ this.uniformDeclarations = [];
10
+ /** @internal */
11
+ this.uniforms = {};
12
+ /** @internal */
13
+ this.helperFunctions = `
14
+ vec4 applySphericalClip() {
15
+ float dist = distance(p_uv, vec2(0.5, 0.5));
16
+ float alpha = 1.0 - step(0.5, dist);
17
+ return vec4(1.0, 1.0, 1.0, alpha);
18
+ }
19
+ `;
20
+ /** @internal */
21
+ this.colorExpression = "applySphericalClip()";
22
+ }
23
+ }
24
+
25
+ export { FXSphericalClipNode };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparcoon",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "particles",