babylon.quarks 0.25.0 → 0.27.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +854 -8
  2. package/README.md +10 -8
  3. package/dist/babylon.quarks.cjs +1 -1
  4. package/dist/babylon.quarks.cjs.map +1 -1
  5. package/dist/babylon.quarks.esm.js +1 -1
  6. package/dist/babylon.quarks.esm.js.map +1 -1
  7. package/dist/babylon.quarks.umd.min.js +1 -1
  8. package/dist/babylon.quarks.umd.min.js.map +1 -1
  9. package/dist/types/index.d.cts +6683 -0
  10. package/dist/types/index.d.ts +2210 -613
  11. package/package.json +12 -6
  12. package/src/BatchedRenderer.ts +215 -106
  13. package/src/EffectPool.ts +4 -1
  14. package/src/MeshSurfaceEmitter.ts +29 -4
  15. package/src/ParticleEmitter.ts +45 -15
  16. package/src/ParticleSystem.ts +1012 -1962
  17. package/src/QuarksLoader.ts +463 -75
  18. package/src/QuarksPrefab.ts +91 -4
  19. package/src/QuarksSerializer.ts +484 -0
  20. package/src/QuarksUtil.ts +15 -0
  21. package/src/SpriteBatch.ts +149 -238
  22. package/src/TrailBatch.ts +586 -286
  23. package/src/VFXBatch.ts +517 -153
  24. package/src/batchKey.ts +237 -0
  25. package/src/effectResources.ts +79 -0
  26. package/src/envAtlas.ts +119 -17
  27. package/src/index.ts +51 -35
  28. package/src/nodeId.ts +13 -0
  29. package/src/shaderProgram.ts +325 -0
  30. package/src/shaderVariants.ts +225 -0
  31. package/src/shaders/chunks/fog.ts +4 -2
  32. package/src/shaders/chunks/sheet.ts +111 -0
  33. package/src/shaders/chunks/soft.ts +84 -0
  34. package/src/shaders/chunks/surface.ts +132 -42
  35. package/src/shaders/local_particle_physics_vert.glsl.ts +28 -27
  36. package/src/shaders/local_particle_physics_vert.wgsl.ts +30 -28
  37. package/src/shaders/particle_frag.glsl.ts +6 -22
  38. package/src/shaders/particle_frag.wgsl.ts +6 -23
  39. package/src/shaders/particle_physics_frag.glsl.ts +22 -29
  40. package/src/shaders/particle_physics_frag.wgsl.ts +22 -30
  41. package/src/shaders/particle_vert.glsl.ts +11 -26
  42. package/src/shaders/particle_vert.wgsl.ts +11 -25
  43. package/src/shaders/stretched_bb_particle_vert.glsl.ts +21 -39
  44. package/src/shaders/stretched_bb_particle_vert.wgsl.ts +22 -40
  45. package/src/shaders/trail_frag.glsl.ts +14 -1
  46. package/src/shaders/trail_frag.wgsl.ts +14 -0
  47. package/src/shaders/trail_vert.glsl.ts +53 -36
  48. package/src/shaders/trail_vert.wgsl.ts +54 -40
  49. package/src/softDepth.ts +136 -0
  50. package/src/system/BehaviorPlan.ts +85 -0
  51. package/src/system/BoundsTracker.ts +181 -0
  52. package/src/system/EmissionController.ts +360 -0
  53. package/src/system/EventDispatcher.ts +44 -0
  54. package/src/system/ParticleSpawner.ts +274 -0
  55. package/src/system/SimulationClock.ts +130 -0
  56. package/src/system/geometry.ts +111 -0
  57. package/src/system/integrate.ts +428 -0
  58. package/src/system/materialResolve.ts +116 -0
  59. package/src/system/normalize.ts +95 -0
  60. package/src/system/serialization.ts +401 -0
  61. package/src/system/settingsSchema.ts +317 -0
  62. package/src/system/types.ts +410 -0
  63. package/src/textureSource.ts +30 -0
  64. package/src/trailSettings.ts +51 -0
  65. package/src/BatchedParticleRenderer.ts +0 -3
  66. package/src/materials/ParticleMaterials.ts +0 -23
  67. package/src/materials/index.ts +0 -1
  68. package/src/shaders/chunks/index.ts +0 -1
  69. package/src/shaders/chunks/register-shader-chunks.ts +0 -32
  70. package/src/shaders/chunks/soft_fragment.glsl.ts +0 -13
  71. package/src/shaders/chunks/soft_pars_fragment.glsl.ts +0 -20
  72. package/src/shaders/chunks/soft_pars_vertex.glsl.ts +0 -6
  73. package/src/shaders/chunks/soft_vertex.glsl.ts +0 -6
  74. package/src/shaders/chunks/tile_fragment.glsl.ts +0 -9
  75. package/src/shaders/chunks/tile_pars_fragment.glsl.ts +0 -9
  76. package/src/shaders/chunks/tile_pars_vertex.glsl.ts +0 -28
  77. package/src/shaders/chunks/tile_vertex.glsl.ts +0 -18
  78. package/src/shaders/index.ts +0 -9
  79. package/src/shaders/local_particle_vert.glsl.ts +0 -50
@@ -1,9 +1,13 @@
1
1
  import {fogFragmentDeclarationGLSL, fogFragmentGLSL} from './chunks/fog';
2
+ import {softFragmentDeclarationGLSL, softFragmentGLSL} from './chunks/soft';
2
3
  import {surfaceColorGLSL, surfaceFragmentDeclarationGLSL} from './chunks/surface';
3
4
 
4
5
  export default /* glsl */ `
5
6
  varying vec2 vUV;
6
7
  varying vec4 vColor;
8
+ #ifdef UV1
9
+ varying vec2 vUV1;
10
+ #endif
7
11
  varying vec3 vNormal;
8
12
  varying vec3 vWorldPos;
9
13
 
@@ -76,29 +80,18 @@ vec3 sampleEnvAtlas(vec3 r) {
76
80
  }
77
81
  #endif
78
82
 
79
- #ifdef SOFT_PARTICLES
80
- uniform sampler2D depthTexture;
81
- uniform vec2 softParams;
82
- uniform vec4 projParams;
83
- varying vec4 projPosition;
84
- varying float linearDepth;
85
- #endif
86
83
 
87
84
  #ifdef USE_ALPHATEST
88
85
  uniform float alphaTest;
89
86
  #endif
90
87
 
91
88
  ${fogFragmentDeclarationGLSL}
89
+ ${softFragmentDeclarationGLSL}
92
90
  ${surfaceFragmentDeclarationGLSL}
93
91
  void main() {
94
92
  ${surfaceColorGLSL(true)}
95
- #ifdef USE_ALPHATEST
96
- if (baseColor.a < alphaTest) discard;
97
- #else
98
- if (baseColor.a < 0.01) discard;
99
- #endif
100
-
101
- vec3 N = normalize(vNormal);
93
+ // A back face lights, reflects and rims as the face the camera sees.
94
+ vec3 N = normalize(vNormal) * (gl_FrontFacing ? 1.0 : -1.0);
102
95
  #ifdef MESH_UNLIT
103
96
  vec3 color = baseColor.rgb;
104
97
  #else
@@ -118,26 +111,26 @@ ${surfaceColorGLSL(true)}
118
111
  #ifdef MESH_RIM
119
112
  // Fresnel: strongest where the surface turns away from the camera.
120
113
  vec3 V = normalize(eyePosition - vWorldPos);
121
- float rim = pow(1.0 - abs(dot(N, V)), rimParams.x) * rimParams.y;
122
- #ifdef MESH_RIM_MIX
123
- color = mix(color, rimColor, clamp(rim, 0.0, 1.0));
114
+ float edgeTerm = pow(1.0 - abs(dot(N, V)), rimParams.x);
115
+ #if defined(MESH_RIM_FADE)
116
+ // Faces turned to the camera fade by the strength; edges stay.
117
+ baseColor.a *= clamp(1.0 - rimParams.y * (1.0 - edgeTerm), 0.0, 1.0);
118
+ #elif defined(MESH_RIM_MIX)
119
+ color = mix(color, rimColor, clamp(edgeTerm * rimParams.y, 0.0, 1.0));
124
120
  #else
125
- color += rimColor * rim;
121
+ color += rimColor * edgeTerm * rimParams.y;
126
122
  #endif
127
123
  #endif
128
124
 
125
+ // After the rim, so a fade that empties a face can discard it.
126
+ #ifdef USE_ALPHATEST
127
+ if (baseColor.a < alphaTest) discard;
128
+ #else
129
+ if (baseColor.a < 0.01) discard;
130
+ #endif
131
+
129
132
  ${fogFragmentGLSL('color')}
130
133
  gl_FragColor = vec4(color, baseColor.a);
131
-
132
- #ifdef SOFT_PARTICLES
133
- vec2 p2 = projPosition.xy / projPosition.w;
134
- p2 = 0.5 * p2 + 0.5;
135
- float readDepth = texture2D(depthTexture, p2.xy).r;
136
- float zNear = projParams.x;
137
- float zFar = projParams.y;
138
- float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));
139
- float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);
140
- gl_FragColor *= fade;
141
- #endif
134
+ ${softFragmentGLSL('gl_FragColor')}
142
135
  }
143
136
  `;
@@ -1,9 +1,13 @@
1
1
  import {fogFragmentDeclarationWGSL, fogFragmentWGSL} from './chunks/fog';
2
+ import {softFragmentDeclarationWGSL, softFragmentWGSL} from './chunks/soft';
2
3
  import {surfaceColorWGSL, surfaceFragmentDeclarationWGSL} from './chunks/surface';
3
4
 
4
5
  export default /* wgsl */ `
5
6
  varying vUV: vec2f;
6
7
  varying vColor: vec4f;
8
+ #ifdef UV1
9
+ varying vUV1: vec2f;
10
+ #endif
7
11
  varying vNormal: vec3f;
8
12
  varying vWorldPos: vec3f;
9
13
 
@@ -75,31 +79,19 @@ fn sampleEnvAtlas(r: vec3f) -> vec3f {
75
79
  }
76
80
  #endif
77
81
 
78
- #ifdef SOFT_PARTICLES
79
- var depthTextureSampler: sampler;
80
- var depthTexture: texture_2d<f32>;
81
- uniform softParams: vec2f;
82
- uniform projParams: vec4f;
83
- varying projPosition: vec4f;
84
- varying linearDepth: f32;
85
- #endif
86
82
 
87
83
  #ifdef USE_ALPHATEST
88
84
  uniform alphaTest: f32;
89
85
  #endif
90
86
 
91
87
  ${fogFragmentDeclarationWGSL}
88
+ ${softFragmentDeclarationWGSL}
92
89
  ${surfaceFragmentDeclarationWGSL}
93
90
  @fragment
94
91
  fn main(input: FragmentInputs) -> FragmentOutputs {
95
92
  ${surfaceColorWGSL(true)}
96
- #ifdef USE_ALPHATEST
97
- if (baseColor.a < uniforms.alphaTest) { discard; }
98
- #else
99
- if (baseColor.a < 0.01) { discard; }
100
- #endif
101
-
102
- let N = normalize(fragmentInputs.vNormal);
93
+ // A back face lights, reflects and rims as the face the camera sees.
94
+ let N = normalize(fragmentInputs.vNormal) * select(-1.0, 1.0, fragmentInputs.frontFacing);
103
95
  #ifdef MESH_UNLIT
104
96
  var color = baseColor.rgb;
105
97
  #else
@@ -119,28 +111,28 @@ ${surfaceColorWGSL(true)}
119
111
  #ifdef MESH_RIM
120
112
  // Fresnel: strongest where the surface turns away from the camera.
121
113
  let V = normalize(uniforms.eyePosition - fragmentInputs.vWorldPos);
122
- let rimTerm = pow(1.0 - abs(dot(N, V)), uniforms.rimParams.x) * uniforms.rimParams.y;
123
- #ifdef MESH_RIM_MIX
124
- color = mix(color, uniforms.rimColor, clamp(rimTerm, 0.0, 1.0));
114
+ let edgeTerm = pow(1.0 - abs(dot(N, V)), uniforms.rimParams.x);
115
+ #if defined(MESH_RIM_FADE)
116
+ // Faces turned to the camera fade by the strength; edges stay.
117
+ baseColor.a *= clamp(1.0 - uniforms.rimParams.y * (1.0 - edgeTerm), 0.0, 1.0);
118
+ #elif defined(MESH_RIM_MIX)
119
+ color = mix(color, uniforms.rimColor, clamp(edgeTerm * uniforms.rimParams.y, 0.0, 1.0));
125
120
  #else
126
- color += uniforms.rimColor * rimTerm;
121
+ color += uniforms.rimColor * edgeTerm * uniforms.rimParams.y;
127
122
  #endif
128
123
  #endif
129
124
 
130
- var finalColor = vec4f(color, baseColor.a);
131
-
132
- #ifdef SOFT_PARTICLES
133
- var p2 = fragmentInputs.projPosition.xy / fragmentInputs.projPosition.w;
134
- p2 = 0.5 * p2 + 0.5;
135
- let readDepth = textureSample(depthTexture, depthTextureSampler, p2).r;
136
- let zNear = uniforms.projParams.x;
137
- let zFar = uniforms.projParams.y;
138
- let viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));
139
- let fade = clamp(uniforms.softParams.y * ((viewDepth - uniforms.softParams.x) - fragmentInputs.linearDepth), 0.0, 1.0);
140
- finalColor *= fade;
125
+ // After the rim, so a fade that empties a face can discard it.
126
+ #ifdef USE_ALPHATEST
127
+ if (baseColor.a < uniforms.alphaTest) { discard; }
128
+ #else
129
+ if (baseColor.a < 0.01) { discard; }
141
130
  #endif
142
131
 
132
+ var finalColor = vec4f(color, baseColor.a);
133
+
143
134
  ${fogFragmentWGSL('finalColor')}
135
+ ${softFragmentWGSL('finalColor')}
144
136
  fragmentOutputs.color = finalColor;
145
137
  }
146
138
  `;
@@ -1,4 +1,5 @@
1
1
  import {fogVertexDeclarationGLSL, fogVertexGLSL} from './chunks/fog';
2
+ import {sheetVertexDeclarationGLSL, sheetVertexGLSL} from './chunks/sheet';
2
3
 
3
4
  export default /* glsl */ `
4
5
  // Per-vertex attributes
@@ -16,12 +17,7 @@ attribute float uvTile;
16
17
  uniform mat4 world;
17
18
  uniform mat4 view;
18
19
  uniform mat4 projection;
19
- uniform mat4 worldViewProjection;
20
-
21
- #ifdef UV_TILE
22
- uniform float tileCountX;
23
- uniform float tileCountY;
24
- #endif
20
+ ${sheetVertexDeclarationGLSL}
25
21
 
26
22
  #ifdef PIVOT
27
23
  // Quad offset in particle-size units: xy in the quad's plane, z toward the camera.
@@ -31,9 +27,9 @@ uniform vec3 pivot;
31
27
  // Varyings
32
28
  varying vec2 vUV;
33
29
  varying vec4 vColor;
34
- #ifdef TILE_BLEND
35
- varying vec2 vUV2;
36
- varying float vTileBlend;
30
+ #ifdef UV1
31
+ // The particle's own UV, never moved by the sheet (UV channel 1).
32
+ varying vec2 vUV1;
37
33
  #endif
38
34
  #ifdef SOFT_PARTICLES
39
35
  varying vec4 projPosition;
@@ -99,26 +95,15 @@ void main() {
99
95
  ${fogVertexGLSL('mvPosition.xyz')}
100
96
  #ifdef SOFT_PARTICLES
101
97
  projPosition = gl_Position;
102
- linearDepth = -mvPosition.z;
98
+ // View depth is +z ahead of a left-handed camera and -z ahead of a right-handed one.
99
+ linearDepth = abs(mvPosition.z);
103
100
  #endif
104
101
 
105
- #ifdef UV_TILE
106
- vec2 tc = vec2(tileCountX, tileCountY);
107
- float baseTile = floor(uvTile);
108
- float tileU = mod(baseTile, tc.x) / tc.x;
109
- float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;
110
- vUV = uv / tc + vec2(tileU, tileV);
111
- #ifdef TILE_BLEND
112
- float nextTile = ceil(uvTile);
113
- float nextU = mod(nextTile, tc.x) / tc.x;
114
- float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;
115
- vUV2 = uv / tc + vec2(nextU, nextV);
116
- vTileBlend = fract(uvTile);
117
- #endif
118
- #else
119
- vUV = uv;
120
- #endif
102
+ ${sheetVertexGLSL('uv')}
121
103
 
104
+ #ifdef UV1
105
+ vUV1 = uv;
106
+ #endif
122
107
  vColor = color;
123
108
  }
124
109
  `;
@@ -1,4 +1,5 @@
1
1
  import {fogVertexDeclarationWGSL, fogVertexWGSL} from './chunks/fog';
2
+ import {sheetVertexDeclarationWGSL, sheetVertexWGSL} from './chunks/sheet';
2
3
 
3
4
  export default /* wgsl */ `
4
5
  // Per-vertex attributes
@@ -16,11 +17,7 @@ attribute uvTile: f32;
16
17
  uniform world: mat4x4f;
17
18
  uniform view: mat4x4f;
18
19
  uniform projection: mat4x4f;
19
-
20
- #ifdef UV_TILE
21
- uniform tileCountX: f32;
22
- uniform tileCountY: f32;
23
- #endif
20
+ ${sheetVertexDeclarationWGSL}
24
21
 
25
22
  #ifdef PIVOT
26
23
  // Quad offset in particle-size units: xy in the quad's plane, z toward the camera.
@@ -30,9 +27,9 @@ uniform pivot: vec3f;
30
27
  // Varyings
31
28
  varying vUV: vec2f;
32
29
  varying vColor: vec4f;
33
- #ifdef TILE_BLEND
34
- varying vUV2: vec2f;
35
- varying vTileBlend: f32;
30
+ #ifdef UV1
31
+ // The particle's own UV, never moved by the sheet (UV channel 1).
32
+ varying vUV1: vec2f;
36
33
  #endif
37
34
  #ifdef SOFT_PARTICLES
38
35
  varying projPosition: vec4f;
@@ -101,26 +98,15 @@ fn main(input: VertexInputs) -> FragmentInputs {
101
98
  ${fogVertexWGSL('mvPosition.xyz')}
102
99
  #ifdef SOFT_PARTICLES
103
100
  vertexOutputs.projPosition = clipPosition;
104
- vertexOutputs.linearDepth = -mvPosition.z;
101
+ // View depth is +z ahead of a left-handed camera and -z ahead of a right-handed one.
102
+ vertexOutputs.linearDepth = abs(mvPosition.z);
105
103
  #endif
106
104
 
107
- #ifdef UV_TILE
108
- let tc = vec2f(uniforms.tileCountX, uniforms.tileCountY);
109
- let baseTile = floor(vertexInputs.uvTile);
110
- let tileU = (baseTile % tc.x) / tc.x;
111
- let tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;
112
- vertexOutputs.vUV = vertexInputs.uv / tc + vec2f(tileU, tileV);
113
- #ifdef TILE_BLEND
114
- let nextTile = ceil(vertexInputs.uvTile);
115
- let nextU = (nextTile % tc.x) / tc.x;
116
- let nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;
117
- vertexOutputs.vUV2 = vertexInputs.uv / tc + vec2f(nextU, nextV);
118
- vertexOutputs.vTileBlend = fract(vertexInputs.uvTile);
119
- #endif
120
- #else
121
- vertexOutputs.vUV = vertexInputs.uv;
122
- #endif
105
+ ${sheetVertexWGSL('vertexInputs.uv')}
123
106
 
107
+ #ifdef UV1
108
+ vertexOutputs.vUV1 = vertexInputs.uv;
109
+ #endif
124
110
  vertexOutputs.vColor = vertexInputs.color;
125
111
  }
126
112
  `;
@@ -1,4 +1,5 @@
1
1
  import {fogVertexDeclarationGLSL, fogVertexGLSL} from './chunks/fog';
2
+ import {sheetVertexDeclarationGLSL, sheetVertexGLSL} from './chunks/sheet';
2
3
 
3
4
  export default /* glsl */ `
4
5
  // Per-vertex attributes
@@ -17,12 +18,7 @@ attribute vec4 velocity;
17
18
  uniform mat4 world;
18
19
  uniform mat4 view;
19
20
  uniform mat4 projection;
20
- uniform float speedFactor;
21
-
22
- #ifdef UV_TILE
23
- uniform float tileCountX;
24
- uniform float tileCountY;
25
- #endif
21
+ ${sheetVertexDeclarationGLSL}
26
22
 
27
23
  #ifdef PIVOT
28
24
  // Streak offset in particle-size units: x from head to tail, y across.
@@ -32,9 +28,9 @@ uniform vec3 pivot;
32
28
  // Varyings
33
29
  varying vec2 vUV;
34
30
  varying vec4 vColor;
35
- #ifdef TILE_BLEND
36
- varying vec2 vUV2;
37
- varying float vTileBlend;
31
+ #ifdef UV1
32
+ // The particle's own UV, never moved by the sheet (UV channel 1).
33
+ varying vec2 vUV1;
38
34
  #endif
39
35
  #ifdef SOFT_PARTICLES
40
36
  varying vec4 projPosition;
@@ -45,6 +41,7 @@ varying float linearDepth;
45
41
  // Smallest and largest size a particle may have on screen, as fractions of the viewport height.
46
42
  uniform vec2 sizeLimits;
47
43
  #endif
44
+
48
45
  ${fogVertexDeclarationGLSL}
49
46
  void main() {
50
47
  float lengthFactor = velocity.w;
@@ -52,6 +49,15 @@ void main() {
52
49
  // extent and mirrors its texture instead (see quadUV below).
53
50
  float avgSize = (abs(size.x) + abs(size.y)) * 0.5;
54
51
  vec4 mvPosition = view * world * vec4(offset, 1.0);
52
+ vec3 viewVelocity = mat3(view * world) * velocity.xyz;
53
+ float vlength = length(viewVelocity);
54
+ // Stretch direction is the velocity direction; only a genuinely motionless particle has none.
55
+ // Deriving it via normalize keeps the stretch aligned even when the speed contribution is ~0
56
+ // (e.g. a speed factor of 0), instead of collapsing the whole burst onto a fixed screen axis.
57
+ vec3 vdir = vlength > 0.000001 ? viewVelocity / vlength : vec3(0.0, 0.0, 1.0);
58
+ // Seen straight along its length a streak has no side to face; any will do.
59
+ vec3 sideRaw = cross(mvPosition.xyz, vdir);
60
+ vec3 side = dot(sideRaw, sideRaw) > 1e-12 ? normalize(sideRaw) : vec3(1.0, 0.0, 0.0);
55
61
  #ifdef SIZE_LIMITS
56
62
  // The streak's width on screen as a fraction of the viewport height, held
57
63
  // between the limits; a perspective projection divides by the view depth.
@@ -60,19 +66,6 @@ void main() {
60
66
  if (screenSize > 0.0) {
61
67
  avgSize *= clamp(screenSize, sizeLimits.x, sizeLimits.y) / screenSize;
62
68
  }
63
- #endif
64
- vec3 viewVelocity = mat3(view * world) * velocity.xyz;
65
- float vlength = length(viewVelocity);
66
- // Stretch direction is the velocity direction; only a genuinely motionless particle has none.
67
- // Deriving it via normalize keeps the stretch aligned even when the speed contribution is ~0
68
- // (e.g. speedFactor 0), instead of collapsing the whole burst onto a fixed screen axis.
69
- vec3 vdir = vlength > 0.000001 ? viewVelocity / vlength : vec3(0.0, 0.0, 1.0);
70
- #ifdef BEAM
71
- // Seen straight along its length a beam has no side to face; any will do.
72
- vec3 sideRaw = cross(mvPosition.xyz, vdir);
73
- vec3 side = dot(sideRaw, sideRaw) > 1e-12 ? normalize(sideRaw) : vec3(1.0, 0.0, 0.0);
74
- #else
75
- vec3 side = normalize(cross(mvPosition.xyz, vdir));
76
69
  #endif
77
70
  mvPosition.xyz += position.y * side * avgSize;
78
71
  #ifdef BEAM
@@ -93,26 +86,15 @@ ${fogVertexGLSL('mvPosition.xyz')}
93
86
  vec2 quadUV = vec2(size.x < 0.0 ? 1.0 - uv.x : uv.x, size.y < 0.0 ? 1.0 - uv.y : uv.y);
94
87
  #ifdef SOFT_PARTICLES
95
88
  projPosition = gl_Position;
96
- linearDepth = -mvPosition.z;
89
+ // View depth is +z ahead of a left-handed camera and -z ahead of a right-handed one.
90
+ linearDepth = abs(mvPosition.z);
97
91
  #endif
98
92
 
99
- #ifdef UV_TILE
100
- vec2 tc = vec2(tileCountX, tileCountY);
101
- float baseTile = floor(uvTile);
102
- float tileU = mod(baseTile, tc.x) / tc.x;
103
- float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;
104
- vUV = quadUV / tc + vec2(tileU, tileV);
105
- #ifdef TILE_BLEND
106
- float nextTile = ceil(uvTile);
107
- float nextU = mod(nextTile, tc.x) / tc.x;
108
- float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;
109
- vUV2 = quadUV / tc + vec2(nextU, nextV);
110
- vTileBlend = fract(uvTile);
111
- #endif
112
- #else
113
- vUV = quadUV;
114
- #endif
93
+ ${sheetVertexGLSL('quadUV')}
115
94
 
95
+ #ifdef UV1
96
+ vUV1 = quadUV;
97
+ #endif
116
98
  vColor = color;
117
99
  }
118
100
  `;
@@ -1,4 +1,5 @@
1
1
  import {fogVertexDeclarationWGSL, fogVertexWGSL} from './chunks/fog';
2
+ import {sheetVertexDeclarationWGSL, sheetVertexWGSL} from './chunks/sheet';
2
3
 
3
4
  export default /* wgsl */ `
4
5
  // Per-vertex attributes
@@ -17,12 +18,7 @@ attribute velocity: vec4f;
17
18
  uniform world: mat4x4f;
18
19
  uniform view: mat4x4f;
19
20
  uniform projection: mat4x4f;
20
- uniform speedFactor: f32;
21
-
22
- #ifdef UV_TILE
23
- uniform tileCountX: f32;
24
- uniform tileCountY: f32;
25
- #endif
21
+ ${sheetVertexDeclarationWGSL}
26
22
 
27
23
  #ifdef PIVOT
28
24
  // Streak offset in particle-size units: x from head to tail, y across.
@@ -32,9 +28,9 @@ uniform pivot: vec3f;
32
28
  // Varyings
33
29
  varying vUV: vec2f;
34
30
  varying vColor: vec4f;
35
- #ifdef TILE_BLEND
36
- varying vUV2: vec2f;
37
- varying vTileBlend: f32;
31
+ #ifdef UV1
32
+ // The particle's own UV, never moved by the sheet (UV channel 1).
33
+ varying vUV1: vec2f;
38
34
  #endif
39
35
  #ifdef SOFT_PARTICLES
40
36
  varying projPosition: vec4f;
@@ -45,6 +41,7 @@ varying linearDepth: f32;
45
41
  // Smallest and largest size a particle may have on screen, as fractions of the viewport height.
46
42
  uniform sizeLimits: vec2f;
47
43
  #endif
44
+
48
45
  ${fogVertexDeclarationWGSL}
49
46
  @vertex
50
47
  fn main(input: VertexInputs) -> FragmentInputs {
@@ -53,35 +50,31 @@ fn main(input: VertexInputs) -> FragmentInputs {
53
50
  // extent and mirrors its texture instead (see quadUV below).
54
51
  var avgSize = (abs(vertexInputs.size.x) + abs(vertexInputs.size.y)) * 0.5;
55
52
  var mvPosition = uniforms.view * uniforms.world * vec4f(vertexInputs.offset, 1.0);
56
- #ifdef SIZE_LIMITS
57
- // The streak's width on screen as a fraction of the viewport height, held
58
- // between the limits; a perspective projection divides by the view depth.
59
- let limitDepth = select(1.0, abs(mvPosition.z), abs(uniforms.projection[2][3]) > 0.0);
60
- let screenSize = avgSize * uniforms.projection[1][1] / (2.0 * limitDepth);
61
- if (screenSize > 0.0) {
62
- avgSize *= clamp(screenSize, uniforms.sizeLimits.x, uniforms.sizeLimits.y) / screenSize;
63
- }
64
- #endif
65
53
  let viewWorld = uniforms.view * uniforms.world;
66
54
  let viewWorld3 = mat3x3f(viewWorld[0].xyz, viewWorld[1].xyz, viewWorld[2].xyz);
67
55
  let viewVelocity = viewWorld3 * vertexInputs.velocity.xyz;
68
56
  let vlength = length(viewVelocity);
69
57
  // Stretch direction is the velocity direction; only a genuinely motionless particle has none.
70
58
  // Deriving it via normalize keeps the stretch aligned even when the speed contribution is ~0
71
- // (e.g. speedFactor 0), instead of collapsing the whole burst onto a fixed screen axis.
59
+ // (e.g. a speed factor of 0), instead of collapsing the whole burst onto a fixed screen axis.
72
60
  var vdir = vec3f(0.0, 0.0, 1.0);
73
61
  if (vlength > 0.000001) {
74
62
  vdir = viewVelocity / vlength;
75
63
  }
76
- #ifdef BEAM
77
- // Seen straight along its length a beam has no side to face; any will do.
64
+ // Seen straight along its length a streak has no side to face; any will do.
78
65
  let sideRaw = cross(mvPosition.xyz, vdir);
79
66
  var side = vec3f(1.0, 0.0, 0.0);
80
67
  if (dot(sideRaw, sideRaw) > 1e-12) {
81
68
  side = normalize(sideRaw);
82
69
  }
83
- #else
84
- let side = normalize(cross(mvPosition.xyz, vdir));
70
+ #ifdef SIZE_LIMITS
71
+ // The streak's width on screen as a fraction of the viewport height, held
72
+ // between the limits; a perspective projection divides by the view depth.
73
+ let limitDepth = select(1.0, abs(mvPosition.z), abs(uniforms.projection[2][3]) > 0.0);
74
+ let screenSize = avgSize * uniforms.projection[1][1] / (2.0 * limitDepth);
75
+ if (screenSize > 0.0) {
76
+ avgSize *= clamp(screenSize, uniforms.sizeLimits.x, uniforms.sizeLimits.y) / screenSize;
77
+ }
85
78
  #endif
86
79
  let widthOffset = vertexInputs.position.y * side * avgSize;
87
80
  // Equivalent to viewVelocity * (1.0 + lengthFactor / vlength) for moving particles, but the
@@ -108,26 +101,15 @@ ${fogVertexWGSL('mvPosition.xyz')}
108
101
  let quadUV = select(vertexInputs.uv, 1.0 - vertexInputs.uv, vertexInputs.size.xy < vec2f(0.0));
109
102
  #ifdef SOFT_PARTICLES
110
103
  vertexOutputs.projPosition = clipPosition;
111
- vertexOutputs.linearDepth = -mvPosition.z;
104
+ // View depth is +z ahead of a left-handed camera and -z ahead of a right-handed one.
105
+ vertexOutputs.linearDepth = abs(mvPosition.z);
112
106
  #endif
113
107
 
114
- #ifdef UV_TILE
115
- let tc = vec2f(uniforms.tileCountX, uniforms.tileCountY);
116
- let baseTile = floor(vertexInputs.uvTile);
117
- let tileU = (baseTile % tc.x) / tc.x;
118
- let tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;
119
- vertexOutputs.vUV = quadUV / tc + vec2f(tileU, tileV);
120
- #ifdef TILE_BLEND
121
- let nextTile = ceil(vertexInputs.uvTile);
122
- let nextU = (nextTile % tc.x) / tc.x;
123
- let nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;
124
- vertexOutputs.vUV2 = quadUV / tc + vec2f(nextU, nextV);
125
- vertexOutputs.vTileBlend = fract(vertexInputs.uvTile);
126
- #endif
127
- #else
128
- vertexOutputs.vUV = quadUV;
129
- #endif
108
+ ${sheetVertexWGSL('quadUV')}
130
109
 
110
+ #ifdef UV1
111
+ vertexOutputs.vUV1 = quadUV;
112
+ #endif
131
113
  vertexOutputs.vColor = vertexInputs.color;
132
114
  }
133
115
  `;
@@ -1,21 +1,34 @@
1
1
  import {fogFragmentDeclarationGLSL, fogFragmentGLSL} from './chunks/fog';
2
+ import {softFragmentDeclarationGLSL, softFragmentGLSL} from './chunks/soft';
2
3
  import {surfaceColorGLSL, surfaceFragmentDeclarationGLSL} from './chunks/surface';
3
4
 
4
5
  export default /* glsl */ `
5
6
  varying vec2 vUV;
6
7
  varying vec4 vColor;
8
+ #ifdef UV1
9
+ varying vec2 vUV1;
10
+ #endif
7
11
 
8
12
  #ifdef USE_MAP
9
13
  uniform sampler2D map;
10
14
  #endif
11
15
 
16
+ #ifdef USE_ALPHATEST
17
+ uniform float alphaTest;
18
+ #endif
19
+
12
20
  ${fogFragmentDeclarationGLSL}
21
+ ${softFragmentDeclarationGLSL}
13
22
  ${surfaceFragmentDeclarationGLSL}
14
23
  void main() {
15
24
  ${surfaceColorGLSL(false)}
25
+ #ifdef USE_ALPHATEST
26
+ if (baseColor.a < alphaTest) discard;
27
+ #else
16
28
  if (baseColor.a < 0.01) discard;
29
+ #endif
17
30
 
18
31
  ${fogFragmentGLSL('baseColor.rgb')}
19
32
  gl_FragColor = baseColor;
20
- }
33
+ ${softFragmentGLSL('gl_FragColor')}}
21
34
  `;
@@ -1,23 +1,37 @@
1
1
  import {fogFragmentDeclarationWGSL, fogFragmentWGSL} from './chunks/fog';
2
+ import {softFragmentDeclarationWGSL, softFragmentWGSL} from './chunks/soft';
2
3
  import {surfaceColorWGSL, surfaceFragmentDeclarationWGSL} from './chunks/surface';
3
4
 
4
5
  export default /* wgsl */ `
5
6
  varying vUV: vec2f;
6
7
  varying vColor: vec4f;
8
+ #ifdef UV1
9
+ varying vUV1: vec2f;
10
+ #endif
7
11
 
8
12
  #ifdef USE_MAP
9
13
  var mapSampler: sampler;
10
14
  var map: texture_2d<f32>;
11
15
  #endif
12
16
 
17
+ #ifdef USE_ALPHATEST
18
+ uniform alphaTest: f32;
19
+ #endif
20
+
13
21
  ${fogFragmentDeclarationWGSL}
22
+ ${softFragmentDeclarationWGSL}
14
23
  ${surfaceFragmentDeclarationWGSL}
15
24
  @fragment
16
25
  fn main(input: FragmentInputs) -> FragmentOutputs {
17
26
  ${surfaceColorWGSL(false)}
27
+ #ifdef USE_ALPHATEST
28
+ if (baseColor.a < uniforms.alphaTest) { discard; }
29
+ #else
18
30
  if (baseColor.a < 0.01) { discard; }
31
+ #endif
19
32
 
20
33
  ${fogFragmentWGSL('baseColor')}
34
+ ${softFragmentWGSL('baseColor')}
21
35
  fragmentOutputs.color = baseColor;
22
36
  }
23
37
  `;