sparcoon 0.7.3 → 0.9.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.
- package/README.md +124 -76
- package/dist/artifact/FXArtifact.d.ts +120 -0
- package/dist/artifact/FXArtifact.js +1 -0
- package/dist/coreLayout.d.ts +22 -0
- package/dist/coreLayout.js +32 -0
- package/dist/editor/index.d.ts +8 -0
- package/dist/editor/index.js +17 -0
- package/dist/effect/FXEffect.d.ts +77 -0
- package/dist/effect/FXEffect.js +454 -0
- package/dist/effect/FXEffectSampling.Internal.d.ts +24 -0
- package/dist/effect/FXEffectSampling.Internal.js +165 -0
- package/dist/effect/FXEffectSpec.d.ts +115 -0
- package/dist/effect/FXEffectSpec.js +1 -0
- package/dist/emitter/FXEmitter.Internal.d.ts +23 -58
- package/dist/emitter/FXEmitter.Internal.js +13 -29
- package/dist/emitter/FXEmitter.d.ts +54 -46
- package/dist/emitter/FXEmitter.js +357 -186
- package/dist/emitter/FXFromArtifactsOptions.d.ts +13 -0
- package/dist/emitter/FXFromArtifactsOptions.js +1 -0
- package/dist/emitter/FXObjectMotion.Internal.d.ts +33 -0
- package/dist/emitter/FXObjectMotion.Internal.js +87 -0
- package/dist/emitter/FXSimulationHolder.d.ts +1 -0
- package/dist/emitter/FXSimulationHolder.js +43 -0
- package/dist/index.d.ts +11 -39
- package/dist/index.js +13 -36
- package/dist/instancedParticle/FXInstancedParticle.d.ts +1 -22
- package/dist/instancedParticle/FXInstancedParticle.js +145 -85
- package/dist/instancedParticle/glTypeInfo.d.ts +5 -0
- package/dist/instancedParticle/glTypeInfo.js +3 -0
- package/dist/instancedParticle/primitiveGeometry.d.ts +10 -0
- package/dist/instancedParticle/primitiveGeometry.js +30 -0
- package/dist/miscellaneous/asserts.d.ts +1 -18
- package/dist/miscellaneous/asserts.js +21 -28
- package/dist/miscellaneous/fxMath.d.ts +26 -0
- package/dist/miscellaneous/fxMath.js +261 -0
- package/dist/miscellaneous/math.d.ts +2 -7
- package/dist/miscellaneous/math.js +8 -9
- package/dist/miscellaneous/texture/fxDataTexture.d.ts +26 -0
- package/dist/miscellaneous/texture/fxDataTexture.js +20 -0
- package/dist/render/FXArtifactMaterial.Internal.d.ts +16 -0
- package/dist/render/FXArtifactMaterial.Internal.js +944 -0
- package/dist/render/FXArtifactMaterial.d.ts +1 -0
- package/dist/render/FXArtifactMaterial.js +79 -0
- package/dist/render/FXMaterialOptions.d.ts +27 -0
- package/dist/render/FXMaterialOptions.js +5 -0
- package/dist/render/FXMesh.d.ts +47 -0
- package/dist/render/FXMesh.js +99 -0
- package/dist/render/FXMeshMaterial.d.ts +40 -0
- package/dist/render/FXMeshMaterial.js +77 -0
- package/dist/world/FXWorld.d.ts +52 -0
- package/dist/world/FXWorld.js +104 -0
- package/package.json +49 -29
- package/dist/_virtual/2d.js +0 -3
- package/dist/_virtual/3d.js +0 -3
- package/dist/_virtual/4d.js +0 -3
- package/dist/_virtual/mod.js +0 -5
- package/dist/_virtual/mod2.js +0 -3
- package/dist/emitter/behavior/FXBehavior.d.ts +0 -24
- package/dist/emitter/behavior/FXBehavior.js +0 -10
- package/dist/emitter/behavior/FXBehaviorDirectionalForce.d.ts +0 -23
- package/dist/emitter/behavior/FXBehaviorDirectionalForce.js +0 -72
- package/dist/emitter/behavior/FXBehaviorPointForce.d.ts +0 -36
- package/dist/emitter/behavior/FXBehaviorPointForce.js +0 -94
- package/dist/emitter/behavior/FXBehaviorScaleOverLife.d.ts +0 -24
- package/dist/emitter/behavior/FXBehaviorScaleOverLife.js +0 -55
- package/dist/emitter/behavior/FXBehaviorTorqueDamping.d.ts +0 -20
- package/dist/emitter/behavior/FXBehaviorTorqueDamping.js +0 -48
- package/dist/emitter/behavior/FXBehaviorTorqueNoise.d.ts +0 -25
- package/dist/emitter/behavior/FXBehaviorTorqueNoise.js +0 -67
- package/dist/emitter/behavior/FXBehaviorTorqueOverLife.d.ts +0 -19
- package/dist/emitter/behavior/FXBehaviorTorqueOverLife.js +0 -41
- package/dist/emitter/behavior/FXBehaviorVelocityDamping.d.ts +0 -20
- package/dist/emitter/behavior/FXBehaviorVelocityDamping.js +0 -50
- package/dist/emitter/behavior/FXBehaviorVelocityNoise.d.ts +0 -25
- package/dist/emitter/behavior/FXBehaviorVelocityNoise.js +0 -76
- package/dist/emitter/behavior/FXBehaviorVelocityOverLife.d.ts +0 -22
- package/dist/emitter/behavior/FXBehaviorVelocityOverLife.js +0 -55
- package/dist/emitter/spawn/FXSpawn.d.ts +0 -11
- package/dist/emitter/spawn/FXSpawn.js +0 -10
- package/dist/emitter/spawn/FXSpawnBox.d.ts +0 -18
- package/dist/emitter/spawn/FXSpawnBox.js +0 -50
- package/dist/emitter/spawn/FXSpawnLifetime.d.ts +0 -17
- package/dist/emitter/spawn/FXSpawnLifetime.js +0 -44
- package/dist/emitter/spawn/FXSpawnOffset.d.ts +0 -21
- package/dist/emitter/spawn/FXSpawnOffset.js +0 -49
- package/dist/emitter/spawn/FXSpawnPoint.d.ts +0 -18
- package/dist/emitter/spawn/FXSpawnPoint.js +0 -46
- package/dist/emitter/spawn/FXSpawnRotation.d.ts +0 -17
- package/dist/emitter/spawn/FXSpawnRotation.js +0 -42
- package/dist/emitter/spawn/FXSpawnScale.d.ts +0 -22
- package/dist/emitter/spawn/FXSpawnScale.js +0 -56
- package/dist/emitter/spawn/FXSpawnSphere.d.ts +0 -36
- package/dist/emitter/spawn/FXSpawnSphere.js +0 -87
- package/dist/emitter/spawn/FXSpawnTorque.d.ts +0 -17
- package/dist/emitter/spawn/FXSpawnTorque.js +0 -42
- package/dist/emitter/spawn/FXSpawnVelocity.d.ts +0 -29
- package/dist/emitter/spawn/FXSpawnVelocity.js +0 -91
- package/dist/instancedParticle/FXInstancedParticle.Internal.d.ts +0 -2
- package/dist/instancedParticle/shared.d.ts +0 -19
- package/dist/instancedParticle/shared.js +0 -116
- package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.Internal.d.ts +0 -24
- package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.Internal.js +0 -275
- package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.d.ts +0 -75
- package/dist/materials/FXDiffuseMaterial/FXDiffuseMaterial.js +0 -63
- package/dist/materials/FXMaterial/FXBlending.Internal.d.ts +0 -24
- package/dist/materials/FXMaterial/FXBlending.Internal.js +0 -64
- package/dist/materials/FXMaterial/FXDepthMaterial.Internal.d.ts +0 -4
- package/dist/materials/FXMaterial/FXDepthMaterial.Internal.js +0 -144
- package/dist/materials/FXMaterial/FXDistanceMaterial.Internal.d.ts +0 -4
- package/dist/materials/FXMaterial/FXDistanceMaterial.Internal.js +0 -175
- package/dist/materials/FXMaterial/FXMaterial.d.ts +0 -70
- package/dist/materials/FXMaterial/FXMaterial.js +0 -51
- package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.Internal.d.ts +0 -7
- package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.Internal.js +0 -103
- package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.d.ts +0 -7
- package/dist/materials/FXUnlitMaterial/FXUnlitMaterial.js +0 -21
- package/dist/miscellaneous/color/FXColor.Internal.d.ts +0 -7
- package/dist/miscellaneous/color/FXColor.Internal.js +0 -42
- package/dist/miscellaneous/color/FXColor.d.ts +0 -234
- package/dist/miscellaneous/color/FXColor.js +0 -636
- package/dist/miscellaneous/curve/FXCurve1D.Internal.d.ts +0 -20
- package/dist/miscellaneous/curve/FXCurve1D.d.ts +0 -17
- package/dist/miscellaneous/curve/FXCurve1D.js +0 -94
- package/dist/miscellaneous/miscellaneous.d.ts +0 -34
- package/dist/miscellaneous/miscellaneous.js +0 -85
- package/dist/miscellaneous/texture/FXTextureView.Internal.d.ts +0 -49
- package/dist/miscellaneous/texture/FXTextureView.Internal.js +0 -6
- package/dist/miscellaneous/texture/FXTextureView.d.ts +0 -72
- package/dist/miscellaneous/texture/FXTextureView.js +0 -234
- package/dist/miscellaneous/webglCapabilities.d.ts +0 -1
- package/dist/miscellaneous/webglCapabilities.js +0 -45
- package/dist/node_modules/fast-simplex-noise/lib/2d.js +0 -93
- package/dist/node_modules/fast-simplex-noise/lib/3d.js +0 -142
- package/dist/node_modules/fast-simplex-noise/lib/4d.js +0 -196
- package/dist/node_modules/fast-simplex-noise/lib/mod.js +0 -24
- package/dist/nodes/FXNode.d.ts +0 -5
- package/dist/nodes/FXNode.js +0 -10
- package/dist/nodes/blending/FXNodeBlending.d.ts +0 -6
- package/dist/nodes/blending/FXNodeBlending.js +0 -9
- package/dist/nodes/blending/FXNodeLightnessBlendingMask.d.ts +0 -19
- package/dist/nodes/blending/FXNodeLightnessBlendingMask.js +0 -65
- package/dist/nodes/color/FXNodeColor.d.ts +0 -6
- package/dist/nodes/color/FXNodeColor.js +0 -9
- package/dist/nodes/color/FXNodeColorOverLife.d.ts +0 -22
- package/dist/nodes/color/FXNodeColorOverLife.js +0 -64
- package/dist/nodes/color/FXNodeSphericalClip.d.ts +0 -21
- package/dist/nodes/color/FXNodeSphericalClip.js +0 -54
- package/dist/nodes/normal/FXNodeFlatNormal.d.ts +0 -6
- package/dist/nodes/normal/FXNodeFlatNormal.js +0 -16
- package/dist/nodes/normal/FXNodeNormal.d.ts +0 -6
- package/dist/nodes/normal/FXNodeNormal.js +0 -9
- package/dist/nodes/normal/FXNodeSphericalNormal.d.ts +0 -6
- package/dist/nodes/normal/FXNodeSphericalNormal.js +0 -23
- package/dist/nodes/texture/FXNodeAnimatedTexture.d.ts +0 -52
- package/dist/nodes/texture/FXNodeAnimatedTexture.js +0 -151
- package/dist/nodes/texture/FXNodeStaticTexture.d.ts +0 -20
- package/dist/nodes/texture/FXNodeStaticTexture.js +0 -67
- package/dist/nodes/texture/FXNodeTexture.d.ts +0 -6
- package/dist/nodes/texture/FXNodeTexture.js +0 -9
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
import { MeshLambertMaterial, Color, DoubleSide, NormalBlending } from 'three';
|
|
2
|
-
import { PARTICLE_DEFINES } from '../../miscellaneous/miscellaneous.js';
|
|
3
|
-
import { FXNodeColor } from '../../nodes/color/FXNodeColor.js';
|
|
4
|
-
import { CURRENT_EXPRESSION_VALUE_PLACEHOLDER } from '../../nodes/FXNode.js';
|
|
5
|
-
import { FXNodeTexture } from '../../nodes/texture/FXNodeTexture.js';
|
|
6
|
-
import { buildAlbedoAndBlendingCode } from '../FXMaterial/FXBlending.Internal.js';
|
|
7
|
-
import { FXBlending } from '../FXMaterial/FXMaterial.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Wraps every `getShadow(...)` call in the shader source with
|
|
11
|
-
* `mix(1.0, getShadow(...), <uniformName>)` so that a uniform
|
|
12
|
-
* can scale shadow influence from 0 (no shadows) to 1 (full shadows).
|
|
13
|
-
*/
|
|
14
|
-
function wrapShadowCalls(source, uniformName) {
|
|
15
|
-
const target = "getShadow(";
|
|
16
|
-
let result = "";
|
|
17
|
-
let position = 0;
|
|
18
|
-
while (position < source.length) {
|
|
19
|
-
const callStart = source.indexOf(target, position);
|
|
20
|
-
if (callStart === -1) {
|
|
21
|
-
result += source.slice(position);
|
|
22
|
-
break;
|
|
23
|
-
}
|
|
24
|
-
result += source.slice(position, callStart);
|
|
25
|
-
let depth = 0;
|
|
26
|
-
let cursor = callStart + target.length - 1;
|
|
27
|
-
for (; cursor < source.length; cursor++) {
|
|
28
|
-
if (source[cursor] === "(") {
|
|
29
|
-
depth++;
|
|
30
|
-
}
|
|
31
|
-
if (source[cursor] === ")") {
|
|
32
|
-
depth--;
|
|
33
|
-
}
|
|
34
|
-
if (depth === 0) {
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const originalCall = source.slice(callStart, cursor + 1);
|
|
39
|
-
result += `mix(1.0, ${originalCall}, ${uniformName})`;
|
|
40
|
-
position = cursor + 1;
|
|
41
|
-
}
|
|
42
|
-
return result;
|
|
43
|
-
}
|
|
44
|
-
function buildFXDiffuseMaterial(varyings, blending, useAlphaHashing, alphaTest, albedoNodes, normalNodes, emissionNodes, scatterUniforms, shadowSensitivity) {
|
|
45
|
-
const useScatter = scatterUniforms !== undefined;
|
|
46
|
-
const useShadowSensitivity = shadowSensitivity !== undefined;
|
|
47
|
-
const useNormals = normalNodes.length > 0;
|
|
48
|
-
const attributeDeclarations = [];
|
|
49
|
-
const varyingDeclarations = [];
|
|
50
|
-
const vertexAssignments = [];
|
|
51
|
-
for (const name in varyings) {
|
|
52
|
-
const { glslTypeName } = varyings[name];
|
|
53
|
-
attributeDeclarations.push(`attribute ${glslTypeName} a_${name};`);
|
|
54
|
-
varyingDeclarations.push(`varying ${glslTypeName} p_${name};`);
|
|
55
|
-
vertexAssignments.push(`p_${name} = a_${name};`);
|
|
56
|
-
}
|
|
57
|
-
const material = new MeshLambertMaterial({
|
|
58
|
-
name: "FXDiffuseMaterial",
|
|
59
|
-
transparent: !useAlphaHashing,
|
|
60
|
-
depthWrite: useAlphaHashing,
|
|
61
|
-
depthTest: true,
|
|
62
|
-
alphaHash: useAlphaHashing,
|
|
63
|
-
blending: NormalBlending,
|
|
64
|
-
side: DoubleSide,
|
|
65
|
-
forceSinglePass: true,
|
|
66
|
-
alphaTest,
|
|
67
|
-
emissive: emissionNodes.length > 0 ? new Color(1, 1, 1) : new Color(0, 0, 0),
|
|
68
|
-
premultipliedAlpha: true,
|
|
69
|
-
});
|
|
70
|
-
material.onBeforeCompile = (shader) => {
|
|
71
|
-
const vertexPreamble = [
|
|
72
|
-
PARTICLE_DEFINES,
|
|
73
|
-
attributeDeclarations.join("\n"),
|
|
74
|
-
"varying vec2 p_uv;",
|
|
75
|
-
useNormals ? "varying vec2 p_billboardSinCos;" : "",
|
|
76
|
-
useScatter ? "varying vec3 v_viewPosition;" : "",
|
|
77
|
-
varyingDeclarations.join("\n"),
|
|
78
|
-
].join("\n");
|
|
79
|
-
shader.vertexShader =
|
|
80
|
-
vertexPreamble +
|
|
81
|
-
"\n" +
|
|
82
|
-
shader.vertexShader
|
|
83
|
-
.replace("#include <beginnormal_vertex>", "vec3 objectNormal = vec3(0.0, 0.0, 1.0);")
|
|
84
|
-
.replace("#include <defaultnormal_vertex>", "vec3 transformedNormal = vec3(0.0, 0.0, 1.0);")
|
|
85
|
-
.replace("#include <begin_vertex>", [
|
|
86
|
-
"p_uv = uv;",
|
|
87
|
-
vertexAssignments.join("\n"),
|
|
88
|
-
"vec3 transformed = position;",
|
|
89
|
-
"#ifdef USE_ALPHAHASH",
|
|
90
|
-
" vPosition = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z) + vec3(position.xy, 0.0);",
|
|
91
|
-
"#endif",
|
|
92
|
-
].join("\n"))
|
|
93
|
-
.replace("#include <project_vertex>", [
|
|
94
|
-
"vec2 billboardOffset = position.xy;",
|
|
95
|
-
"billboardOffset.x *= PARTICLE_SCALE_X;",
|
|
96
|
-
"billboardOffset.y *= PARTICLE_SCALE_Y;",
|
|
97
|
-
"",
|
|
98
|
-
"float cosRotation = cos(PARTICLE_ROTATION);",
|
|
99
|
-
"float sinRotation = sin(PARTICLE_ROTATION);",
|
|
100
|
-
"billboardOffset = vec2(",
|
|
101
|
-
" billboardOffset.x * cosRotation - billboardOffset.y * sinRotation,",
|
|
102
|
-
" billboardOffset.x * sinRotation + billboardOffset.y * cosRotation",
|
|
103
|
-
");",
|
|
104
|
-
"",
|
|
105
|
-
// Pass the exact sin/cos that rotated the billboard to the fragment shader.
|
|
106
|
-
useNormals ? "p_billboardSinCos = vec2(sinRotation, cosRotation);" : "",
|
|
107
|
-
"",
|
|
108
|
-
"vec3 particleCenter = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z);",
|
|
109
|
-
"vec4 mvPosition = modelViewMatrix * vec4(particleCenter, 1.0);",
|
|
110
|
-
"mvPosition.xy += billboardOffset;",
|
|
111
|
-
useScatter ? "v_viewPosition = mvPosition.xyz;" : "",
|
|
112
|
-
"gl_Position = projectionMatrix * mvPosition;",
|
|
113
|
-
].join("\n"))
|
|
114
|
-
.replace("#include <worldpos_vertex>", `
|
|
115
|
-
#if defined(USE_SHADOWMAP) || defined(USE_ENVMAP) || defined(DISTANCE) || (NUM_SPOT_LIGHT_COORDS > 0)
|
|
116
|
-
vec3 cameraRight = vec3(viewMatrix[0][0], viewMatrix[1][0], viewMatrix[2][0]);
|
|
117
|
-
vec3 cameraUp = vec3(viewMatrix[0][1], viewMatrix[1][1], viewMatrix[2][1]);
|
|
118
|
-
vec4 worldPosition = vec4(
|
|
119
|
-
(modelMatrix * vec4(particleCenter, 1.0)).xyz + cameraRight * billboardOffset.x + cameraUp * billboardOffset.y,
|
|
120
|
-
1.0
|
|
121
|
-
);
|
|
122
|
-
#endif
|
|
123
|
-
`);
|
|
124
|
-
const seenCacheKeys = new Set();
|
|
125
|
-
const uniqueHelpers = (nodes) => nodes
|
|
126
|
-
.filter((node) => {
|
|
127
|
-
if (seenCacheKeys.has(node.cacheKey)) {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
seenCacheKeys.add(node.cacheKey);
|
|
131
|
-
return true;
|
|
132
|
-
})
|
|
133
|
-
.map((node) => node.helperFunctions)
|
|
134
|
-
.join("\n");
|
|
135
|
-
const scatterDeclarations = useScatter
|
|
136
|
-
? [
|
|
137
|
-
"varying vec3 v_viewPosition;",
|
|
138
|
-
"uniform vec3 u_ScatterTint;",
|
|
139
|
-
"uniform float u_ScatterPower;",
|
|
140
|
-
"uniform float u_ForwardScatterStrength;",
|
|
141
|
-
"uniform float u_BackScatterStrength;",
|
|
142
|
-
`vec3 calculateScatter(vec3 viewDirection, vec3 lightDirection, vec3 lightColor, float alpha) {
|
|
143
|
-
float viewDotLight = dot(viewDirection, lightDirection);
|
|
144
|
-
float scatterForward = pow(max(-viewDotLight, 0.0), u_ScatterPower) * u_ForwardScatterStrength;
|
|
145
|
-
float scatterBackward = pow(max( viewDotLight, 0.0), 2.0) * u_BackScatterStrength;
|
|
146
|
-
return lightColor * u_ScatterTint * (scatterForward + scatterBackward) * alpha;
|
|
147
|
-
}`,
|
|
148
|
-
]
|
|
149
|
-
: [];
|
|
150
|
-
const shadowSensitivityDeclarations = useShadowSensitivity
|
|
151
|
-
? ["uniform float u_shadowSensitivity;"]
|
|
152
|
-
: [];
|
|
153
|
-
const fragmentPreamble = [
|
|
154
|
-
PARTICLE_DEFINES,
|
|
155
|
-
"varying vec2 p_uv;",
|
|
156
|
-
useNormals ? "varying vec2 p_billboardSinCos;" : "",
|
|
157
|
-
varyingDeclarations.join("\n"),
|
|
158
|
-
albedoNodes.flatMap((node) => node.uniformDeclarations).join("\n"),
|
|
159
|
-
uniqueHelpers(albedoNodes),
|
|
160
|
-
normalNodes.flatMap((node) => node.uniformDeclarations).join("\n"),
|
|
161
|
-
uniqueHelpers(normalNodes),
|
|
162
|
-
emissionNodes.flatMap((node) => node.uniformDeclarations).join("\n"),
|
|
163
|
-
uniqueHelpers(emissionNodes),
|
|
164
|
-
...scatterDeclarations,
|
|
165
|
-
...shadowSensitivityDeclarations,
|
|
166
|
-
].join("\n");
|
|
167
|
-
if (useScatter) {
|
|
168
|
-
shader.uniforms["u_ScatterTint"] = scatterUniforms.u_ScatterTint;
|
|
169
|
-
shader.uniforms["u_ScatterPower"] = scatterUniforms.u_ScatterPower;
|
|
170
|
-
shader.uniforms["u_ForwardScatterStrength"] = scatterUniforms.u_ForwardScatterStrength;
|
|
171
|
-
shader.uniforms["u_BackScatterStrength"] = scatterUniforms.u_BackScatterStrength;
|
|
172
|
-
}
|
|
173
|
-
if (useShadowSensitivity) {
|
|
174
|
-
shader.uniforms["u_shadowSensitivity"] = shadowSensitivity;
|
|
175
|
-
}
|
|
176
|
-
for (const node of albedoNodes) {
|
|
177
|
-
Object.assign(shader.uniforms, node.uniforms);
|
|
178
|
-
}
|
|
179
|
-
for (const node of normalNodes) {
|
|
180
|
-
Object.assign(shader.uniforms, node.uniforms);
|
|
181
|
-
}
|
|
182
|
-
for (const node of emissionNodes) {
|
|
183
|
-
Object.assign(shader.uniforms, node.uniforms);
|
|
184
|
-
}
|
|
185
|
-
let fragmentShader = shader.fragmentShader;
|
|
186
|
-
if (useNormals) {
|
|
187
|
-
const normalLines = [
|
|
188
|
-
"float faceDirection = gl_FrontFacing ? 1.0 : -1.0;",
|
|
189
|
-
"vec3 fxNormal = vec3(0.0, 0.0, 1.0);",
|
|
190
|
-
];
|
|
191
|
-
for (const node of normalNodes) {
|
|
192
|
-
if (node instanceof FXNodeTexture || node instanceof FXNodeColor) {
|
|
193
|
-
normalLines.push(`fxNormal = normalize((${node.colorExpression.replace(CURRENT_EXPRESSION_VALUE_PLACEHOLDER, "vec4(fxNormal, 1.0)")}).rgb * 2.0 - 1.0);`);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
normalLines.push(`fxNormal = ${node.normalExpression.replace(CURRENT_EXPRESSION_VALUE_PLACEHOLDER, "fxNormal")};`);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
normalLines.push("", "float sinR = p_billboardSinCos.x;", "float cosR = p_billboardSinCos.y;", "vec3 normal = vec3(", " fxNormal.x * cosR - fxNormal.y * sinR,", " fxNormal.x * sinR + fxNormal.y * cosR,", " fxNormal.z", ");", "", "normal *= faceDirection;");
|
|
200
|
-
fragmentShader = fragmentShader.replace("#include <normal_fragment_begin>", normalLines.join("\n"));
|
|
201
|
-
}
|
|
202
|
-
const albedoCode = buildAlbedoAndBlendingCode(albedoNodes, blending, useAlphaHashing);
|
|
203
|
-
if (albedoCode.mapFragment !== null) {
|
|
204
|
-
fragmentShader = fragmentShader.replace("#include <map_fragment>", albedoCode.mapFragment);
|
|
205
|
-
}
|
|
206
|
-
if (emissionNodes.length > 0) {
|
|
207
|
-
const emissiveLines = ["vec4 fxEmissive = vec4(1.0);"];
|
|
208
|
-
for (const node of emissionNodes) {
|
|
209
|
-
emissiveLines.push(`fxEmissive = ${node.colorExpression.replace(CURRENT_EXPRESSION_VALUE_PLACEHOLDER, "fxEmissive")};`);
|
|
210
|
-
}
|
|
211
|
-
emissiveLines.push("totalEmissiveRadiance = fxEmissive.rgb;");
|
|
212
|
-
fragmentShader = fragmentShader.replace("#include <emissivemap_fragment>", emissiveLines.join("\n"));
|
|
213
|
-
}
|
|
214
|
-
if (useScatter) {
|
|
215
|
-
fragmentShader = fragmentShader.replace("#include <opaque_fragment>", `
|
|
216
|
-
#ifdef OPAQUE
|
|
217
|
-
diffuseColor.a = 1.0;
|
|
218
|
-
#endif
|
|
219
|
-
|
|
220
|
-
vec3 viewDirection = normalize(-v_viewPosition);
|
|
221
|
-
vec3 totalScatter = vec3(0.0);
|
|
222
|
-
|
|
223
|
-
#if NUM_DIR_LIGHTS > 0
|
|
224
|
-
for (int i = 0; i < NUM_DIR_LIGHTS; i++) {
|
|
225
|
-
totalScatter += calculateScatter(viewDirection, directionalLights[i].direction, directionalLights[i].color, diffuseColor.a);
|
|
226
|
-
}
|
|
227
|
-
#endif
|
|
228
|
-
|
|
229
|
-
#if NUM_POINT_LIGHTS > 0
|
|
230
|
-
for (int i = 0; i < NUM_POINT_LIGHTS; i++) {
|
|
231
|
-
vec3 toLightDirection = normalize(pointLights[i].position - v_viewPosition);
|
|
232
|
-
float lightDistance = length(pointLights[i].position - v_viewPosition);
|
|
233
|
-
float attenuation = 1.0 / (1.0 + 0.09 * lightDistance + 0.032 * lightDistance * lightDistance);
|
|
234
|
-
totalScatter += calculateScatter(viewDirection, toLightDirection, pointLights[i].color, diffuseColor.a) * attenuation;
|
|
235
|
-
}
|
|
236
|
-
#endif
|
|
237
|
-
|
|
238
|
-
#if NUM_SPOT_LIGHTS > 0
|
|
239
|
-
for (int i = 0; i < NUM_SPOT_LIGHTS; i++) {
|
|
240
|
-
vec3 toLightDirection = normalize(spotLights[i].position - v_viewPosition);
|
|
241
|
-
float lightDistance = length(spotLights[i].position - v_viewPosition);
|
|
242
|
-
float attenuation = 1.0 / (1.0 + 0.09 * lightDistance + 0.032 * lightDistance * lightDistance);
|
|
243
|
-
float spotCosine = dot(normalize(spotLights[i].direction), -toLightDirection);
|
|
244
|
-
float spotFalloff = smoothstep(spotLights[i].coneCos, spotLights[i].penumbraCos, spotCosine);
|
|
245
|
-
totalScatter += calculateScatter(viewDirection, toLightDirection, spotLights[i].color, diffuseColor.a) * attenuation * spotFalloff;
|
|
246
|
-
}
|
|
247
|
-
#endif
|
|
248
|
-
|
|
249
|
-
vec3 albedo = diffuseColor.a > 0.001
|
|
250
|
-
? diffuseColor.rgb / diffuseColor.a
|
|
251
|
-
: vec3(0.0);
|
|
252
|
-
gl_FragColor = vec4(outgoingLight + totalScatter * albedo, diffuseColor.a);
|
|
253
|
-
`);
|
|
254
|
-
}
|
|
255
|
-
if (useShadowSensitivity) {
|
|
256
|
-
fragmentShader = wrapShadowCalls(fragmentShader, "u_shadowSensitivity");
|
|
257
|
-
}
|
|
258
|
-
fragmentShader = fragmentShader.replace("#include <premultiplied_alpha_fragment>", albedoCode.premultChunk);
|
|
259
|
-
shader.fragmentShader = fragmentPreamble + "\n" + fragmentShader;
|
|
260
|
-
};
|
|
261
|
-
const scatterKey = useScatter ? `scatter(${scatterUniforms.u_ScatterPower.value})` : "no-scatter";
|
|
262
|
-
const shadowKey = useShadowSensitivity ? "shadow-sens" : "no-shadow-sens";
|
|
263
|
-
material.customProgramCacheKey = () => [
|
|
264
|
-
"fx",
|
|
265
|
-
albedoNodes.map((node) => node.cacheKey).join("-") || "none",
|
|
266
|
-
normalNodes.map((node) => node.cacheKey).join("-") || "none",
|
|
267
|
-
emissionNodes.map((node) => node.cacheKey).join("-") || "none",
|
|
268
|
-
FXBlending[blending],
|
|
269
|
-
scatterKey,
|
|
270
|
-
shadowKey,
|
|
271
|
-
].join("_");
|
|
272
|
-
return material;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
export { buildFXDiffuseMaterial };
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { ColorRepresentation } from "three";
|
|
2
|
-
import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
|
|
3
|
-
import type { FXNodeNormal } from "../../nodes/normal/FXNodeNormal";
|
|
4
|
-
import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
|
|
5
|
-
import type { FXMaterialOptions } from "../FXMaterial/FXMaterial";
|
|
6
|
-
import { FXMaterial } from "../FXMaterial/FXMaterial";
|
|
7
|
-
/**
|
|
8
|
-
* Configuration options for {@link FXDiffuseMaterial}
|
|
9
|
-
*/
|
|
10
|
-
export interface FXDiffuseMaterialOptions extends FXMaterialOptions {
|
|
11
|
-
/**
|
|
12
|
-
* Normal nodes for lighting; multiple nodes are blended together
|
|
13
|
-
*
|
|
14
|
-
* @defaultValue `[new FXNodeSphericalNormal()]`
|
|
15
|
-
*/
|
|
16
|
-
normalNodes: (FXNodeTexture | FXNodeNormal)[];
|
|
17
|
-
/**
|
|
18
|
-
* Emission color nodes composited for emissive output
|
|
19
|
-
*
|
|
20
|
-
* @defaultValue `[]`
|
|
21
|
-
*/
|
|
22
|
-
emissionNodes: (FXNodeColor | FXNodeTexture)[];
|
|
23
|
-
/**
|
|
24
|
-
* Enable subsurface scattering approximation
|
|
25
|
-
*
|
|
26
|
-
* @defaultValue `false`
|
|
27
|
-
*/
|
|
28
|
-
enableScatter: boolean;
|
|
29
|
-
/**
|
|
30
|
-
* Tint color applied to the scatter contribution
|
|
31
|
-
*
|
|
32
|
-
* @defaultValue `0xffd999`
|
|
33
|
-
*/
|
|
34
|
-
scatterTint: ColorRepresentation;
|
|
35
|
-
/**
|
|
36
|
-
* Scatter lobe sharpness; higher values produce a tighter highlight
|
|
37
|
-
*
|
|
38
|
-
* @defaultValue `10`
|
|
39
|
-
*/
|
|
40
|
-
scatterPower: number;
|
|
41
|
-
/**
|
|
42
|
-
* Forward scatter intensity (light-facing side)
|
|
43
|
-
*
|
|
44
|
-
* @defaultValue `1`
|
|
45
|
-
*/
|
|
46
|
-
forwardScatterStrength: number;
|
|
47
|
-
/**
|
|
48
|
-
* Back scatter intensity (back-lit side)
|
|
49
|
-
*
|
|
50
|
-
* @defaultValue `1`
|
|
51
|
-
*/
|
|
52
|
-
backScatterStrength: number;
|
|
53
|
-
/**
|
|
54
|
-
* Shadow influence (`0` = no shadows, `1` = full shadows)
|
|
55
|
-
*
|
|
56
|
-
* @defaultValue `1`
|
|
57
|
-
*/
|
|
58
|
-
shadowSensitivity: number;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Diffuse particle material with lighting, normals, emission, and optional subsurface scattering
|
|
62
|
-
*/
|
|
63
|
-
export declare class FXDiffuseMaterial extends FXMaterial {
|
|
64
|
-
private readonly normalNodes;
|
|
65
|
-
private readonly emissionNodes;
|
|
66
|
-
private readonly scatterUniforms;
|
|
67
|
-
private readonly shadowSensitivity;
|
|
68
|
-
/**
|
|
69
|
-
* @param options - Material configuration
|
|
70
|
-
*/
|
|
71
|
-
constructor(options?: Partial<FXDiffuseMaterialOptions>);
|
|
72
|
-
/** Releases resources held by all albedo, normal, and emission nodes */
|
|
73
|
-
destroy(): void;
|
|
74
|
-
prepare(): void;
|
|
75
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { FXColor } from '../../miscellaneous/color/FXColor.js';
|
|
2
|
-
import { FXNodeSphericalNormal } from '../../nodes/normal/FXNodeSphericalNormal.js';
|
|
3
|
-
import { FXMaterial } from '../FXMaterial/FXMaterial.js';
|
|
4
|
-
import { buildFXDiffuseMaterial } from './FXDiffuseMaterial.Internal.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Diffuse particle material with lighting, normals, emission, and optional subsurface scattering
|
|
8
|
-
*/
|
|
9
|
-
class FXDiffuseMaterial extends FXMaterial {
|
|
10
|
-
/**
|
|
11
|
-
* @param options - Material configuration
|
|
12
|
-
*/
|
|
13
|
-
constructor(options = {}) {
|
|
14
|
-
super(options);
|
|
15
|
-
this._private_normalNodes = options.normalNodes ?? [new FXNodeSphericalNormal()];
|
|
16
|
-
this._private_emissionNodes = options.emissionNodes ?? [];
|
|
17
|
-
this._private_scatterUniforms =
|
|
18
|
-
options.enableScatter === true
|
|
19
|
-
? {
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
21
|
-
u_ScatterTint: { value: new FXColor(options.scatterTint ?? 0xffd999).toThreeColor() },
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
23
|
-
u_ScatterPower: { value: options.scatterPower ?? 10 },
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
25
|
-
u_ForwardScatterStrength: { value: options.forwardScatterStrength ?? 1 },
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
27
|
-
u_BackScatterStrength: { value: options.backScatterStrength ?? 1 },
|
|
28
|
-
}
|
|
29
|
-
: undefined;
|
|
30
|
-
this._private_shadowSensitivity = { value: options.shadowSensitivity ?? 1 };
|
|
31
|
-
}
|
|
32
|
-
/** Releases resources held by all albedo, normal, and emission nodes */
|
|
33
|
-
destroy() {
|
|
34
|
-
super.destroy();
|
|
35
|
-
for (const node of this._private_normalNodes) {
|
|
36
|
-
node.destroy?.();
|
|
37
|
-
}
|
|
38
|
-
for (const node of this._private_emissionNodes) {
|
|
39
|
-
node.destroy?.();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
/** @internal */
|
|
43
|
-
buildThreeMaterial(varyings) {
|
|
44
|
-
return buildFXDiffuseMaterial(varyings, this.blending, this.useAlphaHashing, this.alphaTest, this.albedoNodes, this._private_normalNodes, this._private_emissionNodes, this._private_scatterUniforms, this._private_shadowSensitivity);
|
|
45
|
-
}
|
|
46
|
-
prepare() {
|
|
47
|
-
let i = 0;
|
|
48
|
-
for (const node of this.albedoNodes) {
|
|
49
|
-
node.prepare?.(i);
|
|
50
|
-
i += 1;
|
|
51
|
-
}
|
|
52
|
-
for (const node of this._private_normalNodes) {
|
|
53
|
-
node.prepare?.(i);
|
|
54
|
-
i += 1;
|
|
55
|
-
}
|
|
56
|
-
for (const node of this._private_emissionNodes) {
|
|
57
|
-
node.prepare?.(i);
|
|
58
|
-
i += 1;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export { FXDiffuseMaterial };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { FXNodeBlending } from "../../nodes/blending/FXNodeBlending";
|
|
2
|
-
import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
|
|
3
|
-
import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
|
|
4
|
-
import { FXBlending } from "./FXMaterial";
|
|
5
|
-
export interface AlbedoBlendingCode {
|
|
6
|
-
/** Replacement for #include <map_fragment>. null means: leave the include as-is */
|
|
7
|
-
mapFragment: string | null;
|
|
8
|
-
/** Replacement for #include <premultiplied_alpha_fragment> */
|
|
9
|
-
premultChunk: string;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Processes albedoNodes in order to produce shader code for both the color assignment
|
|
13
|
-
* and the per-pixel blending mode.
|
|
14
|
-
*
|
|
15
|
-
* Nodes are composed sequentially: each node receives the current accumulated value via
|
|
16
|
-
* EXPRESSION_CURRENT_VALUE_PLACEHOLDER and returns a new value. Nodes that do not use
|
|
17
|
-
* the placeholder act as sources and replace the current value entirely.
|
|
18
|
-
*
|
|
19
|
-
* When a FXNodeBlending appears, it receives both the current mask (via
|
|
20
|
-
* EXPRESSION_CURRENT_VALUE_PLACEHOLDER) and the current color (via
|
|
21
|
-
* EXPRESSION_CURRENT_COLOR_PLACEHOLDER), and returns the new mask value. Color nodes
|
|
22
|
-
* that follow a blending node do not affect the mask.
|
|
23
|
-
*/
|
|
24
|
-
export declare function buildAlbedoAndBlendingCode(albedoNodes: readonly (FXNodeColor | FXNodeTexture | FXNodeBlending)[], blending: FXBlending, useAlphaHashing: boolean): AlbedoBlendingCode;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { CURRENT_EXPRESSION_VALUE_PLACEHOLDER, BLENDING_EXPRESSION_CURRENT_COLOR_PLACEHOLDER } from '../../nodes/FXNode.js';
|
|
2
|
-
import { FXNodeBlending } from '../../nodes/blending/FXNodeBlending.js';
|
|
3
|
-
import { FXBlending } from './FXMaterial.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Processes albedoNodes in order to produce shader code for both the color assignment
|
|
7
|
-
* and the per-pixel blending mode.
|
|
8
|
-
*
|
|
9
|
-
* Nodes are composed sequentially: each node receives the current accumulated value via
|
|
10
|
-
* EXPRESSION_CURRENT_VALUE_PLACEHOLDER and returns a new value. Nodes that do not use
|
|
11
|
-
* the placeholder act as sources and replace the current value entirely.
|
|
12
|
-
*
|
|
13
|
-
* When a FXNodeBlending appears, it receives both the current mask (via
|
|
14
|
-
* EXPRESSION_CURRENT_VALUE_PLACEHOLDER) and the current color (via
|
|
15
|
-
* EXPRESSION_CURRENT_COLOR_PLACEHOLDER), and returns the new mask value. Color nodes
|
|
16
|
-
* that follow a blending node do not affect the mask.
|
|
17
|
-
*/
|
|
18
|
-
function buildAlbedoAndBlendingCode(albedoNodes, blending, useAlphaHashing) {
|
|
19
|
-
if (albedoNodes.length === 0) {
|
|
20
|
-
return { mapFragment: null, premultChunk: buildPremultChunk(blending, false) };
|
|
21
|
-
}
|
|
22
|
-
const hasBlendingNodes = albedoNodes.some((node) => node instanceof FXNodeBlending);
|
|
23
|
-
const lines = [];
|
|
24
|
-
lines.push("vec4 fxAlbedo = vec4(1.0);");
|
|
25
|
-
if (hasBlendingNodes) {
|
|
26
|
-
lines.push("float fxBlendMask = 1.0;");
|
|
27
|
-
}
|
|
28
|
-
for (const node of albedoNodes) {
|
|
29
|
-
if (node instanceof FXNodeBlending) {
|
|
30
|
-
lines.push(`fxBlendMask = ${node.blendingExpression
|
|
31
|
-
.replace(CURRENT_EXPRESSION_VALUE_PLACEHOLDER, "fxBlendMask")
|
|
32
|
-
.replace(BLENDING_EXPRESSION_CURRENT_COLOR_PLACEHOLDER, "fxAlbedo")};`);
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
lines.push(`fxAlbedo = ${node.colorExpression.replace(CURRENT_EXPRESSION_VALUE_PLACEHOLDER, "fxAlbedo")};`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const discardLine = useAlphaHashing ? "" : "if (diffuseColor.a < 0.0035) discard;";
|
|
39
|
-
lines.push(`diffuseColor = fxAlbedo; ${discardLine}`);
|
|
40
|
-
return {
|
|
41
|
-
mapFragment: lines.join("\n"),
|
|
42
|
-
premultChunk: buildPremultChunk(blending, hasBlendingNodes),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
function buildPremultChunk(blending, hasBlendingNodes) {
|
|
46
|
-
if (!hasBlendingNodes) {
|
|
47
|
-
return `gl_FragColor.rgb *= gl_FragColor.a;`;
|
|
48
|
-
}
|
|
49
|
-
if (blending === FXBlending.MASKED_ADDITIVE) {
|
|
50
|
-
return `
|
|
51
|
-
gl_FragColor.rgb *= gl_FragColor.a;
|
|
52
|
-
gl_FragColor.a *= (1.0 - clamp(fxBlendMask, 0.0, 1.0));
|
|
53
|
-
`;
|
|
54
|
-
}
|
|
55
|
-
// MASKED_MULTIPLY: dark areas darken destination, bright areas normal-blend
|
|
56
|
-
return `
|
|
57
|
-
gl_FragColor.rgb *= gl_FragColor.a;
|
|
58
|
-
float fxLumPremult = dot(gl_FragColor.rgb, vec3(0.2126, 0.7152, 0.0722));
|
|
59
|
-
vec4 fxMultiply = vec4(0.0, 0.0, 0.0, gl_FragColor.a - fxLumPremult);
|
|
60
|
-
gl_FragColor = mix(gl_FragColor, fxMultiply, clamp(fxBlendMask, 0.0, 1.0));
|
|
61
|
-
`;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export { buildAlbedoAndBlendingCode };
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { MeshDepthMaterial } from "three";
|
|
2
|
-
import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
|
|
3
|
-
import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
|
|
4
|
-
export declare function buildDepthMaterial(albedoNodes: readonly (FXNodeColor | FXNodeTexture)[], depthAlphaTest: number, useDepthAlphaHash: boolean, useSphericalDepth: boolean): MeshDepthMaterial;
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { MeshDepthMaterial, DoubleSide, RGBADepthPacking } from 'three';
|
|
2
|
-
import { PARTICLE_DEFINES } from '../../miscellaneous/miscellaneous.js';
|
|
3
|
-
import { CURRENT_EXPRESSION_VALUE_PLACEHOLDER } from '../../nodes/FXNode.js';
|
|
4
|
-
|
|
5
|
-
const DEPTH_VERTEX_SHADER = `
|
|
6
|
-
#define PARTICLE_POSITION_X a_builtin[0][0]
|
|
7
|
-
#define PARTICLE_POSITION_Y a_builtin[0][1]
|
|
8
|
-
#define PARTICLE_POSITION_Z a_builtin[0][2]
|
|
9
|
-
|
|
10
|
-
#define PARTICLE_SCALE_X a_builtin[1][2]
|
|
11
|
-
#define PARTICLE_SCALE_Y a_builtin[1][3]
|
|
12
|
-
|
|
13
|
-
#define PARTICLE_ROTATION a_builtin[2][1]
|
|
14
|
-
|
|
15
|
-
attribute mat4 a_builtin;
|
|
16
|
-
varying mat4 p_builtin;
|
|
17
|
-
varying vec2 p_uv;
|
|
18
|
-
varying vec2 vHighPrecisionZW;
|
|
19
|
-
varying float vCenterViewZ;
|
|
20
|
-
|
|
21
|
-
#ifdef USE_ALPHAHASH
|
|
22
|
-
varying vec3 vPosition;
|
|
23
|
-
#endif
|
|
24
|
-
|
|
25
|
-
void main() {
|
|
26
|
-
p_builtin = a_builtin;
|
|
27
|
-
p_uv = uv;
|
|
28
|
-
|
|
29
|
-
#ifdef USE_ALPHAHASH
|
|
30
|
-
vPosition = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z) + vec3(position.xy, 0.0);
|
|
31
|
-
#endif
|
|
32
|
-
|
|
33
|
-
vec2 billboardOffset = position.xy;
|
|
34
|
-
billboardOffset.x *= PARTICLE_SCALE_X;
|
|
35
|
-
billboardOffset.y *= PARTICLE_SCALE_Y;
|
|
36
|
-
|
|
37
|
-
float cosRotation = cos(PARTICLE_ROTATION);
|
|
38
|
-
float sinRotation = sin(PARTICLE_ROTATION);
|
|
39
|
-
billboardOffset = vec2(
|
|
40
|
-
billboardOffset.x * cosRotation - billboardOffset.y * sinRotation,
|
|
41
|
-
billboardOffset.x * sinRotation + billboardOffset.y * cosRotation
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
vec3 particleCenter = vec3(PARTICLE_POSITION_X, PARTICLE_POSITION_Y, PARTICLE_POSITION_Z);
|
|
45
|
-
vec4 modelViewPosition = modelViewMatrix * vec4(particleCenter, 1.0);
|
|
46
|
-
vCenterViewZ = modelViewPosition.z;
|
|
47
|
-
modelViewPosition.xy += billboardOffset;
|
|
48
|
-
gl_Position = projectionMatrix * modelViewPosition;
|
|
49
|
-
vHighPrecisionZW = gl_Position.zw;
|
|
50
|
-
}
|
|
51
|
-
`;
|
|
52
|
-
/**
|
|
53
|
-
* GLSL snippet that replaces the flat `fragCoordZ` with a spherical depth
|
|
54
|
-
* approximation. Treats each billboard as the front hemisphere of a sphere
|
|
55
|
-
* whose radius equals half the smaller particle scale dimension. Fragments
|
|
56
|
-
* outside that radius are discarded, producing a circular silhouette.
|
|
57
|
-
*
|
|
58
|
-
* Expects `vCenterViewZ` (view-space Z of the particle center), `p_uv`,
|
|
59
|
-
* `PARTICLE_SCALE_X / Y`, and `projectionMatrix` to be available.
|
|
60
|
-
*/
|
|
61
|
-
const SPHERICAL_DEPTH_FRAG_COORD_Z = `
|
|
62
|
-
float sphereOffsetX = (p_uv.x - 0.5) * PARTICLE_SCALE_X;
|
|
63
|
-
float sphereOffsetY = (p_uv.y - 0.5) * PARTICLE_SCALE_Y;
|
|
64
|
-
float sphereRadius = min(PARTICLE_SCALE_X, PARTICLE_SCALE_Y) * 0.5;
|
|
65
|
-
float squaredDistanceFromCenter = sphereOffsetX * sphereOffsetX + sphereOffsetY * sphereOffsetY;
|
|
66
|
-
if (squaredDistanceFromCenter > sphereRadius * sphereRadius) discard;
|
|
67
|
-
|
|
68
|
-
float sphereViewZ = vCenterViewZ + sqrt(sphereRadius * sphereRadius - squaredDistanceFromCenter);
|
|
69
|
-
float projectedZ = projectionMatrix[2][2] * sphereViewZ + projectionMatrix[3][2];
|
|
70
|
-
float projectedW = projectionMatrix[2][3] * sphereViewZ + projectionMatrix[3][3];
|
|
71
|
-
float normalizedDeviceZ = projectedZ / projectedW;
|
|
72
|
-
|
|
73
|
-
#ifdef USE_REVERSEDEPTHBUF
|
|
74
|
-
float fragCoordZ = normalizedDeviceZ;
|
|
75
|
-
#else
|
|
76
|
-
float fragCoordZ = 0.5 * normalizedDeviceZ + 0.5;
|
|
77
|
-
#endif
|
|
78
|
-
`;
|
|
79
|
-
const FRAG_COORD_Z_PATTERN = /float fragCoordZ\b[^;]*;/;
|
|
80
|
-
function buildDepthMaterial(albedoNodes, depthAlphaTest, useDepthAlphaHash, useSphericalDepth) {
|
|
81
|
-
const depthNodes = albedoNodes.filter((node) => node.affectsDepth);
|
|
82
|
-
const needsFragmentPatch = depthNodes.length > 0 || useSphericalDepth;
|
|
83
|
-
const material = new MeshDepthMaterial({
|
|
84
|
-
name: "FXDepthMaterial",
|
|
85
|
-
depthPacking: RGBADepthPacking,
|
|
86
|
-
side: DoubleSide,
|
|
87
|
-
forceSinglePass: true,
|
|
88
|
-
alphaHash: useDepthAlphaHash,
|
|
89
|
-
});
|
|
90
|
-
material.onBeforeCompile = (shader) => {
|
|
91
|
-
shader.vertexShader = DEPTH_VERTEX_SHADER;
|
|
92
|
-
if (!needsFragmentPatch) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const seenCacheKeys = new Set();
|
|
96
|
-
const uniqueHelpers = depthNodes
|
|
97
|
-
.filter((node) => {
|
|
98
|
-
if (seenCacheKeys.has(node.cacheKey)) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
seenCacheKeys.add(node.cacheKey);
|
|
102
|
-
return true;
|
|
103
|
-
})
|
|
104
|
-
.map((node) => node.helperFunctions)
|
|
105
|
-
.join("\n");
|
|
106
|
-
const fragmentPreamble = [
|
|
107
|
-
PARTICLE_DEFINES,
|
|
108
|
-
"varying mat4 p_builtin;",
|
|
109
|
-
"varying vec2 p_uv;",
|
|
110
|
-
"varying float vCenterViewZ;",
|
|
111
|
-
useSphericalDepth ? "uniform mat4 projectionMatrix;" : "",
|
|
112
|
-
depthNodes.flatMap((node) => node.uniformDeclarations).join("\n"),
|
|
113
|
-
uniqueHelpers,
|
|
114
|
-
].join("\n");
|
|
115
|
-
for (const node of depthNodes) {
|
|
116
|
-
Object.assign(shader.uniforms, node.uniforms);
|
|
117
|
-
}
|
|
118
|
-
let fragmentShader = shader.fragmentShader;
|
|
119
|
-
if (depthNodes.length > 0) {
|
|
120
|
-
const albedoLines = ["vec4 fxDepthAlbedo = vec4(1.0);"];
|
|
121
|
-
for (const node of depthNodes) {
|
|
122
|
-
albedoLines.push(`fxDepthAlbedo = ${node.colorExpression.replace(CURRENT_EXPRESSION_VALUE_PLACEHOLDER, "fxDepthAlbedo")};`);
|
|
123
|
-
}
|
|
124
|
-
albedoLines.push(`diffuseColor.a = fxDepthAlbedo.a;`);
|
|
125
|
-
albedoLines.push(`if (diffuseColor.a < ${depthAlphaTest.toFixed(4)}) discard;`);
|
|
126
|
-
fragmentShader = fragmentShader.replace("#include <map_fragment>", albedoLines.join("\n"));
|
|
127
|
-
}
|
|
128
|
-
if (useSphericalDepth) {
|
|
129
|
-
if (!FRAG_COORD_Z_PATTERN.test(fragmentShader)) {
|
|
130
|
-
console.warn("FXDepthMaterial: could not find 'float fragCoordZ' in the depth fragment shader. " +
|
|
131
|
-
"Spherical depth will not be applied. " +
|
|
132
|
-
"This may indicate a Three.js version mismatch.");
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
fragmentShader = fragmentShader.replace(FRAG_COORD_Z_PATTERN, SPHERICAL_DEPTH_FRAG_COORD_Z);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
shader.fragmentShader = fragmentPreamble + "\n" + fragmentShader;
|
|
139
|
-
};
|
|
140
|
-
material.customProgramCacheKey = () => `fx-depth-${useDepthAlphaHash ? "alphaHash" : "alphaTest"}-${useSphericalDepth ? "spherical" : "flat"}-${depthNodes.map((node) => node.cacheKey).join("-") || "none"}`;
|
|
141
|
-
return material;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export { buildDepthMaterial };
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { MeshDistanceMaterial } from "three";
|
|
2
|
-
import type { FXNodeColor } from "../../nodes/color/FXNodeColor";
|
|
3
|
-
import type { FXNodeTexture } from "../../nodes/texture/FXNodeTexture";
|
|
4
|
-
export declare function buildDistanceMaterial(albedoNodes: readonly (FXNodeColor | FXNodeTexture)[], distanceAlphaTest: number, useDistanceAlphaHash: boolean, useSphericalDepth: boolean): MeshDistanceMaterial;
|