@aethervtt/shard-render 0.0.1 → 0.2.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/dist/ablation.d.ts +74 -0
- package/dist/ablation.js +117 -0
- package/dist/assets.d.ts +3 -0
- package/dist/assets.js +43 -2
- package/dist/atmosphere-nodes.d.ts +9 -0
- package/dist/atmosphere-nodes.js +157 -30
- package/dist/atmosphere-plugin.js +8 -2
- package/dist/atmosphere-shaders.js +17 -5
- package/dist/baseline/atmosphere.d.ts +16 -0
- package/dist/baseline/atmosphere.js +301 -0
- package/dist/baseline/data-texture.d.ts +36 -0
- package/dist/baseline/data-texture.js +181 -0
- package/dist/baseline/environment.d.ts +14 -0
- package/dist/baseline/environment.js +368 -0
- package/dist/baseline/exposure.d.ts +25 -0
- package/dist/baseline/exposure.js +133 -0
- package/dist/baseline/lights.d.ts +33 -0
- package/dist/baseline/lights.js +133 -0
- package/dist/baseline/textures.d.ts +97 -0
- package/dist/baseline/textures.js +203 -0
- package/dist/camera.d.ts +2 -0
- package/dist/camera.js +4 -0
- package/dist/crowd.d.ts +21 -0
- package/dist/crowd.js +121 -0
- package/dist/culling-shaders.js +21 -2
- package/dist/culling.d.ts +11 -2
- package/dist/culling.js +44 -18
- package/dist/cutaway-plugin.d.ts +48 -0
- package/dist/cutaway-plugin.js +364 -0
- package/dist/cutaway.d.ts +27 -0
- package/dist/cutaway.js +49 -0
- package/dist/data-store.d.ts +69 -0
- package/dist/data-store.js +105 -0
- package/dist/debug-shaders.js +17 -3
- package/dist/debug-views.js +4 -2
- package/dist/decals-plugin.d.ts +5 -0
- package/dist/decals-plugin.js +54 -0
- package/dist/decals.d.ts +69 -0
- package/dist/decals.js +326 -0
- package/dist/deferred-shaders.js +2 -0
- package/dist/deferred.js +28 -4
- package/dist/deform.d.ts +5 -4
- package/dist/deform.js +4 -9
- package/dist/describe-plugin.d.ts +4 -2
- package/dist/describe-plugin.js +75 -3
- package/dist/display-nodes.js +37 -13
- package/dist/dynamic-resolution.d.ts +2 -0
- package/dist/dynamic-resolution.js +6 -1
- package/dist/environment-plugin.js +17 -2
- package/dist/environment-state.d.ts +7 -3
- package/dist/environment-state.js +20 -9
- package/dist/environment.js +7 -1
- package/dist/features.d.ts +49 -0
- package/dist/features.js +106 -0
- package/dist/foliage-budget.d.ts +64 -0
- package/dist/foliage-budget.js +108 -0
- package/dist/foliage-path.d.ts +19 -0
- package/dist/foliage-path.js +7 -0
- package/dist/foliage-shaders.d.ts +11 -0
- package/dist/foliage-shaders.js +504 -0
- package/dist/foliage.d.ts +194 -0
- package/dist/foliage.js +1027 -0
- package/dist/forward.d.ts +38 -2
- package/dist/forward.js +608 -186
- package/dist/fxaa.js +12 -2
- package/dist/gizmos-plugin.js +7 -0
- package/dist/gizmos.d.ts +3 -3
- package/dist/gizmos.js +11 -13
- package/dist/gpu-assets.d.ts +58 -4
- package/dist/gpu-assets.js +191 -8
- package/dist/graph.d.ts +45 -0
- package/dist/graph.js +169 -19
- package/dist/health.d.ts +58 -0
- package/dist/health.js +112 -0
- package/dist/index.d.ts +40 -11
- package/dist/index.js +343 -9
- package/dist/instances.d.ts +119 -8
- package/dist/instances.js +387 -78
- package/dist/interior-plugin.d.ts +121 -0
- package/dist/interior-plugin.js +465 -0
- package/dist/interior.d.ts +24 -0
- package/dist/interior.js +13 -0
- package/dist/layers.d.ts +35 -0
- package/dist/layers.js +49 -0
- package/dist/lens-plugin.d.ts +43 -0
- package/dist/lens-plugin.js +304 -0
- package/dist/lens.d.ts +41 -0
- package/dist/lens.js +99 -0
- package/dist/lights.d.ts +50 -5
- package/dist/lights.js +101 -22
- package/dist/material-pipelines.d.ts +37 -4
- package/dist/material-pipelines.js +102 -5
- package/dist/materials.d.ts +23 -0
- package/dist/materials.js +44 -1
- package/dist/outline-plugin.d.ts +48 -0
- package/dist/outline-plugin.js +529 -0
- package/dist/outline.d.ts +15 -0
- package/dist/outline.js +42 -0
- package/dist/overlay-registry.d.ts +3 -1
- package/dist/overlay-registry.js +3 -1
- package/dist/overlays.js +6 -2
- package/dist/perf-overlay.d.ts +9 -0
- package/dist/perf-overlay.js +125 -0
- package/dist/picking.d.ts +17 -0
- package/dist/picking.js +40 -11
- package/dist/pixel-perfect-plugin.js +10 -2
- package/dist/plugin.d.ts +69 -7
- package/dist/plugin.js +223 -25
- package/dist/post-common.d.ts +22 -2
- package/dist/post-common.js +82 -2
- package/dist/post-nodes.d.ts +7 -1
- package/dist/post-nodes.js +235 -111
- package/dist/post-plugin.js +5 -3
- package/dist/post-scene.d.ts +130 -0
- package/dist/post-scene.js +164 -0
- package/dist/post-shaders.js +85 -62
- package/dist/post.js +11 -1
- package/dist/projection.d.ts +24 -0
- package/dist/projection.js +87 -0
- package/dist/readback.d.ts +1 -0
- package/dist/readback.js +1 -0
- package/dist/render-scale.js +1 -0
- package/dist/ribbons-plugin.d.ts +5 -0
- package/dist/ribbons-plugin.js +59 -0
- package/dist/ribbons.d.ts +44 -0
- package/dist/ribbons.js +288 -0
- package/dist/scenario.d.ts +70 -0
- package/dist/scenario.js +125 -0
- package/dist/screen-effects.d.ts +97 -0
- package/dist/screen-effects.js +192 -0
- package/dist/shaders.d.ts +13 -0
- package/dist/shaders.js +189 -34
- package/dist/shadow-catcher.d.ts +9 -0
- package/dist/shadow-catcher.js +133 -0
- package/dist/shadows.d.ts +27 -2
- package/dist/shadows.js +100 -20
- package/dist/standard-fields.d.ts +1 -0
- package/dist/standard-fields.js +5 -0
- package/dist/standard.js +18 -0
- package/dist/stats.d.ts +45 -1
- package/dist/stats.js +91 -3
- package/dist/surface-model.d.ts +57 -0
- package/dist/surface-model.js +289 -0
- package/dist/surface-shaders.d.ts +3 -0
- package/dist/surface-shaders.js +160 -0
- package/dist/surface.d.ts +40 -0
- package/dist/surface.js +86 -0
- package/dist/target.d.ts +1 -13
- package/dist/target.js +1 -26
- package/dist/testing.d.ts +11 -0
- package/dist/testing.js +39 -1
- package/dist/tier.d.ts +13 -0
- package/dist/tier.js +14 -0
- package/dist/timer.d.ts +18 -1
- package/dist/timer.js +73 -20
- package/dist/variants.d.ts +37 -0
- package/dist/variants.js +104 -0
- package/dist/vfx-draw.d.ts +37 -0
- package/dist/vfx-draw.js +291 -0
- package/dist/vfx-state.d.ts +42 -0
- package/dist/vfx-state.js +81 -0
- package/dist/vfx.d.ts +69 -0
- package/dist/vfx.js +103 -0
- package/dist/view-visibility-plugin.d.ts +61 -0
- package/dist/view-visibility-plugin.js +267 -0
- package/dist/view-visibility.d.ts +28 -0
- package/dist/view-visibility.js +46 -0
- package/dist/view.d.ts +29 -1
- package/dist/view.js +57 -34
- package/package.json +23 -11
package/dist/shadows.js
CHANGED
|
@@ -2,7 +2,11 @@ import { defineResource, frustum, mat4 } from "@aethervtt/shard-core";
|
|
|
2
2
|
import { GpuBuffer } from "@aethervtt/shard-gpu";
|
|
3
3
|
import { Culler } from "./culling.js";
|
|
4
4
|
import { GpuAssetsResource } from "./gpu-assets.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createDrawList,
|
|
7
|
+
InstanceFlags,
|
|
8
|
+
Instances
|
|
9
|
+
} from "./instances.js";
|
|
6
10
|
import { setShadowIndex } from "./lights.js";
|
|
7
11
|
import {
|
|
8
12
|
materialVariant,
|
|
@@ -10,6 +14,7 @@ import {
|
|
|
10
14
|
variantBlend,
|
|
11
15
|
variantCull
|
|
12
16
|
} from "./material-pipelines.js";
|
|
17
|
+
import { bindingDimension } from "./tier.js";
|
|
13
18
|
const MAX_CASCADES = 4;
|
|
14
19
|
const MAX_SHADOWED_SPOTS = 8;
|
|
15
20
|
const MAX_SHADOWED_POINTS = 4;
|
|
@@ -31,7 +36,30 @@ function pointTanHalf(size) {
|
|
|
31
36
|
}
|
|
32
37
|
const VIEW_STRIDE = 256;
|
|
33
38
|
function shadowView() {
|
|
34
|
-
return {
|
|
39
|
+
return {
|
|
40
|
+
viewProj: mat4.create(),
|
|
41
|
+
frustum: frustum.create(),
|
|
42
|
+
cullPlanes: frustum.create(),
|
|
43
|
+
draws: createDrawList(),
|
|
44
|
+
offset: 0,
|
|
45
|
+
drawn: false,
|
|
46
|
+
drawnViewProj: mat4.create(),
|
|
47
|
+
drawnEpoch: -1,
|
|
48
|
+
redraw: true
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function shadowRedraw(view, cached, store) {
|
|
52
|
+
if (!cached || !view.drawn || view.drawnEpoch !== store.shadowEpoch || store.deforming)
|
|
53
|
+
return true;
|
|
54
|
+
const a = view.viewProj;
|
|
55
|
+
const b = view.drawnViewProj;
|
|
56
|
+
for (let i = 0; i < 16; i++) if (a[i] !== b[i]) return true;
|
|
57
|
+
return store.movedCasterIn(view.cullPlanes);
|
|
58
|
+
}
|
|
59
|
+
function markShadowDrawn(view, store) {
|
|
60
|
+
view.drawn = true;
|
|
61
|
+
view.drawnViewProj.set(view.viewProj);
|
|
62
|
+
view.drawnEpoch = store.shadowEpoch;
|
|
35
63
|
}
|
|
36
64
|
class Cascades {
|
|
37
65
|
count = 0;
|
|
@@ -46,11 +74,13 @@ class Cascades {
|
|
|
46
74
|
ensureTexture(gpu, size, label) {
|
|
47
75
|
if (!this.texture || this.size !== size || this.generation !== gpu.generation) {
|
|
48
76
|
this.texture?.destroy();
|
|
77
|
+
for (const view of this.views) view.drawn = false;
|
|
49
78
|
this.texture = gpu.device.createTexture({
|
|
50
79
|
label: `${label}/cascades`,
|
|
51
80
|
size: [size, size, MAX_CASCADES],
|
|
52
81
|
format: "depth32float",
|
|
53
|
-
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC
|
|
82
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
|
|
83
|
+
...bindingDimension(gpu, "2d-array")
|
|
54
84
|
});
|
|
55
85
|
this.size = size;
|
|
56
86
|
this.generation = gpu.generation;
|
|
@@ -160,6 +190,7 @@ function fitCascades(cascades, cam, sun, size, cull) {
|
|
|
160
190
|
set(4, -basis[6], -basis[7], -basis[8], lz + radius);
|
|
161
191
|
set(5, 0, 0, 0, 1);
|
|
162
192
|
const view = cascades.views[i];
|
|
193
|
+
view.cullPlanes.set(p);
|
|
163
194
|
const any = cull(view, p, scratchBox);
|
|
164
195
|
let zNear = lz - radius;
|
|
165
196
|
if (any) {
|
|
@@ -228,15 +259,18 @@ class LocalShadows {
|
|
|
228
259
|
label,
|
|
229
260
|
size: [size, size, layers],
|
|
230
261
|
format: "depth32float",
|
|
231
|
-
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC
|
|
262
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
|
|
263
|
+
...bindingDimension(gpu, "2d-array")
|
|
232
264
|
});
|
|
233
265
|
if (fresh || !this.spotTexture || spotLayers > this.spotLayers) {
|
|
234
266
|
this.spotTexture?.destroy();
|
|
267
|
+
for (const view of this.spotViews) view.drawn = false;
|
|
235
268
|
this.spotLayers = Math.max(spotLayers, fresh ? 1 : this.spotLayers);
|
|
236
269
|
this.spotTexture = make("shadows/spots", this.spotLayers);
|
|
237
270
|
}
|
|
238
271
|
if (fresh || !this.pointTexture || pointLayers > this.pointLayers) {
|
|
239
272
|
this.pointTexture?.destroy();
|
|
273
|
+
for (const view of this.pointViews) view.drawn = false;
|
|
240
274
|
this.pointLayers = Math.max(pointLayers, fresh ? 6 : this.pointLayers);
|
|
241
275
|
this.pointTexture = make("shadows/points", this.pointLayers);
|
|
242
276
|
}
|
|
@@ -317,6 +351,7 @@ function fitLocalShadows(shadows, size) {
|
|
|
317
351
|
const view = shadows.spotViews[i];
|
|
318
352
|
mat4.multiply(view.viewProj, scratchProj, scratchView);
|
|
319
353
|
frustum.fromViewProjection(view.frustum, view.viewProj);
|
|
354
|
+
view.cullPlanes.set(view.frustum);
|
|
320
355
|
shadows.spotParams[i * 4] = tanHalf2;
|
|
321
356
|
shadows.spotParams[i * 4 + 1] = near;
|
|
322
357
|
}
|
|
@@ -335,6 +370,7 @@ function fitLocalShadows(shadows, size) {
|
|
|
335
370
|
const view = shadows.pointViews[i * 6 + f];
|
|
336
371
|
mat4.multiply(view.viewProj, scratchProj, scratchView);
|
|
337
372
|
frustum.fromViewProjection(view.frustum, view.viewProj);
|
|
373
|
+
view.cullPlanes.set(view.frustum);
|
|
338
374
|
}
|
|
339
375
|
}
|
|
340
376
|
}
|
|
@@ -377,6 +413,11 @@ class ShadowPassUniforms {
|
|
|
377
413
|
bindGroup;
|
|
378
414
|
bound = "";
|
|
379
415
|
gpu;
|
|
416
|
+
/** What the buffer holds, so unchanged shadow views write nothing (0055). */
|
|
417
|
+
sent = new Float32Array(0);
|
|
418
|
+
sentCount = 0;
|
|
419
|
+
sentVersion = -1;
|
|
420
|
+
sentGeneration = -1;
|
|
380
421
|
constructor(gpu) {
|
|
381
422
|
this.gpu = gpu;
|
|
382
423
|
this.buffer = new GpuBuffer(gpu, {
|
|
@@ -400,7 +441,15 @@ class ShadowPassUniforms {
|
|
|
400
441
|
return this.count++ * VIEW_STRIDE;
|
|
401
442
|
}
|
|
402
443
|
upload(layout, globals) {
|
|
403
|
-
|
|
444
|
+
const floats = this.count * VIEW_STRIDE / 4;
|
|
445
|
+
if (this.count > 0 && !this.unchanged(floats)) {
|
|
446
|
+
this.buffer.write(this.data, 0, 0, floats);
|
|
447
|
+
if (this.sent.length < this.data.length) this.sent = new Float32Array(this.data.length);
|
|
448
|
+
this.sent.set(this.data.subarray(0, floats));
|
|
449
|
+
this.sentCount = this.count;
|
|
450
|
+
this.sentVersion = this.buffer.version;
|
|
451
|
+
this.sentGeneration = this.gpu.generation;
|
|
452
|
+
}
|
|
404
453
|
const key = `${this.buffer.version}/${globals.version}/${this.gpu.generation}`;
|
|
405
454
|
if (!this.bindGroup || this.bound !== key) {
|
|
406
455
|
this.bindGroup = this.gpu.device.createBindGroup({
|
|
@@ -414,6 +463,15 @@ class ShadowPassUniforms {
|
|
|
414
463
|
this.bound = key;
|
|
415
464
|
}
|
|
416
465
|
}
|
|
466
|
+
unchanged(floats) {
|
|
467
|
+
if (this.sentCount < this.count) return false;
|
|
468
|
+
if (this.sentVersion !== this.buffer.version || this.sentGeneration !== this.gpu.generation)
|
|
469
|
+
return false;
|
|
470
|
+
const data = this.data;
|
|
471
|
+
const sent = this.sent;
|
|
472
|
+
for (let i = 0; i < floats; i++) if (data[i] !== sent[i]) return false;
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
417
475
|
}
|
|
418
476
|
function shadowViewLayout(gpu) {
|
|
419
477
|
return gpu.layouts.bindGroupLayout({
|
|
@@ -439,7 +497,7 @@ const SHADOW_BUFFERS = [
|
|
|
439
497
|
{ arrayStride: 8, attributes: [{ shaderLocation: 3, offset: 0, format: "float32x2" }] },
|
|
440
498
|
{ arrayStride: 16, attributes: [{ shaderLocation: 4, offset: 0, format: "float32x4" }] }
|
|
441
499
|
];
|
|
442
|
-
function drawShadowCasters(ctx, target, view, offset, uniforms, pipelines, shadowView2, label) {
|
|
500
|
+
function drawShadowCasters(ctx, target, view, offset, uniforms, pipelines, shadowView2, label, foliage, cam, cascade = 0) {
|
|
443
501
|
const world = ctx.world;
|
|
444
502
|
const gpu = ctx.gpu;
|
|
445
503
|
const store = world.resource(Instances);
|
|
@@ -458,6 +516,7 @@ function drawShadowCasters(ctx, target, view, offset, uniforms, pipelines, shado
|
|
|
458
516
|
const draws0 = view.draws;
|
|
459
517
|
const instances = draws0.cullView >= 0 ? store.gpuBindGroup : store.bindGroup;
|
|
460
518
|
if (!instances || !uniforms.bindGroup) {
|
|
519
|
+
if (foliage && cam && uniforms.bindGroup) foliage.drawShadow(ctx, cam, pass, offset, cascade);
|
|
461
520
|
pass.end();
|
|
462
521
|
return;
|
|
463
522
|
}
|
|
@@ -472,7 +531,8 @@ function drawShadowCasters(ctx, target, view, offset, uniforms, pipelines, shado
|
|
|
472
531
|
const draws = view.draws;
|
|
473
532
|
for (let d = 0; d < draws.length; d++) {
|
|
474
533
|
const item = draws.items[d];
|
|
475
|
-
const
|
|
534
|
+
const fallback = pipelines.failing(item.batch.material.type);
|
|
535
|
+
const material = fallback ? pipelines.proxy(item.batch.material) : item.batch.material;
|
|
476
536
|
const type = material.type;
|
|
477
537
|
const variant = materialVariant(material);
|
|
478
538
|
const masked = type.standard && variantBlend(variant) === "mask";
|
|
@@ -481,21 +541,38 @@ function drawShadowCasters(ctx, target, view, offset, uniforms, pipelines, shado
|
|
|
481
541
|
if (!pipeline) {
|
|
482
542
|
const module = pipelines.module(world, gpu, type, 8, "shard::pbr::shadow", void 0);
|
|
483
543
|
if (!module) {
|
|
484
|
-
|
|
544
|
+
if (!fallback && pipelines.failing(type)) d--;
|
|
545
|
+
else gpu.pipelines.skipped++;
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
pipeline = pipelines.create(
|
|
549
|
+
gpu,
|
|
550
|
+
key,
|
|
551
|
+
{
|
|
552
|
+
label: `shadow/${type.name}/${masked ? "mask" : "opaque"}/${variantCull(variant)}`,
|
|
553
|
+
layout: gpu.layouts.pipelineLayout({
|
|
554
|
+
label: `shadow/${type.name}`,
|
|
555
|
+
bindGroupLayouts: [shadowView2, assets.layoutOf(type), store.layout]
|
|
556
|
+
}),
|
|
557
|
+
vertex: { module, entryPoint: "vs", buffers: SHADOW_BUFFERS },
|
|
558
|
+
fragment: masked ? { module, entryPoint: "fs_mask", targets: [] } : void 0,
|
|
559
|
+
primitive: {
|
|
560
|
+
topology: "triangle-list",
|
|
561
|
+
cullMode: variantCull(variant),
|
|
562
|
+
frontFace: "ccw"
|
|
563
|
+
},
|
|
564
|
+
depthStencil: {
|
|
565
|
+
format: "depth32float",
|
|
566
|
+
depthWriteEnabled: true,
|
|
567
|
+
depthCompare: "greater"
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
type
|
|
571
|
+
);
|
|
572
|
+
if (!pipeline) {
|
|
573
|
+
if (!fallback && pipelines.failing(type)) d--;
|
|
485
574
|
continue;
|
|
486
575
|
}
|
|
487
|
-
pipeline = pipelines.create(gpu, key, {
|
|
488
|
-
label: `shadow/${type.name}/${masked ? "mask" : "opaque"}/${variantCull(variant)}`,
|
|
489
|
-
layout: gpu.layouts.pipelineLayout({
|
|
490
|
-
label: `shadow/${type.name}`,
|
|
491
|
-
bindGroupLayouts: [shadowView2, assets.layoutOf(type), store.layout]
|
|
492
|
-
}),
|
|
493
|
-
vertex: { module, entryPoint: "vs", buffers: SHADOW_BUFFERS },
|
|
494
|
-
fragment: masked ? { module, entryPoint: "fs_mask", targets: [] } : void 0,
|
|
495
|
-
primitive: { topology: "triangle-list", cullMode: variantCull(variant), frontFace: "ccw" },
|
|
496
|
-
depthStencil: { format: "depth32float", depthWriteEnabled: true, depthCompare: "greater" }
|
|
497
|
-
});
|
|
498
|
-
if (!pipeline) continue;
|
|
499
576
|
}
|
|
500
577
|
const mat = assets.material(world, material);
|
|
501
578
|
if (!mat?.bindGroup) continue;
|
|
@@ -531,6 +608,7 @@ function drawShadowCasters(ctx, target, view, offset, uniforms, pipelines, shado
|
|
|
531
608
|
pass.draw(gm.count, item.count, 0, item.first);
|
|
532
609
|
}
|
|
533
610
|
}
|
|
611
|
+
if (foliage && cam) foliage.drawShadow(ctx, cam, pass, offset, cascade);
|
|
534
612
|
pass.end();
|
|
535
613
|
}
|
|
536
614
|
const PASS_SHADOW = 2;
|
|
@@ -555,8 +633,10 @@ export {
|
|
|
555
633
|
drawShadowCasters,
|
|
556
634
|
fitCascades,
|
|
557
635
|
fitLocalShadows,
|
|
636
|
+
markShadowDrawn,
|
|
558
637
|
packShadowData,
|
|
559
638
|
pointTanHalf,
|
|
639
|
+
shadowRedraw,
|
|
560
640
|
shadowViewLayout,
|
|
561
641
|
sliceSphere
|
|
562
642
|
};
|
|
@@ -15,6 +15,7 @@ export declare const STANDARD_FIELDS: {
|
|
|
15
15
|
emissive: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Color, "f32">;
|
|
16
16
|
emissiveLuminance: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
17
17
|
doubleSided: import("@aethervtt/shard-core").FieldType<boolean, "u8">;
|
|
18
|
+
deferUntilReady: import("@aethervtt/shard-core").FieldType<boolean, "u8">;
|
|
18
19
|
alphaMode: import("@aethervtt/shard-core").FieldType<"additive" | "alpha" | "mask" | "opaque" | "premultiplied", "u8">;
|
|
19
20
|
alphaCutoff: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
20
21
|
normalScale: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
package/dist/standard-fields.js
CHANGED
|
@@ -42,6 +42,11 @@ const STANDARD_FIELDS = {
|
|
|
42
42
|
description: "Emitted luminance. 0 = not emissive."
|
|
43
43
|
}),
|
|
44
44
|
doubleSided: t.bool({ description: "Draw back faces too (no culling)." }),
|
|
45
|
+
deferUntilReady: t.bool({
|
|
46
|
+
// The asset layer reads it; shaders don't.
|
|
47
|
+
gpu: false,
|
|
48
|
+
description: "Baseline tier (0064): while a texture it binds waits for a copy in its slot's color space, skip its draws instead of showing the slot's loading fallback."
|
|
49
|
+
}),
|
|
45
50
|
alphaMode: t.enum(["opaque", "mask", "alpha", "additive", "premultiplied"], {
|
|
46
51
|
description: "opaque ignores alpha; mask discards pixels below alphaCutoff; alpha blends (transparent, drawn after opaque, sorted back to front); additive adds light (glows); premultiplied expects color already multiplied by alpha."
|
|
47
52
|
}),
|
package/dist/standard.js
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { definePlugin } from "@aethervtt/shard-runtime";
|
|
2
2
|
import { atmospherePlugin } from "./atmosphere-plugin.js";
|
|
3
|
+
import { cutawayPlugin } from "./cutaway-plugin.js";
|
|
4
|
+
import { decalsPlugin } from "./decals-plugin.js";
|
|
3
5
|
import { deferredPlugin } from "./deferred-plugin.js";
|
|
4
6
|
import { renderDescribePlugin } from "./describe-plugin.js";
|
|
5
7
|
import { dynamicResolutionPlugin } from "./dynamic-resolution.js";
|
|
6
8
|
import { environmentPlugin } from "./environment-plugin.js";
|
|
9
|
+
import { foliagePlugin } from "./foliage.js";
|
|
7
10
|
import { forwardCorePlugin } from "./forward.js";
|
|
8
11
|
import { fxaaPlugin } from "./fxaa.js";
|
|
9
12
|
import { gizmosPlugin } from "./gizmos-plugin.js";
|
|
13
|
+
import { interiorPlugin } from "./interior-plugin.js";
|
|
14
|
+
import { lensPlugin } from "./lens-plugin.js";
|
|
15
|
+
import { outlinePlugin } from "./outline-plugin.js";
|
|
10
16
|
import { pickingPlugin } from "./picking-plugin.js";
|
|
11
17
|
import { pixelPerfectPlugin } from "./pixel-perfect-plugin.js";
|
|
12
18
|
import { postPlugin } from "./post-plugin.js";
|
|
19
|
+
import { ribbonsPlugin } from "./ribbons-plugin.js";
|
|
20
|
+
import { shadowCatcherPlugin } from "./shadow-catcher.js";
|
|
13
21
|
import { skinningPlugin } from "./skinning-plugin.js";
|
|
22
|
+
import { viewVisibilityPlugin } from "./view-visibility-plugin.js";
|
|
14
23
|
function forwardPlugin(options = {}) {
|
|
15
24
|
return definePlugin({
|
|
16
25
|
name: "render/standard",
|
|
@@ -26,7 +35,16 @@ function forwardPlugin(options = {}) {
|
|
|
26
35
|
deferredPlugin,
|
|
27
36
|
skinningPlugin,
|
|
28
37
|
pixelPerfectPlugin,
|
|
38
|
+
lensPlugin,
|
|
39
|
+
outlinePlugin,
|
|
40
|
+
cutawayPlugin,
|
|
41
|
+
viewVisibilityPlugin,
|
|
42
|
+
interiorPlugin,
|
|
43
|
+
shadowCatcherPlugin,
|
|
44
|
+
foliagePlugin,
|
|
29
45
|
dynamicResolutionPlugin,
|
|
46
|
+
ribbonsPlugin,
|
|
47
|
+
decalsPlugin,
|
|
30
48
|
renderDescribePlugin
|
|
31
49
|
);
|
|
32
50
|
}
|
package/dist/stats.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type GpuUploads, type UploadCategory } from '@aethervtt/shard-gpu';
|
|
1
2
|
export interface ViewStats {
|
|
2
3
|
visible: number;
|
|
3
4
|
culled: number;
|
|
@@ -8,7 +9,50 @@ export interface ViewStats {
|
|
|
8
9
|
/** Pipeline changes in the opaque pass (sorting keeps these near the number of material types). */
|
|
9
10
|
pipelineSwitches?: number;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
/** What one frame (or a window of frames) wrote to the GPU and rebuilt (0055). */
|
|
13
|
+
export interface FrameRecord {
|
|
14
|
+
/** Bytes written, by what they were for. */
|
|
15
|
+
bytes: Record<UploadCategory, number>;
|
|
16
|
+
/** Scene data: every byte but `view` (camera and per-frame uniforms). */
|
|
17
|
+
sceneBytes: number;
|
|
18
|
+
/** Buffers and textures created. */
|
|
19
|
+
created: number;
|
|
20
|
+
/** Structure chunks rebuilt (0055). */
|
|
21
|
+
chunksRebuilt: number;
|
|
22
|
+
/** Meshes uploaded to the GPU: new ones, and ones whose data changed. */
|
|
23
|
+
meshesRebuilt: number;
|
|
24
|
+
/** Shadow maps (cascades and local shadow views) drawn. */
|
|
25
|
+
shadowMapsRendered: number;
|
|
26
|
+
}
|
|
27
|
+
/** Counts a system adds to during a frame; they land in `lastFrame` when the frame is submitted. */
|
|
28
|
+
export interface FrameCounts {
|
|
29
|
+
chunksRebuilt: number;
|
|
30
|
+
meshesRebuilt: number;
|
|
31
|
+
shadowMapsRendered: number;
|
|
32
|
+
}
|
|
33
|
+
/** Frames `RenderStatsMap.recent` sums over. */
|
|
34
|
+
export declare const RECENT_FRAMES = 60;
|
|
35
|
+
/**
|
|
36
|
+
* Per-view counts from the last frame (a Map by view name), plus what the last frame wrote to the
|
|
37
|
+
* GPU and rebuilt (`lastFrame`) and the sum over the last 60 rendered frames (`recent`).
|
|
38
|
+
*/
|
|
39
|
+
export declare class RenderStatsMap extends Map<string, ViewStats> {
|
|
40
|
+
readonly lastFrame: FrameRecord;
|
|
41
|
+
readonly recent: FrameRecord;
|
|
42
|
+
/** Counted during the frame being built. */
|
|
43
|
+
readonly current: FrameCounts;
|
|
44
|
+
/** Frames recorded. */
|
|
45
|
+
frames: number;
|
|
46
|
+
private readonly ring;
|
|
47
|
+
private readonly row;
|
|
48
|
+
private readonly seen;
|
|
49
|
+
/**
|
|
50
|
+
* Closes a frame: `uploads` is the owner's running total (`gpu.uploads(owner)`); the difference
|
|
51
|
+
* since the last call is this frame's. Allocates nothing.
|
|
52
|
+
*/
|
|
53
|
+
endFrame(uploads: GpuUploads | undefined): void;
|
|
54
|
+
}
|
|
55
|
+
export declare const RenderStats: import("@aethervtt/shard-core").ResourceDef<RenderStatsMap>;
|
|
12
56
|
export interface GpuMemoryData {
|
|
13
57
|
/** Textures uploaded by the forward renderer. */
|
|
14
58
|
textures: number;
|
package/dist/stats.js
CHANGED
|
@@ -1,7 +1,93 @@
|
|
|
1
1
|
import { defineResource } from "@aethervtt/shard-core";
|
|
2
|
+
import {
|
|
3
|
+
UPLOAD_CATEGORIES,
|
|
4
|
+
Upload
|
|
5
|
+
} from "@aethervtt/shard-gpu";
|
|
6
|
+
const RECENT_FRAMES = 60;
|
|
7
|
+
const FIELDS = UPLOAD_CATEGORIES.length + 4;
|
|
8
|
+
function frameRecord() {
|
|
9
|
+
const bytes = {};
|
|
10
|
+
for (const c of UPLOAD_CATEGORIES) bytes[c] = 0;
|
|
11
|
+
return {
|
|
12
|
+
bytes,
|
|
13
|
+
sceneBytes: 0,
|
|
14
|
+
created: 0,
|
|
15
|
+
chunksRebuilt: 0,
|
|
16
|
+
meshesRebuilt: 0,
|
|
17
|
+
shadowMapsRendered: 0
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
class RenderStatsMap extends Map {
|
|
21
|
+
lastFrame = frameRecord();
|
|
22
|
+
recent = frameRecord();
|
|
23
|
+
/** Counted during the frame being built. */
|
|
24
|
+
current = { chunksRebuilt: 0, meshesRebuilt: 0, shadowMapsRendered: 0 };
|
|
25
|
+
/** Frames recorded. */
|
|
26
|
+
frames = 0;
|
|
27
|
+
ring = new Float64Array(RECENT_FRAMES * FIELDS);
|
|
28
|
+
row = new Float64Array(FIELDS);
|
|
29
|
+
seen = new Float64Array(UPLOAD_CATEGORIES.length + 1);
|
|
30
|
+
/**
|
|
31
|
+
* Closes a frame: `uploads` is the owner's running total (`gpu.uploads(owner)`); the difference
|
|
32
|
+
* since the last call is this frame's. Allocates nothing.
|
|
33
|
+
*/
|
|
34
|
+
endFrame(uploads) {
|
|
35
|
+
const row = this.row;
|
|
36
|
+
const seen = this.seen;
|
|
37
|
+
const n = UPLOAD_CATEGORIES.length;
|
|
38
|
+
for (let i = 0; i < n; i++) {
|
|
39
|
+
const total = uploads ? uploads.bytes[i] : seen[i];
|
|
40
|
+
row[i] = total - seen[i];
|
|
41
|
+
seen[i] = total;
|
|
42
|
+
}
|
|
43
|
+
const created = uploads ? uploads.created : seen[n];
|
|
44
|
+
row[n] = created - seen[n];
|
|
45
|
+
seen[n] = created;
|
|
46
|
+
const cur = this.current;
|
|
47
|
+
row[n + 1] = cur.chunksRebuilt;
|
|
48
|
+
row[n + 2] = cur.meshesRebuilt;
|
|
49
|
+
row[n + 3] = cur.shadowMapsRendered;
|
|
50
|
+
cur.chunksRebuilt = cur.meshesRebuilt = cur.shadowMapsRendered = 0;
|
|
51
|
+
const ring = this.ring;
|
|
52
|
+
const slot = this.frames % RECENT_FRAMES * FIELDS;
|
|
53
|
+
this.frames++;
|
|
54
|
+
const last = this.lastFrame;
|
|
55
|
+
const recent = this.recent;
|
|
56
|
+
let lastScene = 0;
|
|
57
|
+
let recentScene = 0;
|
|
58
|
+
for (let i = 0; i < FIELDS; i++) {
|
|
59
|
+
const sum = recentField(recent, i) - ring[slot + i] + row[i];
|
|
60
|
+
ring[slot + i] = row[i];
|
|
61
|
+
setField(last, i, row[i]);
|
|
62
|
+
setField(recent, i, sum);
|
|
63
|
+
if (i < n && i !== Upload.view) {
|
|
64
|
+
lastScene += row[i];
|
|
65
|
+
recentScene += sum;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
last.sceneBytes = lastScene;
|
|
69
|
+
recent.sceneBytes = recentScene;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function recentField(r, i) {
|
|
73
|
+
const n = UPLOAD_CATEGORIES.length;
|
|
74
|
+
if (i < n) return r.bytes[UPLOAD_CATEGORIES[i]];
|
|
75
|
+
if (i === n) return r.created;
|
|
76
|
+
if (i === n + 1) return r.chunksRebuilt;
|
|
77
|
+
if (i === n + 2) return r.meshesRebuilt;
|
|
78
|
+
return r.shadowMapsRendered;
|
|
79
|
+
}
|
|
80
|
+
function setField(r, i, v) {
|
|
81
|
+
const n = UPLOAD_CATEGORIES.length;
|
|
82
|
+
if (i < n) r.bytes[UPLOAD_CATEGORIES[i]] = v;
|
|
83
|
+
else if (i === n) r.created = v;
|
|
84
|
+
else if (i === n + 1) r.chunksRebuilt = v;
|
|
85
|
+
else if (i === n + 2) r.meshesRebuilt = v;
|
|
86
|
+
else r.shadowMapsRendered = v;
|
|
87
|
+
}
|
|
2
88
|
const RenderStats = defineResource("render/Stats", {
|
|
3
|
-
description: "Per-view counts from the last frame
|
|
4
|
-
init: () =>
|
|
89
|
+
description: "Per-view counts from the last frame (visible, culled, hidden, pending, draw calls), and what the last frame and the last 60 wrote to the GPU and rebuilt.",
|
|
90
|
+
init: () => new RenderStatsMap()
|
|
5
91
|
});
|
|
6
92
|
const GpuMemory = defineResource("render/GpuMemory", {
|
|
7
93
|
description: "GPU memory used by uploaded textures.",
|
|
@@ -13,6 +99,8 @@ const RenderCounters = defineResource("render/Counters", {
|
|
|
13
99
|
});
|
|
14
100
|
export {
|
|
15
101
|
GpuMemory,
|
|
102
|
+
RECENT_FRAMES,
|
|
16
103
|
RenderCounters,
|
|
17
|
-
RenderStats
|
|
104
|
+
RenderStats,
|
|
105
|
+
RenderStatsMap
|
|
18
106
|
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type InferFields } from '@aethervtt/shard-core';
|
|
2
|
+
export declare const VARIATION_PATTERNS: readonly ['mottle', 'streaks', 'grain', 'cells', 'stagger', 'brushed'];
|
|
3
|
+
export type VariationPattern = (typeof VARIATION_PATTERNS)[number];
|
|
4
|
+
/** The variation's fields: one schema for validation, the inspector, and the GPU struct. */
|
|
5
|
+
export declare const VARIATION_FIELDS: {
|
|
6
|
+
strength: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
7
|
+
seed: import("@aethervtt/shard-core").FieldType<number, "u32">;
|
|
8
|
+
pattern: import("@aethervtt/shard-core").FieldType<"brushed" | "cells" | "grain" | "mottle" | "stagger" | "streaks", "u8">;
|
|
9
|
+
scale: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec2, "f32">;
|
|
10
|
+
warp: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
11
|
+
detail: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
12
|
+
bands: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
13
|
+
toneRange: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
14
|
+
coolTint: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
|
|
15
|
+
warmTint: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
|
|
16
|
+
roughnessRange: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
17
|
+
weathering: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
18
|
+
weatherThreshold: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec2, "f32">;
|
|
19
|
+
};
|
|
20
|
+
export type Variation = InferFields<typeof VARIATION_FIELDS>;
|
|
21
|
+
/** A partial variation: what presets and materials write (the rest takes the defaults). */
|
|
22
|
+
export type VariationInit = Partial<Variation>;
|
|
23
|
+
/** The GPU struct `surface::variation::VariationUniform`, generated from VARIATION_FIELDS. */
|
|
24
|
+
export declare const VariationUniform: import("@aethervtt/shard-core").ComponentDef<{
|
|
25
|
+
strength: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
26
|
+
seed: import("@aethervtt/shard-core").FieldType<number, "u32">;
|
|
27
|
+
pattern: import("@aethervtt/shard-core").FieldType<"brushed" | "cells" | "grain" | "mottle" | "stagger" | "streaks", "u8">;
|
|
28
|
+
scale: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec2, "f32">;
|
|
29
|
+
warp: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
30
|
+
detail: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
31
|
+
bands: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
32
|
+
toneRange: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
33
|
+
coolTint: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
|
|
34
|
+
warmTint: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec3, "f32">;
|
|
35
|
+
roughnessRange: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
36
|
+
weathering: import("@aethervtt/shard-core").FieldType<number, "f32">;
|
|
37
|
+
weatherThreshold: import("@aethervtt/shard-core").FieldType<import("@aethervtt/shard-core").Vec2, "f32">;
|
|
38
|
+
}>;
|
|
39
|
+
/** Where the WGSL struct lives: a material's generated module imports it from here. */
|
|
40
|
+
export declare const VARIATION_STRUCT = "surface::variation::VariationUniform";
|
|
41
|
+
/**
|
|
42
|
+
* Tuned variations, seeded from Aether's eight recipes (its patch sizes converted from pixels at
|
|
43
|
+
* 1.5 m per 70 px, its global intensity of 0.5 as `strength`). Plain data: spread one and
|
|
44
|
+
* override, or add your own. Nothing in the shader knows their names.
|
|
45
|
+
*/
|
|
46
|
+
export declare const SURFACE_PRESETS: Record<string, Variation>;
|
|
47
|
+
export interface SurfaceSample {
|
|
48
|
+
/** RGB multiplier for the base colour. */
|
|
49
|
+
tint: [number, number, number];
|
|
50
|
+
/** Added to roughness. */
|
|
51
|
+
roughness: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The variation at surface point `p` (metres): a tint multiplier and a roughness offset. The CPU
|
|
55
|
+
* mirror of WGSL `surface_variation`, for tests and for tools that preview a preset.
|
|
56
|
+
*/
|
|
57
|
+
export declare function surfaceVariation(v: Variation, p: ArrayLike<number>, out?: SurfaceSample): SurfaceSample;
|