babylon.quarks 0.24.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +124 -0
- package/dist/babylon.quarks.cjs +1 -1
- package/dist/babylon.quarks.cjs.map +1 -1
- package/dist/babylon.quarks.esm.js +1 -1
- package/dist/babylon.quarks.esm.js.map +1 -1
- package/dist/babylon.quarks.umd.min.js +1 -1
- package/dist/babylon.quarks.umd.min.js.map +1 -1
- package/dist/types/index.d.ts +501 -9
- package/package.json +1 -1
- package/src/BatchedRenderer.ts +34 -1
- package/src/ParticleSystem.ts +465 -13
- package/src/QuarksLoader.ts +50 -2
- package/src/QuarksUtil.ts +97 -1
- package/src/SpriteBatch.ts +101 -10
- package/src/TrailBatch.ts +132 -20
- package/src/VFXBatch.ts +465 -4
- package/src/index.ts +38 -2
- package/src/shaders/chunks/surface.ts +268 -0
- package/src/shaders/local_particle_physics_vert.glsl.ts +15 -0
- package/src/shaders/local_particle_physics_vert.wgsl.ts +15 -0
- package/src/shaders/particle_frag.glsl.ts +6 -11
- package/src/shaders/particle_frag.wgsl.ts +6 -11
- package/src/shaders/particle_physics_frag.glsl.ts +13 -15
- package/src/shaders/particle_physics_frag.wgsl.ts +13 -15
- package/src/shaders/particle_vert.glsl.ts +7 -0
- package/src/shaders/particle_vert.wgsl.ts +7 -0
- package/src/shaders/stretched_bb_particle_vert.glsl.ts +27 -7
- package/src/shaders/stretched_bb_particle_vert.wgsl.ts +32 -9
- package/src/shaders/trail_frag.glsl.ts +6 -7
- package/src/shaders/trail_frag.wgsl.ts +6 -7
- package/src/shaders/trail_vert.glsl.ts +8 -0
- package/src/shaders/trail_vert.wgsl.ts +8 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Texture effects shared by the sprite, mesh and trail fragment shaders, in
|
|
3
|
+
* both shader languages: UV scrolling, UV distortion, a gradient map and
|
|
4
|
+
* alpha erosion.
|
|
5
|
+
*
|
|
6
|
+
* - `UV1`: the vertex shader passes `vUV1`, the particle's own UV that the
|
|
7
|
+
* sprite sheet never moves (see `UVChannel`). The distortion noise and the
|
|
8
|
+
* erosion mask read it under `UV_DISTORTION_UV1` / `EROSION_MASK_UV1`, the
|
|
9
|
+
* map's UV (`vUV`) otherwise.
|
|
10
|
+
* - Each texture can be laid by a transform, `(tiling u, tiling v, offset u,
|
|
11
|
+
* offset v)`: sampled at `uv * transform.xy + transform.zw`, the offset
|
|
12
|
+
* holding its scroll, wrapped on the CPU so it never loses precision (see
|
|
13
|
+
* `TextureUV`).
|
|
14
|
+
* - `MAP_TRANSFORM`: the map is laid by `mapTransform`, on `vUV1` under
|
|
15
|
+
* `MAP_UV1` (where the sheet's second tile is not blended, the sheet not
|
|
16
|
+
* applying), on the sheet's UV otherwise, where a scroll runs into the
|
|
17
|
+
* neighbouring tiles.
|
|
18
|
+
* - `UV_DISTORTION`: the map's UV is pushed about by a noise texture
|
|
19
|
+
* (`distortionMap`, red and green around 0.5, laid by `distortionTransform`)
|
|
20
|
+
* by up to `distortionStrength` UV units: the heat shimmer, licking and
|
|
21
|
+
* breathing of fire and auras. On a sprite sheet the pushed UV can reach
|
|
22
|
+
* the neighbouring tile.
|
|
23
|
+
* - `GRADIENT_MAP`: the map's texel dotted with `gradientMapChannel` (one
|
|
24
|
+
* channel, or luminance weights) picks a colour along U of `gradientMap`.
|
|
25
|
+
* The ramp's alpha multiplies the map's, or replaces it when the lookup is
|
|
26
|
+
* by alpha (`gradientMapChannel.a` 1). The particle colour still tints the
|
|
27
|
+
* result. `gradientMapRange` keeps the lookup between the first and last
|
|
28
|
+
* texel centres. Make the ramp without mipmaps: the lookup's UV jumps with
|
|
29
|
+
* the map's detail, and the hardware would pick a blurred mip for it.
|
|
30
|
+
* - `EROSION`: the particle's alpha stops being a transparency and becomes how
|
|
31
|
+
* much of the shape is left. A fragment shows where the mask (the red
|
|
32
|
+
* channel of `erosionMask` under `EROSION_MASK`, laid by
|
|
33
|
+
* `erosionMaskTransform`; the map's alpha otherwise) is above the cut that
|
|
34
|
+
* alpha sets: alpha 1 shows everything the map shows, alpha 0 nothing, and
|
|
35
|
+
* on the way down the shape eats away from its lowest mask values first — a
|
|
36
|
+
* noise mask dissolves it, a gradient mask wipes it. `erosionParams` is
|
|
37
|
+
* (softness, edge width); the edge band just above the cut glows in
|
|
38
|
+
* `erosionEdgeColor`. Erosion only changes alpha, so blend modes that
|
|
39
|
+
* ignore alpha (one-one, premultiplied) show a hard cut.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/** Fragment-side declarations, GLSL. */
|
|
43
|
+
export const surfaceFragmentDeclarationGLSL = /* glsl */ `
|
|
44
|
+
#ifdef MAP_TRANSFORM
|
|
45
|
+
uniform vec4 mapTransform;
|
|
46
|
+
#endif
|
|
47
|
+
#ifdef UV_DISTORTION
|
|
48
|
+
uniform sampler2D distortionMap;
|
|
49
|
+
uniform vec4 distortionTransform;
|
|
50
|
+
uniform float distortionStrength;
|
|
51
|
+
#endif
|
|
52
|
+
#ifdef GRADIENT_MAP
|
|
53
|
+
uniform sampler2D gradientMap;
|
|
54
|
+
uniform vec2 gradientMapRange;
|
|
55
|
+
uniform vec4 gradientMapChannel;
|
|
56
|
+
#endif
|
|
57
|
+
#ifdef EROSION
|
|
58
|
+
uniform vec2 erosionParams;
|
|
59
|
+
uniform vec3 erosionEdgeColor;
|
|
60
|
+
#ifdef EROSION_MASK
|
|
61
|
+
uniform sampler2D erosionMask;
|
|
62
|
+
uniform vec4 erosionMaskTransform;
|
|
63
|
+
#endif
|
|
64
|
+
|
|
65
|
+
vec4 quarksErode(vec4 color, float level, float mask) {
|
|
66
|
+
float softness = erosionParams.x;
|
|
67
|
+
float edgeWidth = erosionParams.y;
|
|
68
|
+
// At level 1 the cut sits below the lowest mask value by the soft band
|
|
69
|
+
// and the edge band, so nothing is cut and no edge shows; at level 0 above
|
|
70
|
+
// the highest. The edge then grows in as the cut rises, rather than popping.
|
|
71
|
+
float cut = mix(-(softness + edgeWidth), 1.0, 1.0 - level);
|
|
72
|
+
float visible = smoothstep(cut, cut + softness, mask);
|
|
73
|
+
if (edgeWidth > 0.0) {
|
|
74
|
+
float edge = 1.0 - smoothstep(cut + softness, cut + softness + edgeWidth, mask);
|
|
75
|
+
color.rgb += erosionEdgeColor * edge;
|
|
76
|
+
}
|
|
77
|
+
color.a *= visible;
|
|
78
|
+
return color;
|
|
79
|
+
}
|
|
80
|
+
#endif
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Declares `baseColor` from `vColor` and the map, with the effects applied,
|
|
85
|
+
* GLSL. `tileBlend` adds the second tile of `TILE_BLEND`.
|
|
86
|
+
*/
|
|
87
|
+
export function surfaceColorGLSL(tileBlend: boolean): string {
|
|
88
|
+
return /* glsl */ `
|
|
89
|
+
vec4 baseColor = vColor;
|
|
90
|
+
#if defined(MAP_TRANSFORM) && defined(MAP_UV1)
|
|
91
|
+
vec2 mapUV = vUV1 * mapTransform.xy + mapTransform.zw;
|
|
92
|
+
#elif defined(MAP_TRANSFORM)
|
|
93
|
+
vec2 mapUV = vUV * mapTransform.xy + mapTransform.zw;
|
|
94
|
+
#else
|
|
95
|
+
vec2 mapUV = vUV;
|
|
96
|
+
#endif
|
|
97
|
+
#ifdef UV_DISTORTION
|
|
98
|
+
#ifdef UV_DISTORTION_UV1
|
|
99
|
+
vec2 distortionUV = vUV1;
|
|
100
|
+
#else
|
|
101
|
+
vec2 distortionUV = vUV;
|
|
102
|
+
#endif
|
|
103
|
+
vec2 distortion = (texture2D(distortionMap, distortionUV * distortionTransform.xy + distortionTransform.zw).rg - 0.5) * 2.0 * distortionStrength;
|
|
104
|
+
mapUV += distortion;
|
|
105
|
+
#endif
|
|
106
|
+
#ifdef EROSION
|
|
107
|
+
float erosionLevel = baseColor.a;
|
|
108
|
+
baseColor.a = 1.0;
|
|
109
|
+
float erosionMaskValue = 1.0;
|
|
110
|
+
#endif
|
|
111
|
+
#ifdef USE_MAP
|
|
112
|
+
vec4 texColor = texture2D(map, mapUV);
|
|
113
|
+
${
|
|
114
|
+
tileBlend
|
|
115
|
+
? `#ifdef TILE_BLEND
|
|
116
|
+
#if defined(MAP_TRANSFORM) && defined(MAP_UV1)
|
|
117
|
+
vec2 mapUV2 = mapUV;
|
|
118
|
+
#else
|
|
119
|
+
#ifdef MAP_TRANSFORM
|
|
120
|
+
vec2 mapUV2 = vUV2 * mapTransform.xy + mapTransform.zw;
|
|
121
|
+
#else
|
|
122
|
+
vec2 mapUV2 = vUV2;
|
|
123
|
+
#endif
|
|
124
|
+
#ifdef UV_DISTORTION
|
|
125
|
+
mapUV2 += distortion;
|
|
126
|
+
#endif
|
|
127
|
+
#endif
|
|
128
|
+
vec4 texColor2 = texture2D(map, mapUV2);
|
|
129
|
+
texColor = mix(texColor, texColor2, vTileBlend);
|
|
130
|
+
#endif`
|
|
131
|
+
: ''
|
|
132
|
+
}
|
|
133
|
+
#ifdef GRADIENT_MAP
|
|
134
|
+
float rampAt = clamp(dot(texColor, gradientMapChannel), 0.0, 1.0);
|
|
135
|
+
vec4 ramp = texture2D(gradientMap, vec2(mix(gradientMapRange.x, gradientMapRange.y, rampAt), 0.5));
|
|
136
|
+
texColor = vec4(ramp.rgb, ramp.a * mix(texColor.a, 1.0, gradientMapChannel.a));
|
|
137
|
+
#endif
|
|
138
|
+
#ifdef EROSION
|
|
139
|
+
erosionMaskValue = texColor.a;
|
|
140
|
+
#endif
|
|
141
|
+
baseColor *= texColor;
|
|
142
|
+
#endif
|
|
143
|
+
#ifdef EROSION
|
|
144
|
+
#ifdef EROSION_MASK
|
|
145
|
+
#ifdef EROSION_MASK_UV1
|
|
146
|
+
vec2 erosionUV = vUV1;
|
|
147
|
+
#else
|
|
148
|
+
vec2 erosionUV = vUV;
|
|
149
|
+
#endif
|
|
150
|
+
erosionMaskValue = texture2D(erosionMask, erosionUV * erosionMaskTransform.xy + erosionMaskTransform.zw).r;
|
|
151
|
+
#endif
|
|
152
|
+
baseColor = quarksErode(baseColor, erosionLevel, erosionMaskValue);
|
|
153
|
+
#endif
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Fragment-side declarations, WGSL. */
|
|
158
|
+
export const surfaceFragmentDeclarationWGSL = /* wgsl */ `
|
|
159
|
+
#ifdef MAP_TRANSFORM
|
|
160
|
+
uniform mapTransform: vec4f;
|
|
161
|
+
#endif
|
|
162
|
+
#ifdef UV_DISTORTION
|
|
163
|
+
var distortionMapSampler: sampler;
|
|
164
|
+
var distortionMap: texture_2d<f32>;
|
|
165
|
+
uniform distortionTransform: vec4f;
|
|
166
|
+
uniform distortionStrength: f32;
|
|
167
|
+
#endif
|
|
168
|
+
#ifdef GRADIENT_MAP
|
|
169
|
+
var gradientMapSampler: sampler;
|
|
170
|
+
var gradientMap: texture_2d<f32>;
|
|
171
|
+
uniform gradientMapRange: vec2f;
|
|
172
|
+
uniform gradientMapChannel: vec4f;
|
|
173
|
+
#endif
|
|
174
|
+
#ifdef EROSION
|
|
175
|
+
uniform erosionParams: vec2f;
|
|
176
|
+
uniform erosionEdgeColor: vec3f;
|
|
177
|
+
#ifdef EROSION_MASK
|
|
178
|
+
var erosionMaskSampler: sampler;
|
|
179
|
+
var erosionMask: texture_2d<f32>;
|
|
180
|
+
uniform erosionMaskTransform: vec4f;
|
|
181
|
+
#endif
|
|
182
|
+
|
|
183
|
+
fn quarksErode(colorIn: vec4f, level: f32, mask: f32) -> vec4f {
|
|
184
|
+
var color = colorIn;
|
|
185
|
+
let softness = uniforms.erosionParams.x;
|
|
186
|
+
let edgeWidth = uniforms.erosionParams.y;
|
|
187
|
+
let cut = mix(-(softness + edgeWidth), 1.0, 1.0 - level);
|
|
188
|
+
let visible = smoothstep(cut, cut + softness, mask);
|
|
189
|
+
if (edgeWidth > 0.0) {
|
|
190
|
+
let edge = 1.0 - smoothstep(cut + softness, cut + softness + edgeWidth, mask);
|
|
191
|
+
color = vec4f(color.rgb + uniforms.erosionEdgeColor * edge, color.a);
|
|
192
|
+
}
|
|
193
|
+
color.a *= visible;
|
|
194
|
+
return color;
|
|
195
|
+
}
|
|
196
|
+
#endif
|
|
197
|
+
`;
|
|
198
|
+
|
|
199
|
+
/** Declares `baseColor` from `vColor` and the map, with the effects applied, WGSL. */
|
|
200
|
+
export function surfaceColorWGSL(tileBlend: boolean): string {
|
|
201
|
+
return /* wgsl */ `
|
|
202
|
+
var baseColor = fragmentInputs.vColor;
|
|
203
|
+
#if defined(MAP_TRANSFORM) && defined(MAP_UV1)
|
|
204
|
+
var mapUV = fragmentInputs.vUV1 * uniforms.mapTransform.xy + uniforms.mapTransform.zw;
|
|
205
|
+
#elif defined(MAP_TRANSFORM)
|
|
206
|
+
var mapUV = fragmentInputs.vUV * uniforms.mapTransform.xy + uniforms.mapTransform.zw;
|
|
207
|
+
#else
|
|
208
|
+
var mapUV = fragmentInputs.vUV;
|
|
209
|
+
#endif
|
|
210
|
+
#ifdef UV_DISTORTION
|
|
211
|
+
#ifdef UV_DISTORTION_UV1
|
|
212
|
+
let distortionUV = fragmentInputs.vUV1;
|
|
213
|
+
#else
|
|
214
|
+
let distortionUV = fragmentInputs.vUV;
|
|
215
|
+
#endif
|
|
216
|
+
let distortion = (textureSample(distortionMap, distortionMapSampler, distortionUV * uniforms.distortionTransform.xy + uniforms.distortionTransform.zw).rg - 0.5) * 2.0 * uniforms.distortionStrength;
|
|
217
|
+
mapUV += distortion;
|
|
218
|
+
#endif
|
|
219
|
+
#ifdef EROSION
|
|
220
|
+
let erosionLevel = baseColor.a;
|
|
221
|
+
baseColor.a = 1.0;
|
|
222
|
+
var erosionMaskValue = 1.0;
|
|
223
|
+
#endif
|
|
224
|
+
#ifdef USE_MAP
|
|
225
|
+
var texColor = textureSample(map, mapSampler, mapUV);
|
|
226
|
+
${
|
|
227
|
+
tileBlend
|
|
228
|
+
? `#ifdef TILE_BLEND
|
|
229
|
+
#if defined(MAP_TRANSFORM) && defined(MAP_UV1)
|
|
230
|
+
let mapUV2 = mapUV;
|
|
231
|
+
#else
|
|
232
|
+
#ifdef MAP_TRANSFORM
|
|
233
|
+
var mapUV2 = fragmentInputs.vUV2 * uniforms.mapTransform.xy + uniforms.mapTransform.zw;
|
|
234
|
+
#else
|
|
235
|
+
var mapUV2 = fragmentInputs.vUV2;
|
|
236
|
+
#endif
|
|
237
|
+
#ifdef UV_DISTORTION
|
|
238
|
+
mapUV2 += distortion;
|
|
239
|
+
#endif
|
|
240
|
+
#endif
|
|
241
|
+
let texColor2 = textureSample(map, mapSampler, mapUV2);
|
|
242
|
+
texColor = mix(texColor, texColor2, fragmentInputs.vTileBlend);
|
|
243
|
+
#endif`
|
|
244
|
+
: ''
|
|
245
|
+
}
|
|
246
|
+
#ifdef GRADIENT_MAP
|
|
247
|
+
let rampAt = clamp(dot(texColor, uniforms.gradientMapChannel), 0.0, 1.0);
|
|
248
|
+
let ramp = textureSample(gradientMap, gradientMapSampler, vec2f(mix(uniforms.gradientMapRange.x, uniforms.gradientMapRange.y, rampAt), 0.5));
|
|
249
|
+
texColor = vec4f(ramp.rgb, ramp.a * mix(texColor.a, 1.0, uniforms.gradientMapChannel.a));
|
|
250
|
+
#endif
|
|
251
|
+
#ifdef EROSION
|
|
252
|
+
erosionMaskValue = texColor.a;
|
|
253
|
+
#endif
|
|
254
|
+
baseColor *= texColor;
|
|
255
|
+
#endif
|
|
256
|
+
#ifdef EROSION
|
|
257
|
+
#ifdef EROSION_MASK
|
|
258
|
+
#ifdef EROSION_MASK_UV1
|
|
259
|
+
let erosionUV = fragmentInputs.vUV1;
|
|
260
|
+
#else
|
|
261
|
+
let erosionUV = fragmentInputs.vUV;
|
|
262
|
+
#endif
|
|
263
|
+
erosionMaskValue = textureSample(erosionMask, erosionMaskSampler, erosionUV * uniforms.erosionMaskTransform.xy + uniforms.erosionMaskTransform.zw).r;
|
|
264
|
+
#endif
|
|
265
|
+
baseColor = quarksErode(baseColor, erosionLevel, erosionMaskValue);
|
|
266
|
+
#endif
|
|
267
|
+
`;
|
|
268
|
+
}
|
|
@@ -21,6 +21,14 @@ uniform float tileCountY;
|
|
|
21
21
|
|
|
22
22
|
varying vec2 vUV;
|
|
23
23
|
varying vec4 vColor;
|
|
24
|
+
#ifdef UV1
|
|
25
|
+
#ifdef MESH_UV2
|
|
26
|
+
// The mesh's second UV set.
|
|
27
|
+
attribute vec2 uv2;
|
|
28
|
+
#endif
|
|
29
|
+
// UV channel 1: the mesh's second UV set, or its first when it has none.
|
|
30
|
+
varying vec2 vUV1;
|
|
31
|
+
#endif
|
|
24
32
|
varying vec3 vNormal;
|
|
25
33
|
varying vec3 vWorldPos;
|
|
26
34
|
|
|
@@ -78,6 +86,13 @@ ${fogVertexGLSL('viewPos.xyz')}
|
|
|
78
86
|
vUV = uv;
|
|
79
87
|
#endif
|
|
80
88
|
|
|
89
|
+
#ifdef UV1
|
|
90
|
+
#ifdef MESH_UV2
|
|
91
|
+
vUV1 = uv2;
|
|
92
|
+
#else
|
|
93
|
+
vUV1 = uv;
|
|
94
|
+
#endif
|
|
95
|
+
#endif
|
|
81
96
|
vColor = color;
|
|
82
97
|
}
|
|
83
98
|
`;
|
|
@@ -21,6 +21,14 @@ uniform tileCountY: f32;
|
|
|
21
21
|
|
|
22
22
|
varying vUV: vec2f;
|
|
23
23
|
varying vColor: vec4f;
|
|
24
|
+
#ifdef UV1
|
|
25
|
+
#ifdef MESH_UV2
|
|
26
|
+
// The mesh's second UV set.
|
|
27
|
+
attribute uv2: vec2f;
|
|
28
|
+
#endif
|
|
29
|
+
// UV channel 1: the mesh's second UV set, or its first when it has none.
|
|
30
|
+
varying vUV1: vec2f;
|
|
31
|
+
#endif
|
|
24
32
|
varying vNormal: vec3f;
|
|
25
33
|
varying vWorldPos: vec3f;
|
|
26
34
|
|
|
@@ -80,6 +88,13 @@ ${fogVertexWGSL('viewPos.xyz')}
|
|
|
80
88
|
vertexOutputs.vUV = vertexInputs.uv;
|
|
81
89
|
#endif
|
|
82
90
|
|
|
91
|
+
#ifdef UV1
|
|
92
|
+
#ifdef MESH_UV2
|
|
93
|
+
vertexOutputs.vUV1 = vertexInputs.uv2;
|
|
94
|
+
#else
|
|
95
|
+
vertexOutputs.vUV1 = vertexInputs.uv;
|
|
96
|
+
#endif
|
|
97
|
+
#endif
|
|
83
98
|
vertexOutputs.vColor = vertexInputs.color;
|
|
84
99
|
}
|
|
85
100
|
`;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import {fogFragmentDeclarationGLSL, fogFragmentGLSL} from './chunks/fog';
|
|
2
|
+
import {surfaceColorGLSL, surfaceFragmentDeclarationGLSL} from './chunks/surface';
|
|
2
3
|
|
|
3
4
|
export default /* glsl */ `
|
|
4
5
|
varying vec2 vUV;
|
|
5
6
|
varying vec4 vColor;
|
|
7
|
+
#ifdef UV1
|
|
8
|
+
varying vec2 vUV1;
|
|
9
|
+
#endif
|
|
6
10
|
|
|
7
11
|
#ifdef TILE_BLEND
|
|
8
12
|
varying vec2 vUV2;
|
|
@@ -26,18 +30,9 @@ uniform float alphaTest;
|
|
|
26
30
|
#endif
|
|
27
31
|
|
|
28
32
|
${fogFragmentDeclarationGLSL}
|
|
33
|
+
${surfaceFragmentDeclarationGLSL}
|
|
29
34
|
void main() {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
#ifdef USE_MAP
|
|
33
|
-
vec4 texColor = texture2D(map, vUV);
|
|
34
|
-
#ifdef TILE_BLEND
|
|
35
|
-
vec4 texColor2 = texture2D(map, vUV2);
|
|
36
|
-
texColor = mix(texColor, texColor2, vTileBlend);
|
|
37
|
-
#endif
|
|
38
|
-
baseColor *= texColor;
|
|
39
|
-
#endif
|
|
40
|
-
|
|
35
|
+
${surfaceColorGLSL(true)}
|
|
41
36
|
#ifdef USE_COLOR_AS_ALPHA
|
|
42
37
|
baseColor.a *= (baseColor.r + baseColor.g + baseColor.b) / 3.0;
|
|
43
38
|
#endif
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import {fogFragmentDeclarationWGSL, fogFragmentWGSL} from './chunks/fog';
|
|
2
|
+
import {surfaceColorWGSL, surfaceFragmentDeclarationWGSL} from './chunks/surface';
|
|
2
3
|
|
|
3
4
|
export default /* wgsl */ `
|
|
4
5
|
varying vUV: vec2f;
|
|
5
6
|
varying vColor: vec4f;
|
|
7
|
+
#ifdef UV1
|
|
8
|
+
varying vUV1: vec2f;
|
|
9
|
+
#endif
|
|
6
10
|
|
|
7
11
|
#ifdef TILE_BLEND
|
|
8
12
|
varying vUV2: vec2f;
|
|
@@ -28,19 +32,10 @@ uniform alphaTest: f32;
|
|
|
28
32
|
#endif
|
|
29
33
|
|
|
30
34
|
${fogFragmentDeclarationWGSL}
|
|
35
|
+
${surfaceFragmentDeclarationWGSL}
|
|
31
36
|
@fragment
|
|
32
37
|
fn main(input: FragmentInputs) -> FragmentOutputs {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
#ifdef USE_MAP
|
|
36
|
-
var texColor = textureSample(map, mapSampler, fragmentInputs.vUV);
|
|
37
|
-
#ifdef TILE_BLEND
|
|
38
|
-
let texColor2 = textureSample(map, mapSampler, fragmentInputs.vUV2);
|
|
39
|
-
texColor = mix(texColor, texColor2, fragmentInputs.vTileBlend);
|
|
40
|
-
#endif
|
|
41
|
-
baseColor *= texColor;
|
|
42
|
-
#endif
|
|
43
|
-
|
|
38
|
+
${surfaceColorWGSL(true)}
|
|
44
39
|
#ifdef USE_COLOR_AS_ALPHA
|
|
45
40
|
baseColor.a *= (baseColor.r + baseColor.g + baseColor.b) / 3.0;
|
|
46
41
|
#endif
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import {fogFragmentDeclarationGLSL, fogFragmentGLSL} from './chunks/fog';
|
|
2
|
+
import {surfaceColorGLSL, surfaceFragmentDeclarationGLSL} from './chunks/surface';
|
|
2
3
|
|
|
3
4
|
export default /* glsl */ `
|
|
4
5
|
varying vec2 vUV;
|
|
5
6
|
varying vec4 vColor;
|
|
7
|
+
#ifdef UV1
|
|
8
|
+
varying vec2 vUV1;
|
|
9
|
+
#endif
|
|
6
10
|
varying vec3 vNormal;
|
|
7
11
|
varying vec3 vWorldPos;
|
|
8
12
|
|
|
@@ -88,18 +92,9 @@ uniform float alphaTest;
|
|
|
88
92
|
#endif
|
|
89
93
|
|
|
90
94
|
${fogFragmentDeclarationGLSL}
|
|
95
|
+
${surfaceFragmentDeclarationGLSL}
|
|
91
96
|
void main() {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
#ifdef USE_MAP
|
|
95
|
-
vec4 texColor = texture2D(map, vUV);
|
|
96
|
-
#ifdef TILE_BLEND
|
|
97
|
-
vec4 texColor2 = texture2D(map, vUV2);
|
|
98
|
-
texColor = mix(texColor, texColor2, vTileBlend);
|
|
99
|
-
#endif
|
|
100
|
-
baseColor *= texColor;
|
|
101
|
-
#endif
|
|
102
|
-
|
|
97
|
+
${surfaceColorGLSL(true)}
|
|
103
98
|
#ifdef USE_ALPHATEST
|
|
104
99
|
if (baseColor.a < alphaTest) discard;
|
|
105
100
|
#else
|
|
@@ -126,11 +121,14 @@ void main() {
|
|
|
126
121
|
#ifdef MESH_RIM
|
|
127
122
|
// Fresnel: strongest where the surface turns away from the camera.
|
|
128
123
|
vec3 V = normalize(eyePosition - vWorldPos);
|
|
129
|
-
float
|
|
130
|
-
#
|
|
131
|
-
|
|
124
|
+
float edgeTerm = pow(1.0 - abs(dot(N, V)), rimParams.x);
|
|
125
|
+
#if defined(MESH_RIM_FADE)
|
|
126
|
+
// Faces turned to the camera fade by the strength; edges stay.
|
|
127
|
+
baseColor.a *= clamp(1.0 - rimParams.y * (1.0 - edgeTerm), 0.0, 1.0);
|
|
128
|
+
#elif defined(MESH_RIM_MIX)
|
|
129
|
+
color = mix(color, rimColor, clamp(edgeTerm * rimParams.y, 0.0, 1.0));
|
|
132
130
|
#else
|
|
133
|
-
color += rimColor *
|
|
131
|
+
color += rimColor * edgeTerm * rimParams.y;
|
|
134
132
|
#endif
|
|
135
133
|
#endif
|
|
136
134
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import {fogFragmentDeclarationWGSL, fogFragmentWGSL} from './chunks/fog';
|
|
2
|
+
import {surfaceColorWGSL, surfaceFragmentDeclarationWGSL} from './chunks/surface';
|
|
2
3
|
|
|
3
4
|
export default /* wgsl */ `
|
|
4
5
|
varying vUV: vec2f;
|
|
5
6
|
varying vColor: vec4f;
|
|
7
|
+
#ifdef UV1
|
|
8
|
+
varying vUV1: vec2f;
|
|
9
|
+
#endif
|
|
6
10
|
varying vNormal: vec3f;
|
|
7
11
|
varying vWorldPos: vec3f;
|
|
8
12
|
|
|
@@ -88,19 +92,10 @@ uniform alphaTest: f32;
|
|
|
88
92
|
#endif
|
|
89
93
|
|
|
90
94
|
${fogFragmentDeclarationWGSL}
|
|
95
|
+
${surfaceFragmentDeclarationWGSL}
|
|
91
96
|
@fragment
|
|
92
97
|
fn main(input: FragmentInputs) -> FragmentOutputs {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
#ifdef USE_MAP
|
|
96
|
-
var texColor = textureSample(map, mapSampler, fragmentInputs.vUV);
|
|
97
|
-
#ifdef TILE_BLEND
|
|
98
|
-
let texColor2 = textureSample(map, mapSampler, fragmentInputs.vUV2);
|
|
99
|
-
texColor = mix(texColor, texColor2, fragmentInputs.vTileBlend);
|
|
100
|
-
#endif
|
|
101
|
-
baseColor *= texColor;
|
|
102
|
-
#endif
|
|
103
|
-
|
|
98
|
+
${surfaceColorWGSL(true)}
|
|
104
99
|
#ifdef USE_ALPHATEST
|
|
105
100
|
if (baseColor.a < uniforms.alphaTest) { discard; }
|
|
106
101
|
#else
|
|
@@ -127,11 +122,14 @@ fn main(input: FragmentInputs) -> FragmentOutputs {
|
|
|
127
122
|
#ifdef MESH_RIM
|
|
128
123
|
// Fresnel: strongest where the surface turns away from the camera.
|
|
129
124
|
let V = normalize(uniforms.eyePosition - fragmentInputs.vWorldPos);
|
|
130
|
-
let
|
|
131
|
-
#
|
|
132
|
-
|
|
125
|
+
let edgeTerm = pow(1.0 - abs(dot(N, V)), uniforms.rimParams.x);
|
|
126
|
+
#if defined(MESH_RIM_FADE)
|
|
127
|
+
// Faces turned to the camera fade by the strength; edges stay.
|
|
128
|
+
baseColor.a *= clamp(1.0 - uniforms.rimParams.y * (1.0 - edgeTerm), 0.0, 1.0);
|
|
129
|
+
#elif defined(MESH_RIM_MIX)
|
|
130
|
+
color = mix(color, uniforms.rimColor, clamp(edgeTerm * uniforms.rimParams.y, 0.0, 1.0));
|
|
133
131
|
#else
|
|
134
|
-
color += uniforms.rimColor *
|
|
132
|
+
color += uniforms.rimColor * edgeTerm * uniforms.rimParams.y;
|
|
135
133
|
#endif
|
|
136
134
|
#endif
|
|
137
135
|
|
|
@@ -31,6 +31,10 @@ uniform vec3 pivot;
|
|
|
31
31
|
// Varyings
|
|
32
32
|
varying vec2 vUV;
|
|
33
33
|
varying vec4 vColor;
|
|
34
|
+
#ifdef UV1
|
|
35
|
+
// The particle's own UV, never moved by the sheet (UV channel 1).
|
|
36
|
+
varying vec2 vUV1;
|
|
37
|
+
#endif
|
|
34
38
|
#ifdef TILE_BLEND
|
|
35
39
|
varying vec2 vUV2;
|
|
36
40
|
varying float vTileBlend;
|
|
@@ -119,6 +123,9 @@ ${fogVertexGLSL('mvPosition.xyz')}
|
|
|
119
123
|
vUV = uv;
|
|
120
124
|
#endif
|
|
121
125
|
|
|
126
|
+
#ifdef UV1
|
|
127
|
+
vUV1 = uv;
|
|
128
|
+
#endif
|
|
122
129
|
vColor = color;
|
|
123
130
|
}
|
|
124
131
|
`;
|
|
@@ -30,6 +30,10 @@ uniform pivot: vec3f;
|
|
|
30
30
|
// Varyings
|
|
31
31
|
varying vUV: vec2f;
|
|
32
32
|
varying vColor: vec4f;
|
|
33
|
+
#ifdef UV1
|
|
34
|
+
// The particle's own UV, never moved by the sheet (UV channel 1).
|
|
35
|
+
varying vUV1: vec2f;
|
|
36
|
+
#endif
|
|
33
37
|
#ifdef TILE_BLEND
|
|
34
38
|
varying vUV2: vec2f;
|
|
35
39
|
varying vTileBlend: f32;
|
|
@@ -121,6 +125,9 @@ ${fogVertexWGSL('mvPosition.xyz')}
|
|
|
121
125
|
vertexOutputs.vUV = vertexInputs.uv;
|
|
122
126
|
#endif
|
|
123
127
|
|
|
128
|
+
#ifdef UV1
|
|
129
|
+
vertexOutputs.vUV1 = vertexInputs.uv;
|
|
130
|
+
#endif
|
|
124
131
|
vertexOutputs.vColor = vertexInputs.color;
|
|
125
132
|
}
|
|
126
133
|
`;
|
|
@@ -32,6 +32,10 @@ uniform vec3 pivot;
|
|
|
32
32
|
// Varyings
|
|
33
33
|
varying vec2 vUV;
|
|
34
34
|
varying vec4 vColor;
|
|
35
|
+
#ifdef UV1
|
|
36
|
+
// The particle's own UV, never moved by the sheet (UV channel 1).
|
|
37
|
+
varying vec2 vUV1;
|
|
38
|
+
#endif
|
|
35
39
|
#ifdef TILE_BLEND
|
|
36
40
|
varying vec2 vUV2;
|
|
37
41
|
varying float vTileBlend;
|
|
@@ -45,6 +49,7 @@ varying float linearDepth;
|
|
|
45
49
|
// Smallest and largest size a particle may have on screen, as fractions of the viewport height.
|
|
46
50
|
uniform vec2 sizeLimits;
|
|
47
51
|
#endif
|
|
52
|
+
|
|
48
53
|
${fogVertexDeclarationGLSL}
|
|
49
54
|
void main() {
|
|
50
55
|
float lengthFactor = velocity.w;
|
|
@@ -52,6 +57,19 @@ void main() {
|
|
|
52
57
|
// extent and mirrors its texture instead (see quadUV below).
|
|
53
58
|
float avgSize = (abs(size.x) + abs(size.y)) * 0.5;
|
|
54
59
|
vec4 mvPosition = view * world * vec4(offset, 1.0);
|
|
60
|
+
vec3 viewVelocity = mat3(view * world) * velocity.xyz;
|
|
61
|
+
float vlength = length(viewVelocity);
|
|
62
|
+
// Stretch direction is the velocity direction; only a genuinely motionless particle has none.
|
|
63
|
+
// Deriving it via normalize keeps the stretch aligned even when the speed contribution is ~0
|
|
64
|
+
// (e.g. speedFactor 0), instead of collapsing the whole burst onto a fixed screen axis.
|
|
65
|
+
vec3 vdir = vlength > 0.000001 ? viewVelocity / vlength : vec3(0.0, 0.0, 1.0);
|
|
66
|
+
#ifdef BEAM
|
|
67
|
+
// Seen straight along its length a beam has no side to face; any will do.
|
|
68
|
+
vec3 sideRaw = cross(mvPosition.xyz, vdir);
|
|
69
|
+
vec3 side = dot(sideRaw, sideRaw) > 1e-12 ? normalize(sideRaw) : vec3(1.0, 0.0, 0.0);
|
|
70
|
+
#else
|
|
71
|
+
vec3 side = normalize(cross(mvPosition.xyz, vdir));
|
|
72
|
+
#endif
|
|
55
73
|
#ifdef SIZE_LIMITS
|
|
56
74
|
// The streak's width on screen as a fraction of the viewport height, held
|
|
57
75
|
// between the limits; a perspective projection divides by the view depth.
|
|
@@ -61,17 +79,16 @@ void main() {
|
|
|
61
79
|
avgSize *= clamp(screenSize, sizeLimits.x, sizeLimits.y) / screenSize;
|
|
62
80
|
}
|
|
63
81
|
#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
|
-
vec3 side = normalize(cross(mvPosition.xyz, vdir));
|
|
71
82
|
mvPosition.xyz += position.y * side * avgSize;
|
|
83
|
+
#ifdef BEAM
|
|
84
|
+
// The vector runs from the particle to the beam's end: the quad spans it
|
|
85
|
+
// exactly, U from the particle (0) to the end (1), as wide as the size.
|
|
86
|
+
mvPosition.xyz += (position.x + 0.5) * viewVelocity;
|
|
87
|
+
#else
|
|
72
88
|
// Equivalent to viewVelocity * (1.0 + lengthFactor / vlength) for moving particles, but the
|
|
73
89
|
// size-based term (vdir * lengthFactor) survives when the velocity contribution vanishes.
|
|
74
90
|
mvPosition.xyz -= (position.x + 0.5) * (viewVelocity + vdir * lengthFactor) * avgSize;
|
|
91
|
+
#endif
|
|
75
92
|
#ifdef PIVOT
|
|
76
93
|
// In particle-size units along the quad's own axes: x from head to tail, y across.
|
|
77
94
|
mvPosition.xyz += (pivot.y * side - pivot.x * vdir) * avgSize;
|
|
@@ -101,6 +118,9 @@ ${fogVertexGLSL('mvPosition.xyz')}
|
|
|
101
118
|
vUV = quadUV;
|
|
102
119
|
#endif
|
|
103
120
|
|
|
121
|
+
#ifdef UV1
|
|
122
|
+
vUV1 = quadUV;
|
|
123
|
+
#endif
|
|
104
124
|
vColor = color;
|
|
105
125
|
}
|
|
106
126
|
`;
|