@driftengine/core 4.9.0 → 4.10.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.json +62 -11
- package/README.md +43 -38
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -3
- package/dist/render/ambientHarmonics.d.ts +1 -1
- package/dist/render/ambientHarmonics.js +1 -1
- package/dist/render/areaLights.d.ts +4 -4
- package/dist/render/areaLights.js +1 -1
- package/dist/render/backend/api.d.ts +10 -3
- package/dist/render/backend/select.js +11 -5
- package/dist/render/backend/webgl2/boneAnimations.d.ts +29 -0
- package/dist/render/backend/webgl2/boneAnimations.js +80 -0
- package/dist/render/backend/webgl2/instanced.d.ts +5 -1
- package/dist/render/backend/webgl2/instanced.js +13 -1
- package/dist/render/backend/webgl2/renderer.d.ts +90 -2
- package/dist/render/backend/webgl2/renderer.js +253 -24
- package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +5 -3
- package/dist/render/backend/webgl2/skinPaletteTexture.js +6 -4
- package/dist/render/backend/webgpu/boneAnimations.d.ts +34 -0
- package/dist/render/backend/webgpu/boneAnimations.js +76 -0
- package/dist/render/backend/webgpu/buffers.d.ts +19 -4
- package/dist/render/backend/webgpu/buffers.js +18 -11
- package/dist/render/backend/webgpu/compressedUpload.d.ts +0 -1
- package/dist/render/backend/webgpu/compressedUpload.js +53 -8
- package/dist/render/backend/webgpu/depthPass.d.ts +59 -3
- package/dist/render/backend/webgpu/depthPass.js +49 -14
- package/dist/render/backend/webgpu/drawCommand.d.ts +18 -4
- package/dist/render/backend/webgpu/drawCommand.js +10 -3
- package/dist/render/backend/webgpu/flatPass.d.ts +85 -42
- package/dist/render/backend/webgpu/flatPass.js +136 -20
- package/dist/render/backend/webgpu/instanced.d.ts +14 -1
- package/dist/render/backend/webgpu/instanced.js +24 -1
- package/dist/render/backend/webgpu/materialStore.d.ts +101 -0
- package/dist/render/backend/webgpu/materialStore.js +265 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +6 -0
- package/dist/render/backend/webgpu/pipelineCache.js +7 -0
- package/dist/render/backend/webgpu/renderer.d.ts +152 -35
- package/dist/render/backend/webgpu/renderer.js +787 -142
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +7 -3
- package/dist/render/backend/webgpu/skinPaletteRing.js +13 -7
- package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +6 -0
- package/dist/render/backend/webgpu/skinPaletteTexture.js +7 -1
- package/dist/render/backend/webgpu/staticBundles.d.ts +125 -0
- package/dist/render/backend/webgpu/staticBundles.js +241 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +10 -3
- package/dist/render/backend/webgpu/surfaceTexturePass.js +20 -2
- package/dist/render/backend/webgpu/uniformRing.d.ts +21 -0
- package/dist/render/backend/webgpu/uniformRing.js +9 -1
- package/dist/render/bloomChain.d.ts +3 -3
- package/dist/render/boneAnimation.d.ts +92 -0
- package/dist/render/boneAnimation.js +133 -0
- package/dist/render/compressedSource.d.ts +33 -13
- package/dist/render/compressedSource.js +70 -25
- package/dist/render/glCompressed.js +83 -0
- package/dist/render/instances.d.ts +26 -0
- package/dist/render/lightBudget.d.ts +10 -0
- package/dist/render/lightBudget.js +10 -0
- package/dist/render/lightmap.d.ts +1 -1
- package/dist/render/mesh.d.ts +5 -0
- package/dist/render/mesh.js +6 -0
- package/dist/render/pointLightSelection.d.ts +4 -4
- package/dist/render/screenSpaceReflection.d.ts +2 -1
- package/dist/render/shaders/boneAnimation.d.ts +19 -0
- package/dist/render/shaders/boneAnimation.js +63 -0
- package/dist/render/shaders/depth.d.ts +7 -0
- package/dist/render/shaders/depth.js +35 -10
- package/dist/render/shaders/flat/index.d.ts +6 -0
- package/dist/render/shaders/flat/index.js +27 -5
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +15 -5
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/overlay.js +1 -1
- package/dist/render/shaders/flat/pointShadow.js +2 -2
- package/dist/render/shaders/flat/preamble.js +38 -24
- package/dist/render/shaders/generated/depth.wgsl.d.ts +93 -0
- package/dist/render/shaders/generated/depth.wgsl.js +93 -0
- package/dist/render/shaders/generated/flat.wgsl.d.ts +3077 -2903
- package/dist/render/shaders/generated/flat.wgsl.js +3100 -2925
- package/dist/render/shaders/outputTransform.d.ts +7 -0
- package/dist/render/shaders/outputTransform.js +28 -14
- package/dist/render/shaders/vertexChannel.d.ts +7 -0
- package/dist/render/shaders/vertexChannel.js +26 -0
- package/dist/render/staticDraws.d.ts +47 -0
- package/dist/render/staticDraws.js +43 -0
- package/dist/render/surfaceTexture.d.ts +38 -7
- package/dist/render/surfaceTexture.js +56 -17
- package/package.json +6 -6
- package/src/index.ts +8 -2
- package/src/render/ambientHarmonics.ts +1 -1
- package/src/render/areaLights.ts +4 -4
- package/src/render/backend/api.ts +13 -3
- package/src/render/backend/select.ts +10 -5
- package/src/render/backend/webgl2/boneAnimations.ts +105 -0
- package/src/render/backend/webgl2/instanced.ts +20 -1
- package/src/render/backend/webgl2/renderer.ts +315 -24
- package/src/render/backend/webgl2/skinPaletteTexture.ts +6 -4
- package/src/render/backend/webgpu/boneAnimations.ts +97 -0
- package/src/render/backend/webgpu/buffers.ts +42 -16
- package/src/render/backend/webgpu/compressedUpload.ts +59 -9
- package/src/render/backend/webgpu/depthPass.ts +51 -10
- package/src/render/backend/webgpu/drawCommand.ts +22 -4
- package/src/render/backend/webgpu/flatPass.ts +187 -14
- package/src/render/backend/webgpu/instanced.ts +32 -1
- package/src/render/backend/webgpu/materialStore.ts +276 -0
- package/src/render/backend/webgpu/pipelineCache.ts +7 -0
- package/src/render/backend/webgpu/renderer.ts +928 -155
- package/src/render/backend/webgpu/skinPaletteRing.ts +13 -7
- package/src/render/backend/webgpu/skinPaletteTexture.ts +7 -1
- package/src/render/backend/webgpu/staticBundles.ts +363 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +29 -3
- package/src/render/backend/webgpu/uniformRing.ts +10 -1
- package/src/render/bloomChain.ts +3 -3
- package/src/render/boneAnimation.ts +223 -0
- package/src/render/compressedSource.ts +121 -29
- package/src/render/glCompressed.ts +83 -0
- package/src/render/instances.ts +27 -0
- package/src/render/lightBudget.ts +11 -0
- package/src/render/lightmap.ts +1 -1
- package/src/render/mesh.ts +6 -0
- package/src/render/pointLightSelection.ts +4 -4
- package/src/render/screenSpaceReflection.ts +2 -1
- package/src/render/shaders/boneAnimation.ts +63 -0
- package/src/render/shaders/depth.ts +45 -10
- package/src/render/shaders/flat/index.ts +33 -5
- package/src/render/shaders/flat/main.ts +15 -5
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/overlay.ts +1 -1
- package/src/render/shaders/flat/pointShadow.ts +2 -2
- package/src/render/shaders/flat/preamble.ts +38 -24
- package/src/render/shaders/generated/depth.wgsl.ts +95 -0
- package/src/render/shaders/generated/flat.wgsl.ts +3100 -2925
- package/src/render/shaders/outputTransform.ts +30 -14
- package/src/render/shaders/vertexChannel.ts +27 -0
- package/src/render/staticDraws.ts +95 -0
- package/src/render/surfaceTexture.ts +94 -27
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vertex-stage bone animation: a crowd instance's vertex turned and placed by its bone, at its
|
|
3
|
+
* instance's moment of the clip — the GLSL of `boneAnimation.ts`'s `animateBoneVertex`, line for
|
|
4
|
+
* line. Shared by the lit stage and the depth stage, so a crowd's shadow moves with it.
|
|
5
|
+
*
|
|
6
|
+
* **Three textures, read by index and never filtered**: the places and the turns, a texel a bone a
|
|
7
|
+
* frame (bones across, frames down, sizes read with `textureSize` so no uniform says them), and the
|
|
8
|
+
* batch's clocks, two floats an instance wrapped onto rows, read at `gl_InstanceID`. The clip's speed
|
|
9
|
+
* and its bone scale are the one uniform, `uBoneClip`; the scene's time is the pass's `uSceneTime`.
|
|
10
|
+
*
|
|
11
|
+
* **The bone is read from the grain lane**, which is where a mesh's second coordinates ride, stored
|
|
12
|
+
* as `-1 - u` (`lightmap.ts`). An instanced batch reads no grain of its own from that lane: a crowd's
|
|
13
|
+
* mesh carries second coordinates, which is what makes it one.
|
|
14
|
+
*
|
|
15
|
+
* Integer arithmetic for the lattice, by the 2026-09-20 rule, except where a float is clamped onto
|
|
16
|
+
* it: the first frame is `min(floor(wrapped), frames - 1)`, so the wrap that division-by-reciprocal
|
|
17
|
+
* lands on `frames` is the last frame fully blended into the first — the first, which is right.
|
|
18
|
+
*/
|
|
19
|
+
export const BONE_ANIMATION_GLSL = `
|
|
20
|
+
uniform highp sampler2D uBonePlaces;
|
|
21
|
+
uniform highp sampler2D uBoneTurns;
|
|
22
|
+
uniform highp sampler2D uInstanceClocks;
|
|
23
|
+
/** x the clip's frames a second, y how many bones one unit of the second coordinates' u counts. */
|
|
24
|
+
uniform vec2 uBoneClip;
|
|
25
|
+
|
|
26
|
+
/** v turned by the unit quaternion q. */
|
|
27
|
+
vec3 boneTurn(vec4 q, vec3 v) {
|
|
28
|
+
return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Where the clip puts this vertex, from its place at rest; its normal and tangent turned with it.
|
|
33
|
+
*/
|
|
34
|
+
vec3 boneAnimate(vec3 position, inout vec3 normal, inout vec3 tangent) {
|
|
35
|
+
ivec2 size = textureSize(uBonePlaces, 0);
|
|
36
|
+
int clocksWidth = textureSize(uInstanceClocks, 0).x;
|
|
37
|
+
vec2 clock = texelFetch(
|
|
38
|
+
uInstanceClocks,
|
|
39
|
+
ivec2(gl_InstanceID % clocksWidth, gl_InstanceID / clocksWidth),
|
|
40
|
+
0
|
|
41
|
+
).xy;
|
|
42
|
+
float moment = (uSceneTime * clock.y + clock.x) * uBoneClip.x;
|
|
43
|
+
float frames = float(size.y);
|
|
44
|
+
float wrapped = moment - frames * floor(moment / frames);
|
|
45
|
+
int first = min(int(floor(wrapped)), size.y - 1);
|
|
46
|
+
int second = first + 1 == size.y ? 0 : first + 1;
|
|
47
|
+
float blend = clamp(wrapped - float(first), 0.0, 1.0);
|
|
48
|
+
int bone = clamp(int(floor((-1.0 - aGrain) * uBoneClip.y + 0.5)), 0, size.x - 1);
|
|
49
|
+
vec4 q0 = texelFetch(uBoneTurns, ivec2(bone, first), 0);
|
|
50
|
+
vec4 q1 = texelFetch(uBoneTurns, ivec2(bone, second), 0);
|
|
51
|
+
/* The shorter arc: a quaternion and its negation are one turn. */
|
|
52
|
+
if (dot(q0, q1) < 0.0) q1 = -q1;
|
|
53
|
+
vec4 q = normalize(mix(q0, q1, blend));
|
|
54
|
+
vec3 place = mix(
|
|
55
|
+
texelFetch(uBonePlaces, ivec2(bone, first), 0).xyz,
|
|
56
|
+
texelFetch(uBonePlaces, ivec2(bone, second), 0).xyz,
|
|
57
|
+
blend
|
|
58
|
+
);
|
|
59
|
+
normal = boneTurn(q, normal);
|
|
60
|
+
tangent = boneTurn(q, tangent);
|
|
61
|
+
return boneTurn(q, position) + place;
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
@@ -5,6 +5,7 @@ import { CUTOUT_DITHER_GLSL } from '../cutoutDither.ts';
|
|
|
5
5
|
import { SKINNING_GLSL } from './skinning.ts';
|
|
6
6
|
import { CLOTH_BINDING_GLSL } from './clothBinding.ts';
|
|
7
7
|
import { CHANNEL_ATTRIBUTE, CHANNEL_BEND } from './vertexChannel.ts';
|
|
8
|
+
import { BONE_ANIMATION_GLSL } from './boneAnimation.ts';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Depth-only shadow pass. Its optional peel mode rejects the first recorded
|
|
@@ -78,6 +79,17 @@ uniform vec2 uUvOffset;
|
|
|
78
79
|
uniform vec2 uAlphaCutout;
|
|
79
80
|
#endif
|
|
80
81
|
|
|
82
|
+
#if ANIMATED
|
|
83
|
+
/*
|
|
84
|
+
* **A bone animation's, after every other declaration** so no field of the variants before it
|
|
85
|
+
* moves: the grain lane the vertex's bone rides in, the scene's clock, and the chunk the colour
|
|
86
|
+
* pass runs — the same expression, or a crowd's shadow stands still while the crowd moves.
|
|
87
|
+
*/
|
|
88
|
+
layout(location = 8) in float aGrain;
|
|
89
|
+
uniform float uSceneTime;
|
|
90
|
+
${BONE_ANIMATION_GLSL}
|
|
91
|
+
#endif
|
|
92
|
+
|
|
81
93
|
out vec4 vLightPosition;
|
|
82
94
|
#if CUTOUT
|
|
83
95
|
/* The texture coordinate and, in z, the texture-array layer the face wears. */
|
|
@@ -99,6 +111,12 @@ void main() {
|
|
|
99
111
|
#else
|
|
100
112
|
vec4 local = vec4(aPosition, 1.0);
|
|
101
113
|
#endif
|
|
114
|
+
#if ANIMATED
|
|
115
|
+
/* Turned and placed as the colour pass turns and places it; its normal and tangent unused. */
|
|
116
|
+
vec3 animatedNormal = vec3(0.0, 1.0, 0.0);
|
|
117
|
+
vec3 animatedTangent = vec3(1.0, 0.0, 0.0);
|
|
118
|
+
local = vec4(boneAnimate(local.xyz, animatedNormal, animatedTangent), 1.0);
|
|
119
|
+
#endif
|
|
102
120
|
#if INSTANCED
|
|
103
121
|
mat4 model = mat4(aInstanceModel0, aInstanceModel1, aInstanceModel2, aInstanceModel3);
|
|
104
122
|
/* The bottom row is the instance's texture cell, rebuilt as the row it stands for: see flat. */
|
|
@@ -148,14 +166,14 @@ void main() {
|
|
|
148
166
|
/** The rigid variant: the world, a prop, a mesh with no rig behind it. */
|
|
149
167
|
export const DEPTH_VERT = resolveConditionals(
|
|
150
168
|
DEPTH_VERT_SOURCE,
|
|
151
|
-
{ SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: false },
|
|
169
|
+
{ SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: false, ANIMATED: false },
|
|
152
170
|
'depth',
|
|
153
171
|
);
|
|
154
172
|
|
|
155
173
|
/** The skinned variant, which reads a joint palette and moves the vertex by it. */
|
|
156
174
|
export const DEPTH_SKINNED_VERT = resolveConditionals(
|
|
157
175
|
DEPTH_VERT_SOURCE,
|
|
158
|
-
{ SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: false },
|
|
176
|
+
{ SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: false, ANIMATED: false },
|
|
159
177
|
'depth-skinned',
|
|
160
178
|
);
|
|
161
179
|
|
|
@@ -169,7 +187,7 @@ export const DEPTH_SKINNED_VERT = resolveConditionals(
|
|
|
169
187
|
*/
|
|
170
188
|
export const DEPTH_INSTANCED_VERT = resolveConditionals(
|
|
171
189
|
DEPTH_VERT_SOURCE,
|
|
172
|
-
{ SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false },
|
|
190
|
+
{ SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false, ANIMATED: false },
|
|
173
191
|
'depth-instanced',
|
|
174
192
|
);
|
|
175
193
|
|
|
@@ -185,16 +203,33 @@ export const DEPTH_INSTANCED_VERT = resolveConditionals(
|
|
|
185
203
|
*/
|
|
186
204
|
export const DEPTH_CUTOUT_VERT = resolveConditionals(
|
|
187
205
|
DEPTH_VERT_SOURCE,
|
|
188
|
-
{ SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: false },
|
|
206
|
+
{ SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: false, ANIMATED: false },
|
|
189
207
|
'depth-cutout',
|
|
190
208
|
);
|
|
191
209
|
|
|
192
210
|
export const DEPTH_INSTANCED_CUTOUT_VERT = resolveConditionals(
|
|
193
211
|
DEPTH_VERT_SOURCE,
|
|
194
|
-
{ SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false },
|
|
212
|
+
{ SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false, ANIMATED: false },
|
|
195
213
|
'depth-instanced-cutout',
|
|
196
214
|
);
|
|
197
215
|
|
|
216
|
+
/**
|
|
217
|
+
* The variants a crowd casts through: an instanced batch playing a bone animation, its vertices
|
|
218
|
+
* where the clip puts them at each instance's moment. See `shaders/boneAnimation.ts`. No glass
|
|
219
|
+
* variant: a crowd is not glass, and a glass batch that animates casts its tint from rest.
|
|
220
|
+
*/
|
|
221
|
+
export const DEPTH_INSTANCED_ANIMATED_VERT = resolveConditionals(
|
|
222
|
+
DEPTH_VERT_SOURCE,
|
|
223
|
+
{ SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: false, ANIMATED: true },
|
|
224
|
+
'depth-instanced-animated',
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
export const DEPTH_INSTANCED_ANIMATED_CUTOUT_VERT = resolveConditionals(
|
|
228
|
+
DEPTH_VERT_SOURCE,
|
|
229
|
+
{ SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: false, ANIMATED: true },
|
|
230
|
+
'depth-instanced-animated-cutout',
|
|
231
|
+
);
|
|
232
|
+
|
|
198
233
|
export const DEPTH_FRAG = `#version 300 es
|
|
199
234
|
precision highp float;
|
|
200
235
|
in vec4 vLightPosition;
|
|
@@ -269,27 +304,27 @@ void main() {
|
|
|
269
304
|
*/
|
|
270
305
|
export const GLASS_TINT_VERT = resolveConditionals(
|
|
271
306
|
DEPTH_VERT_SOURCE,
|
|
272
|
-
{ SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: true },
|
|
307
|
+
{ SKINNED: false, INSTANCED: false, CUTOUT: false, GLASS: true, ANIMATED: false },
|
|
273
308
|
'glass-tint',
|
|
274
309
|
);
|
|
275
310
|
export const GLASS_TINT_SKINNED_VERT = resolveConditionals(
|
|
276
311
|
DEPTH_VERT_SOURCE,
|
|
277
|
-
{ SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: true },
|
|
312
|
+
{ SKINNED: true, INSTANCED: false, CUTOUT: false, GLASS: true, ANIMATED: false },
|
|
278
313
|
'glass-tint-skinned',
|
|
279
314
|
);
|
|
280
315
|
export const GLASS_TINT_INSTANCED_VERT = resolveConditionals(
|
|
281
316
|
DEPTH_VERT_SOURCE,
|
|
282
|
-
{ SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: true },
|
|
317
|
+
{ SKINNED: false, INSTANCED: true, CUTOUT: false, GLASS: true, ANIMATED: false },
|
|
283
318
|
'glass-tint-instanced',
|
|
284
319
|
);
|
|
285
320
|
export const GLASS_TINT_CUTOUT_VERT = resolveConditionals(
|
|
286
321
|
DEPTH_VERT_SOURCE,
|
|
287
|
-
{ SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: true },
|
|
322
|
+
{ SKINNED: false, INSTANCED: false, CUTOUT: true, GLASS: true, ANIMATED: false },
|
|
288
323
|
'glass-tint-cutout',
|
|
289
324
|
);
|
|
290
325
|
export const GLASS_TINT_INSTANCED_CUTOUT_VERT = resolveConditionals(
|
|
291
326
|
DEPTH_VERT_SOURCE,
|
|
292
|
-
{ SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: true },
|
|
327
|
+
{ SKINNED: false, INSTANCED: true, CUTOUT: true, GLASS: true, ANIMATED: false },
|
|
293
328
|
'glass-tint-instanced-cutout',
|
|
294
329
|
);
|
|
295
330
|
|
|
@@ -21,7 +21,8 @@ import { DRIFT_LIGHT_GLSL } from './driftLight.ts';
|
|
|
21
21
|
import { SURFACE_EFFECTS_GLSL } from './surfaceEffects.ts';
|
|
22
22
|
import { overlayGlsl } from './overlay.ts';
|
|
23
23
|
import { reflectionSurfaceGlsl } from './reflectionSurface.ts';
|
|
24
|
-
import {
|
|
24
|
+
import { CHANNEL_BEND, LIT_CHANNEL_ATTRIBUTE } from '../vertexChannel.ts';
|
|
25
|
+
import { BONE_ANIMATION_GLSL } from '../boneAnimation.ts';
|
|
25
26
|
import { FULL_LIGHT_BUDGET, type LightBudget } from '../../uniformVectorBudget.ts';
|
|
26
27
|
|
|
27
28
|
/**
|
|
@@ -56,10 +57,16 @@ layout(location = 10) in vec4 aTangent;
|
|
|
56
57
|
${SKINNING_GLSL}
|
|
57
58
|
#endif
|
|
58
59
|
|
|
59
|
-
uniform mat4 uViewProj;
|
|
60
|
+
uniform mat4 uViewProj; // wgsl:view
|
|
60
61
|
/** 1 when the mesh carries a tangent frame. See vHasTangents. */
|
|
61
62
|
uniform int uHasTangents;
|
|
62
|
-
uniform mat4 uLightViewProj;
|
|
63
|
+
uniform mat4 uLightViewProj; // wgsl:view
|
|
64
|
+
/**
|
|
65
|
+
* The scene's clock, what \`setAnimationTime\` set: what a bone animation's instances read
|
|
66
|
+
* their moment from. In the view block, before the wind, so every variant's view block is the
|
|
67
|
+
* plain one's or a prefix of it — the instanced variant declares no wind and keeps this.
|
|
68
|
+
*/
|
|
69
|
+
uniform float uSceneTime; // wgsl:view
|
|
63
70
|
/**
|
|
64
71
|
* How often the surface texture repeats across this mesh's UV range, per axis.
|
|
65
72
|
*
|
|
@@ -122,6 +129,9 @@ layout(location = 15) in vec4 aInstanceTint;
|
|
|
122
129
|
* opacity of one. See lightmap.ts.
|
|
123
130
|
*/
|
|
124
131
|
const bool LIGHTMAP_REGIONS = false; // wgsl:override
|
|
132
|
+
#if ANIMATED
|
|
133
|
+
${BONE_ANIMATION_GLSL}
|
|
134
|
+
#endif
|
|
125
135
|
#else
|
|
126
136
|
uniform mat4 uModel;
|
|
127
137
|
/**
|
|
@@ -147,7 +157,7 @@ uniform vec3 uTint;
|
|
|
147
157
|
* agreeing about where the shared uniforms sit: the instanced variant drops these five along with
|
|
148
158
|
* the two above it, and a dropped field moves nothing. flatPass.ts asserts exactly that.
|
|
149
159
|
*/
|
|
150
|
-
${
|
|
160
|
+
${LIT_CHANNEL_ATTRIBUTE}
|
|
151
161
|
${CHANNEL_BEND}
|
|
152
162
|
#endif
|
|
153
163
|
|
|
@@ -245,6 +255,10 @@ void main() {
|
|
|
245
255
|
vec3 localNormal = aNormal;
|
|
246
256
|
vec3 localTangent = aTangent.xyz;
|
|
247
257
|
#endif
|
|
258
|
+
#if ANIMATED
|
|
259
|
+
/* The clip's turn and place, in the mesh's own space, before the instance places it. */
|
|
260
|
+
local = vec4(boneAnimate(local.xyz, localNormal, localTangent), 1.0);
|
|
261
|
+
#endif
|
|
248
262
|
#if INSTANCED
|
|
249
263
|
mat4 model = mat4(aInstanceModel0, aInstanceModel1, aInstanceModel2, aInstanceModel3);
|
|
250
264
|
/*
|
|
@@ -379,6 +393,12 @@ export interface FlatVertexOptions {
|
|
|
379
393
|
* Excludes `skinned`: the joint attributes and the instance matrix want the same locations.
|
|
380
394
|
*/
|
|
381
395
|
readonly instanced: boolean;
|
|
396
|
+
/**
|
|
397
|
+
* Whether an instanced variant follows a bone animation: \`shaders/boneAnimation.ts\`. A
|
|
398
|
+
* variant rather than a pipeline constant, because it declares three textures the other
|
|
399
|
+
* instanced pipelines would otherwise have to bind stand-ins for. Instanced only.
|
|
400
|
+
*/
|
|
401
|
+
readonly animated?: boolean;
|
|
382
402
|
}
|
|
383
403
|
|
|
384
404
|
/**
|
|
@@ -401,9 +421,17 @@ export function flatVert(options: FlatVertexOptions): string {
|
|
|
401
421
|
'so every instance of the batch would wear one expression between them.',
|
|
402
422
|
);
|
|
403
423
|
}
|
|
424
|
+
if (options.animated === true && !options.instanced) {
|
|
425
|
+
throw new Error('flatVert: a bone animation is played by an instanced variant alone.');
|
|
426
|
+
}
|
|
404
427
|
return resolveConditionals(
|
|
405
428
|
FLAT_VERT_SOURCE,
|
|
406
|
-
{
|
|
429
|
+
{
|
|
430
|
+
SKINNED: options.skinned,
|
|
431
|
+
MORPHED: options.morphed,
|
|
432
|
+
INSTANCED: options.instanced,
|
|
433
|
+
ANIMATED: options.animated === true,
|
|
434
|
+
},
|
|
407
435
|
'flatVert',
|
|
408
436
|
);
|
|
409
437
|
}
|
|
@@ -82,7 +82,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
82
82
|
*/
|
|
83
83
|
float share = cutoutShare(tested, uCutout.x);
|
|
84
84
|
if (uCutout.y == 1.0) {
|
|
85
|
-
if (!cutoutKeeps(share, gl_FragCoord.xy,
|
|
85
|
+
if (!cutoutKeeps(share, gl_FragCoord.xy, uHighlightMin.w)) discard;
|
|
86
86
|
kept = 1.0;
|
|
87
87
|
} else {
|
|
88
88
|
kept = share;
|
|
@@ -1281,7 +1281,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1281
1281
|
*/
|
|
1282
1282
|
float falloff;
|
|
1283
1283
|
/*
|
|
1284
|
-
* **A light may name its own falloff, and then it is
|
|
1284
|
+
* **A light may name its own falloff, and then it is the usual one for a light without
|
|
1285
1285
|
* inverse-square falloff**: \`(1 - (d/R)^2)^n\` with no distance term, so a fill authored to
|
|
1286
1286
|
* light a whole hall across a hundred metres does, where the inverse square would have it
|
|
1287
1287
|
* gone a few metres out. Zero is the frame's own rule below, which every light was before.
|
|
@@ -1997,7 +1997,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
1997
1997
|
// finishing a run reads the same at noon and at midnight. Costs one compare
|
|
1998
1998
|
// per fragment and no extra draw call — the box is a uniform, not geometry.
|
|
1999
1999
|
if (uHighlightMax.w > 0.0) {
|
|
2000
|
-
vec3 inside = step(uHighlightMin, vWorldPos) * step(vWorldPos, uHighlightMax.xyz);
|
|
2000
|
+
vec3 inside = step(uHighlightMin.xyz, vWorldPos) * step(vWorldPos, uHighlightMax.xyz);
|
|
2001
2001
|
lit += albedo * uHighlightMax.w * inside.x * inside.y * inside.z;
|
|
2002
2002
|
}
|
|
2003
2003
|
}
|
|
@@ -2101,7 +2101,17 @@ export const MAIN_GLSL = `void main() {
|
|
|
2101
2101
|
vec3 refractV = normalize(uCameraPos - vWorldPos);
|
|
2102
2102
|
ivec2 snapSize = textureSize(uRefractScene, 0);
|
|
2103
2103
|
vec2 screenUv = gl_FragCoord.xy / vec2(snapSize);
|
|
2104
|
-
|
|
2104
|
+
/*
|
|
2105
|
+
* **The normal's sideways part as the eye sees it**: the shading normal in view space, its x
|
|
2106
|
+
* and y across the screen, y turned to the way this frame's rows run (w of the tint). It was the
|
|
2107
|
+
* normal's world x and y until 4.10.0, which on a quad facing the camera is the quad's own lean
|
|
2108
|
+
* against the world's axes: one offset over the whole quad, a lens, with a normal map's tilt a
|
|
2109
|
+
* small change on top. In view space a quad facing the eye bends by nothing but its map, which
|
|
2110
|
+
* is a shimmer, and a pane bends by how it leans toward the eye wherever the eye stands.
|
|
2111
|
+
*/
|
|
2112
|
+
vec3 seenN = mat3(uView) * refractN;
|
|
2113
|
+
vec2 bend = vec2(seenN.x, seenN.y * uRefractTint.w);
|
|
2114
|
+
vec2 bent = clamp(screenUv + bend * uSeeThrough.x, vec2(0.0), vec2(1.0));
|
|
2105
2115
|
/*
|
|
2106
2116
|
* **An explicit level, and frost is what picks it** — the 2026-08-07 rule, and the reason a
|
|
2107
2117
|
* frosted pane blurs rather than fades: the copy carries a mip chain on a frame that draws glass,
|
|
@@ -2115,7 +2125,7 @@ export const MAIN_GLSL = `void main() {
|
|
|
2115
2125
|
/* Unsigned: a pane passes the same light seen from either side, and so does its Fresnel. */
|
|
2116
2126
|
float cosView = max(abs(dot(refractN, refractV)), 0.05);
|
|
2117
2127
|
float pathLength = uSeeThrough.y * vThickness / cosView;
|
|
2118
|
-
vec3 seen = behind * pow(uRefractTint, vec3(pathLength));
|
|
2128
|
+
vec3 seen = behind * pow(uRefractTint.rgb, vec3(pathLength));
|
|
2119
2129
|
if (glassTransmission > 0.0) {
|
|
2120
2130
|
/*
|
|
2121
2131
|
* **Glass keeps its own surface and shows what is behind over it**, by how much it lets
|
|
@@ -59,7 +59,7 @@ const bool PHYSICAL_SPECULAR = PHYSICAL_SPECULAR_ON; // wgsl:override
|
|
|
59
59
|
* A model's numbers, two vectors a material — the lit stage's uniform budget has no more room
|
|
60
60
|
* (surfaceModel.ts) — and whether a model map is bound, in the last component.
|
|
61
61
|
*/
|
|
62
|
-
uniform vec4 uModelParams[2];
|
|
62
|
+
uniform vec4 uModelParams[2]; // wgsl:material
|
|
63
63
|
/* The model's own channels, in the albedo's layout: what each means is each model's to say. */
|
|
64
64
|
uniform highp sampler2DArray uModelMap;
|
|
65
65
|
|
|
@@ -26,7 +26,7 @@ vec3 overlayGlow(vec2 uv, vec3 n) { return vec3(0.0); }
|
|
|
26
26
|
/* Whether this program carries a draw's overlay. Off but where one has been set: overlay.ts. */
|
|
27
27
|
const bool SURFACE_OVERLAY = true; // wgsl:override
|
|
28
28
|
/* The overlay's fifteen vectors; packSurfaceOverlay in surfaceOverlay.ts says what each holds. */
|
|
29
|
-
uniform vec4 uOverlay[15];
|
|
29
|
+
uniform vec4 uOverlay[15]; // wgsl:material
|
|
30
30
|
|
|
31
31
|
/* Whether the atlas is what the refraction slot holds: not where this draw refracts or is glass. */
|
|
32
32
|
bool overlayImagesBound() {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* picture and is its own change.
|
|
14
14
|
*/
|
|
15
15
|
import { MAX_SHADOW_FILTER_TAPS } from '../../renderQuality.ts';
|
|
16
|
-
import {
|
|
16
|
+
import { LIT_OUTPUT_TRANSFORM_GLSL } from '../outputTransform.ts';
|
|
17
17
|
import { LAMP_GLASS_GLSL } from './lampGlass.ts';
|
|
18
18
|
|
|
19
19
|
export const POINTSHADOW_GLSL = `/**
|
|
@@ -344,7 +344,7 @@ ${LAMP_GLASS_GLSL}
|
|
|
344
344
|
|
|
345
345
|
layout(location = 0) out vec4 outColor;
|
|
346
346
|
|
|
347
|
-
${
|
|
347
|
+
${LIT_OUTPUT_TRANSFORM_GLSL}
|
|
348
348
|
|
|
349
349
|
/**
|
|
350
350
|
* A fixed Poisson disk avoids the grid-shaped edge left by square 3x3 PCF.
|
|
@@ -121,9 +121,15 @@ uniform sampler2D uRefractScene;
|
|
|
121
121
|
* gives up, and four separate floats cost half the shadowed lights such a device can have. The tints
|
|
122
122
|
* stay colours of their own. Zero transmission is not glass — see glass.ts.
|
|
123
123
|
*/
|
|
124
|
-
uniform vec4 uSeeThrough;
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
uniform vec4 uSeeThrough; // wgsl:material
|
|
125
|
+
/*
|
|
126
|
+
* What a metre of the medium leaves of each channel (rgb), and in w which way this frame's rows run
|
|
127
|
+
* up the screen: +1 where the first row is the bottom (WebGL2), -1 where it is the top (WebGPU). The
|
|
128
|
+
* bend is taken in view space, whose y is up whatever the framebuffer says, so it is turned here to
|
|
129
|
+
* the rows a screen coordinate counts. A vec4 where a vec3 already spent the row.
|
|
130
|
+
*/
|
|
131
|
+
uniform vec4 uRefractTint; // wgsl:material
|
|
132
|
+
uniform vec3 uGlassTint; // wgsl:material
|
|
127
133
|
flat in int vHasTangents;
|
|
128
134
|
|
|
129
135
|
/**
|
|
@@ -154,7 +160,7 @@ uniform mediump sampler2DArray uAlbedo;
|
|
|
154
160
|
* card. Its draw culls nothing, and a back face is lit as a front, with the shading normal turned
|
|
155
161
|
* toward the viewer.
|
|
156
162
|
*/
|
|
157
|
-
uniform ivec4 uMaterialFlags;
|
|
163
|
+
uniform ivec4 uMaterialFlags; // wgsl:material
|
|
158
164
|
/**
|
|
159
165
|
* Alpha below which a textured fragment is thrown away entirely, 0 to disable.
|
|
160
166
|
*
|
|
@@ -168,13 +174,17 @@ uniform ivec4 uMaterialFlags;
|
|
|
168
174
|
* else changes.
|
|
169
175
|
*
|
|
170
176
|
* **Four numbers in one row**: x is the cutoff, y how this frame resolves the edge (0 the hard test,
|
|
171
|
-
* 1 a dither the temporal resolve averages, 2 alpha-to-coverage; see \`cutoutDither.ts\`), z
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
177
|
+
* 1 a dither the temporal resolve averages, 2 alpha-to-coverage; see \`cutoutDither.ts\`), z unused,
|
|
178
|
+
* w the material's lighting channels — a mask a light shades it only where its own shares a bit
|
|
179
|
+
* with (\`SurfaceMaterial.lightChannels\`, 1 unless a material names others). One vector rather than
|
|
180
|
+
* a float and three more, because every loose scalar is a row of WebGL2's 224 that the light budget
|
|
181
|
+
* gives up.
|
|
182
|
+
*
|
|
183
|
+
* **z was the frame the dither's pattern is offset by until 4.10.0**, and that made every material
|
|
184
|
+
* new every frame: a material is kept on WebGPU by its numbers, and one of them changed with the
|
|
185
|
+
* clock. The frame is the pass's, in \`uHighlightMin.w\`.
|
|
176
186
|
*/
|
|
177
|
-
uniform vec4 uCutout;
|
|
187
|
+
uniform vec4 uCutout; // wgsl:material
|
|
178
188
|
/**
|
|
179
189
|
* A draw's own ambient, as nine spherical-harmonic coefficients of incoming radiance, red green blue
|
|
180
190
|
* in turn, twenty-seven floats, and in the last of the twenty-eight a 1 where they are on — 0 is the
|
|
@@ -182,7 +192,7 @@ uniform vec4 uCutout;
|
|
|
182
192
|
* and the basis, and its tests hold this to it. Seven rows of the material block, which is per draw
|
|
183
193
|
* as far as anything here is: \`setAmbientSH\` moves it between two draws as \`setMaterial\` does.
|
|
184
194
|
*/
|
|
185
|
-
uniform vec4 uAmbientSH[7];
|
|
195
|
+
uniform vec4 uAmbientSH[7]; // wgsl:material
|
|
186
196
|
|
|
187
197
|
/** The ambient a surface facing \`n\` receives from \`uAmbientSH\`: \`ambientFromSH\`'s arithmetic. */
|
|
188
198
|
vec3 ambientHarmonics(vec3 n) {
|
|
@@ -229,7 +239,7 @@ uniform highp sampler2DArray uNormalMap;
|
|
|
229
239
|
* shadow samplers, where a profile with shadows off should declare none of them; it is the wrong
|
|
230
240
|
* tool for one image on a shader that already declares one.
|
|
231
241
|
*/
|
|
232
|
-
uniform float uNormalStrength;
|
|
242
|
+
uniform float uNormalStrength; // wgsl:material
|
|
233
243
|
|
|
234
244
|
/**
|
|
235
245
|
* Occlusion, roughness and metallic in one image. glTF's packing, because that is what an import
|
|
@@ -250,7 +260,7 @@ uniform highp sampler2DArray uOrmMap;
|
|
|
250
260
|
* occlusionTexture.strength is: 1 + strength * (texel - 1). A multiply at 0 means fully occluded,
|
|
251
261
|
* which is the opposite of what a caller asking for no occlusion means.
|
|
252
262
|
*/
|
|
253
|
-
uniform vec3 uOrmScale;
|
|
263
|
+
uniform vec3 uOrmScale; // wgsl:material
|
|
254
264
|
/**
|
|
255
265
|
* 1 when \`uEnvironment\` holds the GGX-prefiltered cube, 0 when it holds the capture's box chain.
|
|
256
266
|
*
|
|
@@ -266,7 +276,7 @@ uniform vec3 uOrmScale;
|
|
|
266
276
|
* (\`uniformVectorBudget.ts\`). y is how much of the environment the material mirrors, z how
|
|
267
277
|
* bright what it mirrors is.
|
|
268
278
|
*/
|
|
269
|
-
uniform vec3 uEnvironmentDials;
|
|
279
|
+
uniform vec3 uEnvironmentDials; // wgsl:material
|
|
270
280
|
|
|
271
281
|
/**
|
|
272
282
|
* Where a surface glows, and in what colour.
|
|
@@ -288,7 +298,7 @@ uniform highp sampler2DArray uEmissiveMap;
|
|
|
288
298
|
* The counterpart of \`uOrmScale\`: a factor that multiplies a texture is not a value, and this is
|
|
289
299
|
* where the multiplier lives once an image supplies the shape.
|
|
290
300
|
*/
|
|
291
|
-
uniform vec3 uEmissiveScale;
|
|
301
|
+
uniform vec3 uEmissiveScale; // wgsl:material
|
|
292
302
|
|
|
293
303
|
#if DIRECTIONAL_SHADOWS
|
|
294
304
|
/*
|
|
@@ -375,7 +385,7 @@ uniform vec4 uSurfaceScene;
|
|
|
375
385
|
* draw moves it), y the night factor emission is gated on. One row where two floats were two
|
|
376
386
|
* (\`uniformVectorBudget.ts\`).
|
|
377
387
|
*/
|
|
378
|
-
uniform vec2 uEmission;
|
|
388
|
+
uniform vec2 uEmission; // wgsl:material
|
|
379
389
|
#if NIGHT_EMISSIVE
|
|
380
390
|
/**
|
|
381
391
|
* Emission that only shows where the dominant light does not reach. 0 is off and is the default.
|
|
@@ -400,7 +410,7 @@ uniform float uNightEmissive;
|
|
|
400
410
|
* of that to change one channel is how a renderer ends up with two shaders that
|
|
401
411
|
* disagree about the sun. The caller owns the blend state; this owns the number.
|
|
402
412
|
*/
|
|
403
|
-
uniform float uOpacity;
|
|
413
|
+
uniform float uOpacity; // wgsl:material
|
|
404
414
|
|
|
405
415
|
/**
|
|
406
416
|
* Two per-draw switches on how a fragment is *written* rather than what colour it is, sharing one
|
|
@@ -432,7 +442,7 @@ uniform float uOpacity;
|
|
|
432
442
|
* crossfade reads as grain for as long as it lasts, which is why it should be short; and a blended
|
|
433
443
|
* draw that asks for it is dithered too, since the test is a discard.
|
|
434
444
|
*/
|
|
435
|
-
uniform vec2 uWriteMode;
|
|
445
|
+
uniform vec2 uWriteMode; // wgsl:material
|
|
436
446
|
|
|
437
447
|
/** Whether this fragment is one \`uWriteMode.y\` keeps. Integer arithmetic, per the device rule. */
|
|
438
448
|
bool ditherKeeps(float amount) {
|
|
@@ -465,7 +475,7 @@ bool ditherKeeps(float amount) {
|
|
|
465
475
|
* one uniform skips the untaken side rather than computing both and discarding one, which is
|
|
466
476
|
* only true because nothing here reads it through a *varying*-dependent branch.
|
|
467
477
|
*/
|
|
468
|
-
uniform int uLightingEnabled;
|
|
478
|
+
uniform int uLightingEnabled; // wgsl:material
|
|
469
479
|
/**
|
|
470
480
|
* How this draw meets the medium: the atmospheric haze and the underwater tint both, folded
|
|
471
481
|
* together because both are the *camera's* medium rather than a property of the surface — see
|
|
@@ -487,7 +497,7 @@ uniform int uLightingEnabled;
|
|
|
487
497
|
* is what "exactly as its colour says" has to mean for it; the cost is that such a draw will
|
|
488
498
|
* not tint if the camera goes under water, unlike everything else in the frame.
|
|
489
499
|
*/
|
|
490
|
-
uniform int uFogEnabled;
|
|
500
|
+
uniform int uFogEnabled; // wgsl:material
|
|
491
501
|
|
|
492
502
|
/**
|
|
493
503
|
* A pass-level scale over the grain the geometry declared, 0 to 1.
|
|
@@ -497,7 +507,7 @@ uniform int uFogEnabled;
|
|
|
497
507
|
* imported model that declares nothing is drawn with the pass's own answer, and a scene
|
|
498
508
|
* can dial a whole draw down without rebuilding its geometry.
|
|
499
509
|
*/
|
|
500
|
-
uniform float uGrain;
|
|
510
|
+
uniform float uGrain; // wgsl:material
|
|
501
511
|
/*
|
|
502
512
|
* The material's own relief: how strong, and how many bumps to a metre.
|
|
503
513
|
*
|
|
@@ -506,7 +516,7 @@ uniform float uGrain;
|
|
|
506
516
|
* between them, and the geometry carrying them is identical in all three cases. See
|
|
507
517
|
* Renderer.setSurfaceRelief. x is the strength and y the bumps to a metre, in one row.
|
|
508
518
|
*/
|
|
509
|
-
uniform vec2 uRelief;
|
|
519
|
+
uniform vec2 uRelief; // wgsl:material
|
|
510
520
|
/**
|
|
511
521
|
* How hard the bound surface texture's own luminance turns the shading normal, 0 for not at all.
|
|
512
522
|
*
|
|
@@ -529,7 +539,7 @@ uniform vec2 uRelief;
|
|
|
529
539
|
* 0..1 like its neighbours for the same reason: this is an amplitude against a luminance
|
|
530
540
|
* gradient, not a fraction of anything.
|
|
531
541
|
*/
|
|
532
|
-
uniform float uTextureRelief;
|
|
542
|
+
uniform float uTextureRelief; // wgsl:material
|
|
533
543
|
|
|
534
544
|
/**
|
|
535
545
|
* How much of the environment this material mirrors, 0 to 1.
|
|
@@ -664,8 +674,12 @@ uniform vec3 uProbeGridSets;
|
|
|
664
674
|
/**
|
|
665
675
|
* A world-space box that lights up regardless of time of day: its corners, and in the far corner's
|
|
666
676
|
* w the gain — one row where a loose float was another (\`uniformVectorBudget.ts\`).
|
|
677
|
+
*
|
|
678
|
+
* **And in the near corner's w the frame the cutout dither's pattern is offset by**, for the same
|
|
679
|
+
* reason: a row the lit stage already pays for, holding a number the pass sets and no material does.
|
|
680
|
+
* See \`uCutout\`.
|
|
667
681
|
*/
|
|
668
|
-
uniform
|
|
682
|
+
uniform vec4 uHighlightMin;
|
|
669
683
|
uniform vec4 uHighlightMax;
|
|
670
684
|
|
|
671
685
|
/*
|