@driftengine/core 4.1.3 → 4.1.5
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 +3796 -3739
- package/README.md +1 -1
- package/dist/index.js +12 -2
- package/dist/render/backend/webgl2/renderer.d.ts +15 -0
- package/dist/render/backend/webgl2/renderer.js +28 -7
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +46 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.js +105 -0
- package/dist/render/backend/webgpu/pointShadowPass.d.ts +4 -0
- package/dist/render/backend/webgpu/pointShadowPass.js +10 -0
- package/dist/render/backend/webgpu/renderer.js +17 -4
- package/dist/render/depthConvention.d.ts +19 -0
- package/dist/render/depthConvention.js +21 -0
- package/dist/render/livePointShadowSet.js +8 -0
- package/dist/render/pointShadowBudget.js +59 -5
- package/dist/render/pointShadowImage.d.ts +40 -0
- package/dist/render/pointShadowImage.js +20 -0
- package/dist/render/pointShadowMap.d.ts +4 -0
- package/dist/render/pointShadowMap.js +10 -0
- package/dist/render/pointShadowSystem.js +9 -0
- package/dist/render/renderQuality.d.ts +27 -4
- package/dist/render/renderQuality.js +1 -1
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +104 -10
- package/dist/render/shaders/flat/pointShadow.d.ts +1 -1
- package/dist/render/shaders/flat/pointShadow.js +84 -46
- package/dist/render/shaders/flat/preamble.js +70 -9
- package/dist/render/shaders/generated/flat.wgsl.d.ts +16 -16
- package/dist/render/shaders/generated/flat.wgsl.js +32 -32
- package/dist/render/shaders/sky.d.ts +10 -6
- package/dist/render/shaders/sky.js +35 -2
- package/dist/render/textLayout.d.ts +58 -0
- package/dist/render/textLayout.js +83 -0
- package/dist/render/textRenderer.js +7 -3
- package/package.json +6 -6
- package/src/index.ts +12 -2
- package/src/render/backend/webgl2/renderer.ts +28 -7
- package/src/render/backend/webgpu/gpuDrivenPass.ts +105 -0
- package/src/render/backend/webgpu/pointShadowPass.ts +13 -0
- package/src/render/backend/webgpu/renderer.ts +26 -4
- package/src/render/depthConvention.ts +22 -0
- package/src/render/livePointShadowSet.ts +7 -0
- package/src/render/pointShadowBudget.ts +58 -5
- package/src/render/pointShadowImage.ts +51 -0
- package/src/render/pointShadowMap.ts +13 -0
- package/src/render/pointShadowSystem.ts +8 -0
- package/src/render/renderQuality.ts +28 -5
- package/src/render/shaders/flat/main.ts +104 -10
- package/src/render/shaders/flat/pointShadow.ts +84 -46
- package/src/render/shaders/flat/preamble.ts +70 -9
- package/src/render/shaders/generated/flat.wgsl.ts +32 -32
- package/src/render/shaders/sky.ts +37 -2
- package/src/render/textLayout.ts +88 -0
- package/src/render/textRenderer.ts +22 -3
|
@@ -111,6 +111,18 @@ export declare class PointShadowImage {
|
|
|
111
111
|
private pendingRange;
|
|
112
112
|
private pendingNear;
|
|
113
113
|
private pendingSourceRadius;
|
|
114
|
+
/**
|
|
115
|
+
* Where this image was rendered from, which is what a sampler has to shoot its ray from.
|
|
116
|
+
*
|
|
117
|
+
* **Not the light's position**, and the difference is the whole point: `matchesSource` lets a
|
|
118
|
+
* light drift up to the caller's rebake tolerance from here before the image is re-rendered,
|
|
119
|
+
* so for any light that wanders these two are apart on nearly every frame. A shader that
|
|
120
|
+
* builds its direction and its distance from the live light asks this picture a question the
|
|
121
|
+
* picture cannot answer. See `ResolvedPointShadows.origins`.
|
|
122
|
+
*/
|
|
123
|
+
get originX(): number;
|
|
124
|
+
get originY(): number;
|
|
125
|
+
get originZ(): number;
|
|
114
126
|
/** Whether this map holds an image worth sampling. False until a bake completes. */
|
|
115
127
|
get hasBaked(): boolean;
|
|
116
128
|
/** How present the image is, 0 to 1. The shader mixes the occlusion in by it. */
|
|
@@ -222,6 +234,10 @@ export interface PointShadowSource {
|
|
|
222
234
|
readonly far: number;
|
|
223
235
|
readonly near: number;
|
|
224
236
|
readonly sourceRadius: number;
|
|
237
|
+
/** Where the image was rendered from. See `PointShadowImage.originX`. */
|
|
238
|
+
readonly originX: number;
|
|
239
|
+
readonly originY: number;
|
|
240
|
+
readonly originZ: number;
|
|
225
241
|
/** Whether this map holds an image worth sampling. */
|
|
226
242
|
readonly hasBaked: boolean;
|
|
227
243
|
/** How present the image is, 0 to 1. */
|
|
@@ -253,6 +269,28 @@ export interface ResolvedPointShadows {
|
|
|
253
269
|
readonly far: Float32Array;
|
|
254
270
|
readonly near: Float32Array;
|
|
255
271
|
readonly sourceRadius: Float32Array;
|
|
272
|
+
/**
|
|
273
|
+
* The projection each bound map was rendered under: origin in `xyz`, far plane in `w`, four
|
|
274
|
+
* floats a light. The origin is **not** the light's position.
|
|
275
|
+
*
|
|
276
|
+
* A light is allowed to drift `pointShadowRebakeDistance` from its image before the image is
|
|
277
|
+
* re-rendered — that tolerance is what stops a flame re-baking six faces of the static world
|
|
278
|
+
* every frame — so for anything that flickers these two are apart on nearly every frame. The
|
|
279
|
+
* shader builds both its sample direction and the distance it compares from this point, so the
|
|
280
|
+
* ray it shoots is the ray the picture was drawn along and the drift costs nothing.
|
|
281
|
+
*
|
|
282
|
+
* **It used to build them from the live light**, and the drift went straight into the
|
|
283
|
+
* comparison: `dist` moved one for one with it against a bias of a few centimetres, and the
|
|
284
|
+
* single-tap blocker search moved across the occluder's silhouette, swapping `occluderDistance`
|
|
285
|
+
* between the caster and nothing. Reported on a brazier at night as a hard square under the
|
|
286
|
+
* fire, flashing in time with the flame while the camera stood still.
|
|
287
|
+
*
|
|
288
|
+
* **The far plane rides in `w` rather than in an array of its own**, because a default-block
|
|
289
|
+
* `float[N]` spends a whole uniform vector per element: declared separately the origin cost
|
|
290
|
+
* sixteen rows on each of the two sets, which the budget ladder answers on a 256-vector
|
|
291
|
+
* device by halving `MAX_LIGHTS`. See `uPointShadowProjection` in the preamble.
|
|
292
|
+
*/
|
|
293
|
+
readonly projections: Float32Array;
|
|
256
294
|
/** How present each bound map is, so a re-baked one arrives rather than appears. */
|
|
257
295
|
readonly presence: Float32Array;
|
|
258
296
|
/** The live pair, by the same light index: a light owns at most one of the two. */
|
|
@@ -260,6 +298,8 @@ export interface ResolvedPointShadows {
|
|
|
260
298
|
readonly liveFar: Float32Array;
|
|
261
299
|
readonly liveNear: Float32Array;
|
|
262
300
|
readonly liveSourceRadius: Float32Array;
|
|
301
|
+
/** The live pair's own, by the same rule and for the same reason. */
|
|
302
|
+
readonly liveProjections: Float32Array;
|
|
263
303
|
readonly liveWeights: Float32Array;
|
|
264
304
|
}
|
|
265
305
|
export declare function createResolvedPointShadows(lights: number): ResolvedPointShadows;
|
|
@@ -160,6 +160,24 @@ export class PointShadowImage {
|
|
|
160
160
|
pendingRange = 0;
|
|
161
161
|
pendingNear = 0;
|
|
162
162
|
pendingSourceRadius = 0;
|
|
163
|
+
/**
|
|
164
|
+
* Where this image was rendered from, which is what a sampler has to shoot its ray from.
|
|
165
|
+
*
|
|
166
|
+
* **Not the light's position**, and the difference is the whole point: `matchesSource` lets a
|
|
167
|
+
* light drift up to the caller's rebake tolerance from here before the image is re-rendered,
|
|
168
|
+
* so for any light that wanders these two are apart on nearly every frame. A shader that
|
|
169
|
+
* builds its direction and its distance from the live light asks this picture a question the
|
|
170
|
+
* picture cannot answer. See `ResolvedPointShadows.origins`.
|
|
171
|
+
*/
|
|
172
|
+
get originX() {
|
|
173
|
+
return this.x;
|
|
174
|
+
}
|
|
175
|
+
get originY() {
|
|
176
|
+
return this.y;
|
|
177
|
+
}
|
|
178
|
+
get originZ() {
|
|
179
|
+
return this.z;
|
|
180
|
+
}
|
|
163
181
|
/** Whether this map holds an image worth sampling. False until a bake completes. */
|
|
164
182
|
get hasBaked() {
|
|
165
183
|
return this.baked;
|
|
@@ -329,11 +347,13 @@ export function createResolvedPointShadows(lights) {
|
|
|
329
347
|
far: new Float32Array(lights),
|
|
330
348
|
near: new Float32Array(lights),
|
|
331
349
|
sourceRadius: new Float32Array(lights),
|
|
350
|
+
projections: new Float32Array(lights * 4),
|
|
332
351
|
presence: new Float32Array(lights),
|
|
333
352
|
liveLayers: new Int32Array(lights).fill(-1),
|
|
334
353
|
liveFar: new Float32Array(lights),
|
|
335
354
|
liveNear: new Float32Array(lights),
|
|
336
355
|
liveSourceRadius: new Float32Array(lights),
|
|
356
|
+
liveProjections: new Float32Array(lights * 4),
|
|
337
357
|
liveWeights: new Float32Array(lights),
|
|
338
358
|
};
|
|
339
359
|
}
|
|
@@ -46,6 +46,10 @@ export declare class PointShadowMap {
|
|
|
46
46
|
get far(): number;
|
|
47
47
|
get near(): number;
|
|
48
48
|
get sourceRadius(): number;
|
|
49
|
+
/** Where the image was rendered from, not where the light is now. See the image. */
|
|
50
|
+
get originX(): number;
|
|
51
|
+
get originY(): number;
|
|
52
|
+
get originZ(): number;
|
|
49
53
|
/** Whether this map holds an image worth sampling. False until a bake completes. */
|
|
50
54
|
get hasBaked(): boolean;
|
|
51
55
|
/** How present the image is, 0 to 1. The shader mixes the occlusion in by it. */
|
|
@@ -54,6 +54,16 @@ export class PointShadowMap {
|
|
|
54
54
|
get sourceRadius() {
|
|
55
55
|
return this.image.sourceRadius;
|
|
56
56
|
}
|
|
57
|
+
/** Where the image was rendered from, not where the light is now. See the image. */
|
|
58
|
+
get originX() {
|
|
59
|
+
return this.image.originX;
|
|
60
|
+
}
|
|
61
|
+
get originY() {
|
|
62
|
+
return this.image.originY;
|
|
63
|
+
}
|
|
64
|
+
get originZ() {
|
|
65
|
+
return this.image.originZ;
|
|
66
|
+
}
|
|
57
67
|
/** Whether this map holds an image worth sampling. False until a bake completes. */
|
|
58
68
|
get hasBaked() {
|
|
59
69
|
return this.image.hasBaked;
|
|
@@ -272,6 +272,10 @@ export class PointShadowSystem {
|
|
|
272
272
|
out.far.fill(1);
|
|
273
273
|
out.near.fill(0.01);
|
|
274
274
|
out.sourceRadius.fill(0);
|
|
275
|
+
/* Origin zero, far plane one: the same neutral the separate `far` array is filled with. */
|
|
276
|
+
out.projections.fill(0);
|
|
277
|
+
for (let k = 0; k < MAX_POINT_LIGHTS; k++)
|
|
278
|
+
out.projections[k * 4 + 3] = 1;
|
|
275
279
|
out.presence.fill(0);
|
|
276
280
|
for (let k = 0; k < MAX_POINT_LIGHTS; k++) {
|
|
277
281
|
const map = this.mapForShaderSlot(k);
|
|
@@ -299,6 +303,11 @@ export class PointShadowSystem {
|
|
|
299
303
|
out.far[light] = map.far;
|
|
300
304
|
out.near[light] = map.near;
|
|
301
305
|
out.sourceRadius[light] = map.sourceRadius;
|
|
306
|
+
/* Where the image was rendered from, not where the light is now. See `projections`. */
|
|
307
|
+
out.projections[light * 4] = map.originX;
|
|
308
|
+
out.projections[light * 4 + 1] = map.originY;
|
|
309
|
+
out.projections[light * 4 + 2] = map.originZ;
|
|
310
|
+
out.projections[light * 4 + 3] = map.far;
|
|
302
311
|
out.presence[light] = map.presence;
|
|
303
312
|
out.layers[light] = map.layer;
|
|
304
313
|
}
|
|
@@ -154,10 +154,33 @@ export interface RenderQuality {
|
|
|
154
154
|
* sampled lights flickering at once accounted for 174 of the frame's 296 draw
|
|
155
155
|
* calls, and for the game being unplayable exactly where lamps cluster.
|
|
156
156
|
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
157
|
+
* **It was 0.4 until 4.1.5, chosen to clear a flame's whole wander with room to spare** — so
|
|
158
|
+
* a flame never re-baked at all, and its shadow of the static world stood still while the live
|
|
159
|
+
* map under the same light, which is re-rendered every frame because it holds the movers, swung
|
|
160
|
+
* with the flame. One light, two shadows, visibly disagreeing about where it was. Reported as
|
|
161
|
+
* the runner's shadow following the fire and the brazier's not.
|
|
162
|
+
*
|
|
163
|
+
* **A millimetre instead, which is as near to "whenever it moved" as makes sense**, so a shadow
|
|
164
|
+
* travels with its light rather than freezing between re-bakes. A centimetre was tried first and
|
|
165
|
+
* left a visible vibration: a light wandering on a curve moves less than that in a frame near
|
|
166
|
+
* the turning points of its travel, so the shadow ran smoothly through the fast part and stepped
|
|
167
|
+
* through the slow part. What the tolerance is still for is not re-baking on arithmetic noise.
|
|
168
|
+
*
|
|
169
|
+
* A light that does not move never goes stale at any positive value, so the whole cost falls on
|
|
170
|
+
* the lights that need it, and it is bounded rather than proportional: one such light takes a
|
|
171
|
+
* whole cube in a frame and the rest dribble under the ordinary face budget.
|
|
172
|
+
*
|
|
173
|
+
* **What makes that affordable is not this number.** The 174-of-296 draw calls this paragraph
|
|
174
|
+
* used to cite was measured before `pointShadowFacesPerFrame` capped the whole static bake, and
|
|
175
|
+
* before `planPointShadowBakes` learned to put a chronically stale map behind every cold and
|
|
176
|
+
* settling one. A flame now spends leftover budget and can never hold another light's first
|
|
177
|
+
* image hostage. One such light also finishes its cube inside a single frame rather than
|
|
178
|
+
* dribbling it over three, which is what makes the motion smooth instead of stepped; see
|
|
179
|
+
* `pointShadowBudget.ts`.
|
|
180
|
+
*
|
|
181
|
+
* **What would make it wrong** is a caster set heavy enough that six passes over it does not
|
|
182
|
+
* fit the frame, where a stepped shadow is the better trade and this should go back up.
|
|
183
|
+
* `gpuTiming` is how to tell which, and it is a number rather than an opinion.
|
|
161
184
|
*/
|
|
162
185
|
readonly pointShadowRebakeDistance: number;
|
|
163
186
|
/**
|
|
@@ -58,7 +58,7 @@ export const DEFAULT_RENDER_QUALITY = Object.freeze({
|
|
|
58
58
|
directionalShadowDepthLayers: 2,
|
|
59
59
|
directionalShadowMaxDistance: 6,
|
|
60
60
|
directionalShadowMaxSlope: 3,
|
|
61
|
-
pointShadowRebakeDistance: 0.
|
|
61
|
+
pointShadowRebakeDistance: 0.001,
|
|
62
62
|
pointShadowFacesPerFrame: 2,
|
|
63
63
|
/*
|
|
64
64
|
* Twelve, which is `LIVE_POINT_SHADOW_MAPS` cubemaps of six faces: exactly what the live
|