@driftengine/core 4.4.2 → 4.5.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 +46 -0
- package/README.md +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -0
- package/dist/render/backend/api.d.ts +17 -11
- package/dist/render/backend/webgl2/glassTintPrograms.d.ts +13 -0
- package/dist/render/backend/webgl2/glassTintPrograms.js +38 -0
- package/dist/render/backend/webgl2/renderer.d.ts +79 -8
- package/dist/render/backend/webgl2/renderer.js +360 -105
- package/dist/render/backend/webgpu/buffers.d.ts +19 -1
- package/dist/render/backend/webgpu/buffers.js +27 -1
- package/dist/render/backend/webgpu/depthPass.d.ts +1 -1
- package/dist/render/backend/webgpu/depthPass.js +2 -1
- package/dist/render/backend/webgpu/flatPass.d.ts +2 -0
- package/dist/render/backend/webgpu/flatPass.js +20 -1
- package/dist/render/backend/webgpu/glassTintPass.d.ts +28 -0
- package/dist/render/backend/webgpu/glassTintPass.js +205 -0
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +60 -1
- package/dist/render/backend/webgpu/gpuDrivenPass.js +305 -5
- package/dist/render/backend/webgpu/instanced.d.ts +12 -1
- package/dist/render/backend/webgpu/instanced.js +20 -1
- package/dist/render/backend/webgpu/latePass.d.ts +26 -0
- package/dist/render/backend/webgpu/latePass.js +133 -0
- package/dist/render/backend/webgpu/lightVolumePass.js +5 -1
- package/dist/render/backend/webgpu/motionPass.d.ts +95 -0
- package/dist/render/backend/webgpu/motionPass.js +491 -0
- package/dist/render/backend/webgpu/pipelineCache.d.ts +10 -1
- package/dist/render/backend/webgpu/pipelineCache.js +11 -1
- package/dist/render/backend/webgpu/pointGlassTintPass.d.ts +32 -0
- package/dist/render/backend/webgpu/pointGlassTintPass.js +193 -0
- package/dist/render/backend/webgpu/pointShadowPass.d.ts +35 -6
- package/dist/render/backend/webgpu/pointShadowPass.js +105 -20
- package/dist/render/backend/webgpu/postPass.d.ts +2 -12
- package/dist/render/backend/webgpu/renderer.d.ts +171 -54
- package/dist/render/backend/webgpu/renderer.js +944 -390
- package/dist/render/backend/webgpu/scatterPass.js +2 -1
- package/dist/render/backend/webgpu/skinPaletteRing.d.ts +4 -0
- package/dist/render/backend/webgpu/skinPaletteRing.js +4 -0
- package/dist/render/backend/webgpu/snapshotMips.d.ts +29 -0
- package/dist/render/backend/webgpu/snapshotMips.js +52 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +5 -0
- package/dist/render/backend/webgpu/surfaceTexturePass.js +1 -1
- package/dist/render/glass.d.ts +45 -0
- package/dist/render/glass.js +39 -0
- package/dist/render/glassCasters.d.ts +40 -0
- package/dist/render/glassCasters.js +84 -0
- package/dist/render/glassShadow.d.ts +78 -0
- package/dist/render/glassShadow.js +125 -0
- package/dist/render/globalMediumPass.d.ts +2 -3
- package/dist/render/globalMediumPass.js +2 -8
- package/dist/render/gpudriven/lit.d.ts +12 -0
- package/dist/render/gpudriven/lit.js +23 -0
- package/dist/render/gpudriven/materialTable.d.ts +15 -5
- package/dist/render/gpudriven/materialTable.js +26 -6
- package/dist/render/gpudriven/pipeline.d.ts +1 -1
- package/dist/render/gpudriven/pipeline.js +4 -3
- package/dist/render/gpudriven/sunGlass.d.ts +35 -0
- package/dist/render/gpudriven/sunGlass.js +89 -0
- package/dist/render/lightBudget.d.ts +17 -5
- package/dist/render/lightBudget.js +17 -5
- package/dist/render/pointGlassTint.d.ts +59 -0
- package/dist/render/pointGlassTint.js +198 -0
- package/dist/render/pointShadowArray.d.ts +56 -3
- package/dist/render/pointShadowArray.js +127 -16
- package/dist/render/pointShadowMap.d.ts +23 -1
- package/dist/render/pointShadowMap.js +27 -1
- package/dist/render/recon/changeFrames.d.ts +15 -0
- package/dist/render/recon/changeFrames.js +21 -0
- package/dist/render/recon/lateRouting.d.ts +14 -0
- package/dist/render/recon/lateRouting.js +18 -0
- package/dist/render/recon/mover.d.ts +57 -0
- package/dist/render/recon/mover.js +86 -0
- package/dist/render/renderQuality.d.ts +35 -0
- package/dist/render/renderQuality.js +7 -0
- package/dist/render/rendererHarness.js +12 -0
- package/dist/render/sceneTarget.d.ts +7 -1
- package/dist/render/sceneTarget.js +58 -12
- package/dist/render/shaders/depth.d.ts +16 -1
- package/dist/render/shaders/depth.js +85 -9
- package/dist/render/shaders/flat/directionalShadow.js +91 -6
- package/dist/render/shaders/flat/glassTint.d.ts +6 -0
- package/dist/render/shaders/flat/glassTint.js +25 -0
- package/dist/render/shaders/flat/index.d.ts +13 -0
- package/dist/render/shaders/flat/index.js +4 -0
- package/dist/render/shaders/flat/lampGlass.d.ts +1 -0
- package/dist/render/shaders/flat/lampGlass.js +183 -0
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +115 -15
- package/dist/render/shaders/flat/pointShadow.d.ts +1 -1
- package/dist/render/shaders/flat/pointShadow.js +2 -0
- package/dist/render/shaders/flat/preamble.js +21 -6
- package/dist/render/shaders/generated/depth.wgsl.d.ts +227 -4
- package/dist/render/shaders/generated/depth.wgsl.js +227 -4
- package/dist/render/shaders/generated/flat.wgsl.d.ts +360 -312
- package/dist/render/shaders/generated/flat.wgsl.js +376 -328
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +3 -13
- package/dist/render/shaders/generated/globalMedium.wgsl.js +3 -13
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +3 -13
- package/dist/render/shaders/generated/lightVolume.wgsl.js +4 -14
- package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +29 -0
- package/dist/render/shaders/generated/octahedralResolve.wgsl.js +29 -0
- package/dist/render/shaders/globalMedium.js +6 -6
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +7 -0
- package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +86 -1
- package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +1 -1
- package/dist/render/shaders/gpudriven/cull.wgsl.js +11 -2
- package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +1 -1
- package/dist/render/shaders/gpudriven/materialTable.wgsl.js +3 -1
- package/dist/render/shaders/gpudriven/shade.wgsl.js +50 -1
- package/dist/render/shaders/gpudriven/sunGlass.wgsl.d.ts +9 -0
- package/dist/render/shaders/gpudriven/sunGlass.wgsl.js +133 -0
- package/dist/render/shaders/lightVolume.js +6 -6
- package/dist/render/shaders/octahedralResolve.d.ts +8 -0
- package/dist/render/shaders/octahedralResolve.js +48 -17
- package/dist/render/shaders/recon/lateDepth.wgsl.d.ts +1 -0
- package/dist/render/shaders/recon/lateDepth.wgsl.js +44 -0
- package/dist/render/shaders/recon/motion.wgsl.d.ts +1 -1
- package/dist/render/shaders/recon/motion.wgsl.js +84 -0
- package/dist/render/shadowCasters.d.ts +20 -1
- package/dist/render/shadowCasters.js +15 -1
- package/dist/render/shadowMap.d.ts +54 -5
- package/dist/render/shadowMap.js +190 -36
- package/dist/render/sunGlassTint.d.ts +25 -0
- package/dist/render/sunGlassTint.js +79 -0
- package/dist/render/translucentQueue.d.ts +6 -0
- package/dist/render/translucentQueue.js +15 -1
- package/package.json +6 -6
- package/src/index.ts +10 -0
- package/src/render/backend/api.ts +15 -9
- package/src/render/backend/webgl2/glassTintPrograms.ts +58 -0
- package/src/render/backend/webgl2/renderer.ts +401 -108
- package/src/render/backend/webgpu/buffers.ts +50 -2
- package/src/render/backend/webgpu/depthPass.ts +2 -1
- package/src/render/backend/webgpu/flatPass.ts +22 -1
- package/src/render/backend/webgpu/glassTintPass.ts +244 -0
- package/src/render/backend/webgpu/gpuDrivenPass.ts +349 -5
- package/src/render/backend/webgpu/instanced.ts +21 -1
- package/src/render/backend/webgpu/latePass.ts +152 -0
- package/src/render/backend/webgpu/lightVolumePass.ts +5 -1
- package/src/render/backend/webgpu/motionPass.ts +535 -0
- package/src/render/backend/webgpu/pipelineCache.ts +12 -1
- package/src/render/backend/webgpu/pointGlassTintPass.ts +233 -0
- package/src/render/backend/webgpu/pointShadowPass.ts +158 -26
- package/src/render/backend/webgpu/renderer.ts +1108 -421
- package/src/render/backend/webgpu/scatterPass.ts +2 -1
- package/src/render/backend/webgpu/skinPaletteRing.ts +4 -0
- package/src/render/backend/webgpu/snapshotMips.ts +80 -0
- package/src/render/backend/webgpu/surfaceTexturePass.ts +1 -1
- package/src/render/glass.ts +74 -0
- package/src/render/glassCasters.ts +164 -0
- package/src/render/glassShadow.ts +153 -0
- package/src/render/globalMediumPass.ts +4 -11
- package/src/render/gpudriven/lit.ts +31 -0
- package/src/render/gpudriven/materialTable.ts +28 -6
- package/src/render/gpudriven/pipeline.ts +4 -3
- package/src/render/gpudriven/sunGlass.ts +117 -0
- package/src/render/lightBudget.ts +19 -5
- package/src/render/pointGlassTint.ts +250 -0
- package/src/render/pointShadowArray.ts +188 -22
- package/src/render/pointShadowMap.ts +41 -0
- package/src/render/recon/changeFrames.ts +24 -0
- package/src/render/recon/lateRouting.ts +29 -0
- package/src/render/recon/mover.ts +118 -0
- package/src/render/renderQuality.ts +47 -0
- package/src/render/rendererHarness.ts +12 -0
- package/src/render/sceneTarget.ts +58 -11
- package/src/render/shaders/depth.ts +109 -9
- package/src/render/shaders/flat/directionalShadow.ts +97 -6
- package/src/render/shaders/flat/glassTint.ts +25 -0
- package/src/render/shaders/flat/index.ts +17 -0
- package/src/render/shaders/flat/lampGlass.ts +185 -0
- package/src/render/shaders/flat/main.ts +115 -15
- package/src/render/shaders/flat/pointShadow.ts +2 -0
- package/src/render/shaders/flat/preamble.ts +21 -6
- package/src/render/shaders/generated/depth.wgsl.ts +234 -4
- package/src/render/shaders/generated/flat.wgsl.ts +376 -328
- package/src/render/shaders/generated/globalMedium.wgsl.ts +3 -13
- package/src/render/shaders/generated/lightVolume.wgsl.ts +4 -14
- package/src/render/shaders/generated/octahedralResolve.wgsl.ts +30 -0
- package/src/render/shaders/globalMedium.ts +6 -6
- package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +88 -1
- package/src/render/shaders/gpudriven/cull.wgsl.ts +11 -2
- package/src/render/shaders/gpudriven/materialTable.wgsl.ts +3 -1
- package/src/render/shaders/gpudriven/shade.wgsl.ts +50 -1
- package/src/render/shaders/gpudriven/sunGlass.wgsl.ts +139 -0
- package/src/render/shaders/lightVolume.ts +6 -6
- package/src/render/shaders/octahedralResolve.ts +50 -17
- package/src/render/shaders/recon/lateDepth.wgsl.ts +47 -0
- package/src/render/shaders/recon/motion.wgsl.ts +84 -0
- package/src/render/shadowCasters.ts +28 -1
- package/src/render/shadowMap.ts +231 -37
- package/src/render/sunGlassTint.ts +86 -0
- package/src/render/translucentQueue.ts +20 -1
|
@@ -92,6 +92,11 @@ import {
|
|
|
92
92
|
gpuDrivenSupported,
|
|
93
93
|
recordGpuDrivenStages,
|
|
94
94
|
} from '../../gpudriven/pipeline.ts';
|
|
95
|
+
import { resolveGlass, type GlassOptions, type ResolvedGlass } from '../../glass.ts';
|
|
96
|
+
import type { GlassShadows } from '../../renderQuality.ts';
|
|
97
|
+
import { GLASS_TINT_BLEND } from './glassTintPass.ts';
|
|
98
|
+
import { SnapshotMips } from './snapshotMips.ts';
|
|
99
|
+
import type { MipPipelines } from './surfaceTexturePass.ts';
|
|
95
100
|
import type { GpuDrivenFrameShape, GpuDrivenPassName } from '../../gpudriven/pipeline.ts';
|
|
96
101
|
import { createDeps, resetDeps } from '../../frame/deps.ts';
|
|
97
102
|
import { createGraphPasses, createGraphScratch, scheduleGraph } from '../../frame/graphSchedule.ts';
|
|
@@ -369,6 +374,14 @@ export interface GpuDrivenMaterial {
|
|
|
369
374
|
* blend and said nothing else gets — visible, and therefore findable.
|
|
370
375
|
*/
|
|
371
376
|
readonly opacity?: number;
|
|
377
|
+
/**
|
|
378
|
+
* Glass: how much light passes, how milky it is, and the colour it takes — `GlassOptions`, as the
|
|
379
|
+
* forward path's `drawTranslucentMesh` takes it. Absent, or letting nothing through, is not glass.
|
|
380
|
+
*
|
|
381
|
+
* **A glass material is drawn in the blended half whatever `blend` says**, because a visibility
|
|
382
|
+
* buffer holds one surface a pixel and glass is the pane and what is behind it.
|
|
383
|
+
*/
|
|
384
|
+
readonly glass?: GlassOptions;
|
|
372
385
|
}
|
|
373
386
|
|
|
374
387
|
/** What the pass needs told once a frame, before `beginFrame`. */
|
|
@@ -473,6 +486,12 @@ export interface GpuDrivenShadowOptions {
|
|
|
473
486
|
* texels, and reaches toward the sun as far as the scene does.
|
|
474
487
|
*/
|
|
475
488
|
readonly followRadius?: number;
|
|
489
|
+
/**
|
|
490
|
+
* What the sun keeps through glass: `RenderQualityOptions.glassShadows`, which a contributed pass
|
|
491
|
+
* is not handed and so takes here. `'full'` by default, as there; `'half'` halves the tint and
|
|
492
|
+
* `'off'` draws a glass material's shadow as nothing, which is what it cast before.
|
|
493
|
+
*/
|
|
494
|
+
readonly glass?: GlassShadows;
|
|
476
495
|
}
|
|
477
496
|
|
|
478
497
|
interface Level {
|
|
@@ -675,6 +694,30 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
675
694
|
private latentClamp: GPUSampler | null = null;
|
|
676
695
|
private latentRepeat: GPUSampler | null = null;
|
|
677
696
|
private shadowView: GPUTextureView | null = null;
|
|
697
|
+
/** The nearest pane's depth from the sun: the shadow texture's second layer, where glass casts. */
|
|
698
|
+
private glassDepthView: GPUTextureView | null = null;
|
|
699
|
+
/** What the panes let through, as the sun sees them, with the chain frost reads. */
|
|
700
|
+
private glassTintTexture: GPUTexture | null = null;
|
|
701
|
+
private glassTintTarget: GPUTextureView | null = null;
|
|
702
|
+
private glassTintSampled: GPUTextureView | null = null;
|
|
703
|
+
private glassTintMips: SnapshotMips | null = null;
|
|
704
|
+
/** One white texel, bound where no glass casts, which the lookup reads as none. */
|
|
705
|
+
private glassTintNone: GPUTexture | null = null;
|
|
706
|
+
private readonly glassMode: GlassShadows;
|
|
707
|
+
/** Whether the sun's glass pass runs at all: a glass material, and glass shadows not off. */
|
|
708
|
+
private readonly castsGlass: boolean;
|
|
709
|
+
private glassList: GPUBuffer | null = null;
|
|
710
|
+
private glassArgs: GPUBuffer | null = null;
|
|
711
|
+
private glassLodBuffer: GPUBuffer | null = null;
|
|
712
|
+
private readonly lodParamsGlass = new Float32Array(8);
|
|
713
|
+
private shadowCullSettingsGlass: GPUBuffer | null = null;
|
|
714
|
+
private glassLodGroup: GPUBindGroup | null = null;
|
|
715
|
+
private glassCullGroup: GPUBindGroup | null = null;
|
|
716
|
+
private glassCompactGroup: GPUBindGroup | null = null;
|
|
717
|
+
private glassDepthPipeline: GPURenderPipeline | null = null;
|
|
718
|
+
private glassDepthGroup: GPUBindGroup | null = null;
|
|
719
|
+
private glassTintPipeline: GPURenderPipeline | null = null;
|
|
720
|
+
private glassTintGroup: GPUBindGroup | null = null;
|
|
678
721
|
/**
|
|
679
722
|
* What is bound as the probe where the frame has none.
|
|
680
723
|
*
|
|
@@ -790,7 +833,26 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
790
833
|
private visibilityTexture: GPUTexture | null = null;
|
|
791
834
|
private depthTexture: GPUTexture | null = null;
|
|
792
835
|
private colourTexture: GPUTexture | null = null;
|
|
836
|
+
/** Level 0: what the shading writes, the resolve lays over and the blit presents. */
|
|
793
837
|
private colourView: GPUTextureView | null = null;
|
|
838
|
+
/** Every level, for glass to read at the level its frost picks. Level 0 alone with no glass. */
|
|
839
|
+
private colourSampledView: GPUTextureView | null = null;
|
|
840
|
+
/** The chain glass reads, filled from the shaded picture each frame; null in a scene with none. */
|
|
841
|
+
private colourMips: SnapshotMips | null = null;
|
|
842
|
+
/** Whether any material is glass, which is what earns the colour its chain: see `buildTargets`. */
|
|
843
|
+
private readonly hasGlass: boolean;
|
|
844
|
+
/** The pipelines the chain draws with, one a format. */
|
|
845
|
+
private readonly mipPipelineCache = new Map<string, GPURenderPipeline>();
|
|
846
|
+
private readonly mipPipelines: MipPipelines = {
|
|
847
|
+
get: (key, describe) => {
|
|
848
|
+
const held = this.mipPipelineCache.get(key);
|
|
849
|
+
if (held !== undefined) return held;
|
|
850
|
+
const made = (this.device as GPUDevice).createRenderPipeline(describe());
|
|
851
|
+
this.mipPipelineCache.set(key, made);
|
|
852
|
+
return made;
|
|
853
|
+
},
|
|
854
|
+
};
|
|
855
|
+
private glassSampler: GPUSampler | null = null;
|
|
794
856
|
private visibility: GPUBuffer | null = null;
|
|
795
857
|
private hzb: GPUBuffer | null = null;
|
|
796
858
|
private levelStart: GPUBuffer | null = null;
|
|
@@ -921,7 +983,10 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
921
983
|
this.decode = packDecodeTables(this.programs.programs);
|
|
922
984
|
this.scene = scene;
|
|
923
985
|
this.materials = materials;
|
|
986
|
+
this.hasGlass = materials.some((material) => resolveGlass(material.glass, glassProbe));
|
|
924
987
|
this.shadowSize = shadow.mapSize ?? DEFAULT_RENDER_QUALITY.directionalShadowMapSize;
|
|
988
|
+
this.glassMode = shadow.glass ?? DEFAULT_RENDER_QUALITY.glassShadows;
|
|
989
|
+
this.castsGlass = this.hasGlass && this.glassMode !== 'off';
|
|
925
990
|
this.shadowMaxDistance =
|
|
926
991
|
shadow.maxDistance ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxDistance;
|
|
927
992
|
this.shadowMaxSlope = shadow.maxSlope ?? DEFAULT_RENDER_QUALITY.directionalShadowMaxSlope;
|
|
@@ -1163,6 +1228,10 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
1163
1228
|
this.shadowArgs = this.storage(device, 'draw shadow', shadowArgs, INDIRECT | COPY_SRC);
|
|
1164
1229
|
this.shadowArgsTwo = this.storage(device, 'draw shadow two', shadowArgs, INDIRECT | COPY_SRC);
|
|
1165
1230
|
this.shadowSelected = this.empty(device, 'shadow selected', count * 4);
|
|
1231
|
+
/* The sun's glass: its own list and arguments, over the light's selection once the map is done. */
|
|
1232
|
+
this.glassList = this.empty(device, 'shadow glass list', count * 4);
|
|
1233
|
+
this.glassArgs = this.storage(device, 'draw shadow glass', shadowArgs, INDIRECT | COPY_SRC);
|
|
1234
|
+
this.glassLodBuffer = this.empty(device, 'lod params glass', 8 * 4);
|
|
1166
1235
|
this.shadowKeep = this.empty(device, 'shadow keep', count * 4);
|
|
1167
1236
|
this.shadowPlanes = this.empty(device, 'shadow planes', FRUSTUM_FLOATS * 4);
|
|
1168
1237
|
this.shadowHistories = [
|
|
@@ -1198,6 +1267,12 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
1198
1267
|
'cull settings, shadow two',
|
|
1199
1268
|
this.shadowCullValues,
|
|
1200
1269
|
);
|
|
1270
|
+
/* The glass pass's: no pyramid and no cones, since a pane casts from either side. */
|
|
1271
|
+
this.shadowCullSettingsGlass = this.storage(
|
|
1272
|
+
device,
|
|
1273
|
+
'cull settings, shadow glass',
|
|
1274
|
+
this.shadowCullValues,
|
|
1275
|
+
);
|
|
1201
1276
|
this.shadowCompactSettings = this.storage(
|
|
1202
1277
|
device,
|
|
1203
1278
|
'phase shadow',
|
|
@@ -1219,11 +1294,61 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
1219
1294
|
*/
|
|
1220
1295
|
this.shadowTexture = device.createTexture({
|
|
1221
1296
|
label: 'gpu-driven shadow',
|
|
1222
|
-
|
|
1297
|
+
/* A second layer for the nearest pane where a material is glass, and none where none is. */
|
|
1298
|
+
size: {
|
|
1299
|
+
width: this.shadowSize,
|
|
1300
|
+
height: this.shadowSize,
|
|
1301
|
+
depthOrArrayLayers: this.castsGlass ? 2 : 1,
|
|
1302
|
+
},
|
|
1223
1303
|
format: SHADOW_FORMAT,
|
|
1224
1304
|
usage: RENDER_ATTACHMENT | TEXTURE_BINDING,
|
|
1225
1305
|
});
|
|
1226
|
-
|
|
1306
|
+
const layer = (at: number): GPUTextureView =>
|
|
1307
|
+
(this.shadowTexture as GPUTexture).createView({
|
|
1308
|
+
dimension: '2d',
|
|
1309
|
+
baseArrayLayer: at,
|
|
1310
|
+
arrayLayerCount: 1,
|
|
1311
|
+
});
|
|
1312
|
+
this.shadowView = layer(0);
|
|
1313
|
+
this.glassDepthView = this.castsGlass ? layer(1) : null;
|
|
1314
|
+
const tintSize =
|
|
1315
|
+
this.glassMode === 'half' ? Math.max(1, this.shadowSize >> 1) : this.shadowSize;
|
|
1316
|
+
this.glassTintTexture = this.castsGlass
|
|
1317
|
+
? device.createTexture({
|
|
1318
|
+
label: 'gpu-driven glass tint',
|
|
1319
|
+
size: { width: tintSize, height: tintSize },
|
|
1320
|
+
format: 'rgba8unorm',
|
|
1321
|
+
mipLevelCount: Math.floor(Math.log2(tintSize)) + 1,
|
|
1322
|
+
usage: RENDER_ATTACHMENT | TEXTURE_BINDING,
|
|
1323
|
+
})
|
|
1324
|
+
: null;
|
|
1325
|
+
if (this.glassTintTexture !== null) {
|
|
1326
|
+
this.glassTintTarget = this.glassTintTexture.createView({
|
|
1327
|
+
baseMipLevel: 0,
|
|
1328
|
+
mipLevelCount: 1,
|
|
1329
|
+
});
|
|
1330
|
+
this.glassTintSampled = this.glassTintTexture.createView();
|
|
1331
|
+
this.glassTintMips = new SnapshotMips(
|
|
1332
|
+
device,
|
|
1333
|
+
this.mipPipelines,
|
|
1334
|
+
this.glassTintTexture,
|
|
1335
|
+
'rgba8unorm',
|
|
1336
|
+
null,
|
|
1337
|
+
'gpu-driven glass tint mips',
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
this.glassTintNone = device.createTexture({
|
|
1341
|
+
label: 'gpu-driven no glass',
|
|
1342
|
+
size: { width: 1, height: 1 },
|
|
1343
|
+
format: 'rgba8unorm',
|
|
1344
|
+
usage: TEXTURE_BINDING | TEXTURE_COPY_DST,
|
|
1345
|
+
});
|
|
1346
|
+
device.queue.writeTexture(
|
|
1347
|
+
{ texture: this.glassTintNone },
|
|
1348
|
+
new Uint8Array([255, 255, 255, 255]),
|
|
1349
|
+
{ bytesPerRow: 4 },
|
|
1350
|
+
{ width: 1, height: 1 },
|
|
1351
|
+
);
|
|
1227
1352
|
|
|
1228
1353
|
this.emptyEnvironment = device.createTexture({
|
|
1229
1354
|
label: 'gpu-driven no environment',
|
|
@@ -1538,6 +1663,37 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
1538
1663
|
});
|
|
1539
1664
|
this.shadowGroup = shadowRasterFor(this.shadowList as GPUBuffer);
|
|
1540
1665
|
this.shadowGroupTwo = shadowRasterFor(this.shadowListTwo as GPUBuffer);
|
|
1666
|
+
/*
|
|
1667
|
+
* **The nearest pane, from the sun: the same raster, culling nothing**, since a pane casts from
|
|
1668
|
+
* either side; into the shadow texture's second layer. Built only where glass casts.
|
|
1669
|
+
*/
|
|
1670
|
+
if (this.castsGlass) {
|
|
1671
|
+
this.glassDepthPipeline = device.createRenderPipeline({
|
|
1672
|
+
label: 'gpu-driven shadow glass',
|
|
1673
|
+
layout: 'auto',
|
|
1674
|
+
vertex: { module: raster, entryPoint: 'vertexMain' },
|
|
1675
|
+
primitive: { topology: 'triangle-list', cullMode: 'none', frontFace: 'cw' },
|
|
1676
|
+
depthStencil: {
|
|
1677
|
+
format: SHADOW_FORMAT,
|
|
1678
|
+
depthWriteEnabled: true,
|
|
1679
|
+
depthCompare: 'less',
|
|
1680
|
+
depthBias: 4,
|
|
1681
|
+
depthBiasSlopeScale: 1.1,
|
|
1682
|
+
},
|
|
1683
|
+
});
|
|
1684
|
+
this.glassDepthGroup = device.createBindGroup({
|
|
1685
|
+
layout: this.glassDepthPipeline.getBindGroupLayout(0),
|
|
1686
|
+
entries: [
|
|
1687
|
+
{ binding: 0, resource: { buffer: this.shadowMatrix as GPUBuffer } },
|
|
1688
|
+
{ binding: 1, resource: { buffer: this.glassList as GPUBuffer } },
|
|
1689
|
+
{ binding: 2, resource: { buffer: this.clusterMeta as GPUBuffer } },
|
|
1690
|
+
{ binding: 3, resource: { buffer: this.indices as GPUBuffer } },
|
|
1691
|
+
{ binding: 4, resource: { buffer: this.vertices as GPUBuffer } },
|
|
1692
|
+
{ binding: 5, resource: { buffer: this.transformBuffer as GPUBuffer } },
|
|
1693
|
+
{ binding: 6, resource: { buffer: this.materialOf as GPUBuffer } },
|
|
1694
|
+
],
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1541
1697
|
|
|
1542
1698
|
/*
|
|
1543
1699
|
* **The transparent half's raster: one indirect draw into two targets at once.**
|
|
@@ -1604,6 +1760,38 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
1604
1760
|
},
|
|
1605
1761
|
});
|
|
1606
1762
|
this.watchBlendPipeline(device);
|
|
1763
|
+
/*
|
|
1764
|
+
* **What a pane lets through, from the sun**: the blended raster's vertex stage handed the
|
|
1765
|
+
* light's matrix and the glass list, and \`glassTintFrag\` for the colour — white target, a
|
|
1766
|
+
* multiplying blend, no depth, so every pane on a ray counts in any order.
|
|
1767
|
+
*/
|
|
1768
|
+
if (this.castsGlass) {
|
|
1769
|
+
this.glassTintPipeline = device.createRenderPipeline({
|
|
1770
|
+
label: 'gpu-driven shadow tint',
|
|
1771
|
+
layout: 'auto',
|
|
1772
|
+
vertex: { module: blend, entryPoint: 'blendVert' },
|
|
1773
|
+
fragment: {
|
|
1774
|
+
module: blend,
|
|
1775
|
+
entryPoint: 'glassTintFrag',
|
|
1776
|
+
targets: [{ format: 'rgba8unorm', blend: GLASS_TINT_BLEND }],
|
|
1777
|
+
},
|
|
1778
|
+
primitive: { topology: 'triangle-list', cullMode: 'none' },
|
|
1779
|
+
});
|
|
1780
|
+
this.glassTintGroup = device.createBindGroup({
|
|
1781
|
+
layout: this.glassTintPipeline.getBindGroupLayout(0),
|
|
1782
|
+
entries: [
|
|
1783
|
+
{ binding: 0, resource: { buffer: this.shadowMatrix as GPUBuffer } },
|
|
1784
|
+
{ binding: 1, resource: { buffer: this.glassList as GPUBuffer } },
|
|
1785
|
+
{ binding: 2, resource: { buffer: this.clusterMeta as GPUBuffer } },
|
|
1786
|
+
{ binding: 3, resource: { buffer: this.indices as GPUBuffer } },
|
|
1787
|
+
{ binding: 4, resource: { buffer: this.vertices as GPUBuffer } },
|
|
1788
|
+
{ binding: 5, resource: { buffer: this.transformBuffer as GPUBuffer } },
|
|
1789
|
+
{ binding: 6, resource: { buffer: this.materialOf as GPUBuffer } },
|
|
1790
|
+
{ binding: 7, resource: { buffer: this.materialTable as GPUBuffer } },
|
|
1791
|
+
{ binding: 8, resource: { buffer: this.frameBuffer as GPUBuffer } },
|
|
1792
|
+
],
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1607
1795
|
|
|
1608
1796
|
/*
|
|
1609
1797
|
* **Premultiplied over, where `renderer.ts`'s composite is a lerp**, and `blendRaster.wgsl.ts`
|
|
@@ -1796,6 +1984,39 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
1796
1984
|
shadowCullFor(this.shadowCullSettings as GPUBuffer),
|
|
1797
1985
|
shadowCullFor(this.shadowCullSettingsTwo as GPUBuffer),
|
|
1798
1986
|
];
|
|
1987
|
+
/*
|
|
1988
|
+
* **The sun's glass cut: the light's selection again, of the glass alone**, once the map is
|
|
1989
|
+
* drawn and those buffers are free. The camera's level of detail, as the map's; every pane in
|
|
1990
|
+
* the light's frustum kept, as the blended half keeps every pane — so compacted as phase two
|
|
1991
|
+
* against a history of zeros, exactly as that half is.
|
|
1992
|
+
*/
|
|
1993
|
+
if (this.castsGlass) {
|
|
1994
|
+
this.glassLodGroup = device.createBindGroup({
|
|
1995
|
+
layout: (this.lodPipeline as GPUComputePipeline).getBindGroupLayout(0),
|
|
1996
|
+
entries: [
|
|
1997
|
+
{ binding: 0, resource: { buffer: this.glassLodBuffer as GPUBuffer } },
|
|
1998
|
+
{ binding: 1, resource: { buffer: this.clusterLod as GPUBuffer } },
|
|
1999
|
+
{ binding: 2, resource: { buffer: this.shadowSelected as GPUBuffer } },
|
|
2000
|
+
{ binding: 3, resource: { buffer: this.clusterMeta as GPUBuffer } },
|
|
2001
|
+
{ binding: 4, resource: { buffer: this.instanceNone as GPUBuffer } },
|
|
2002
|
+
{ binding: 5, resource: { buffer: this.materialOf as GPUBuffer } },
|
|
2003
|
+
{ binding: 6, resource: { buffer: this.materialTable as GPUBuffer } },
|
|
2004
|
+
],
|
|
2005
|
+
});
|
|
2006
|
+
this.glassCullGroup = shadowCullFor(this.shadowCullSettingsGlass as GPUBuffer);
|
|
2007
|
+
this.glassCompactGroup = device.createBindGroup({
|
|
2008
|
+
layout: (this.compactPipeline as GPUComputePipeline).getBindGroupLayout(0),
|
|
2009
|
+
entries: [
|
|
2010
|
+
{ binding: 0, resource: { buffer: this.blendCompactSettings as GPUBuffer } },
|
|
2011
|
+
{ binding: 1, resource: { buffer: this.shadowSelected as GPUBuffer } },
|
|
2012
|
+
{ binding: 2, resource: { buffer: this.shadowKeep as GPUBuffer } },
|
|
2013
|
+
{ binding: 3, resource: { buffer: this.zeroHistory as GPUBuffer } },
|
|
2014
|
+
{ binding: 4, resource: { buffer: this.glassList as GPUBuffer } },
|
|
2015
|
+
{ binding: 5, resource: { buffer: this.historySink as GPUBuffer } },
|
|
2016
|
+
{ binding: 6, resource: { buffer: this.glassArgs as GPUBuffer } },
|
|
2017
|
+
],
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
1799
2020
|
this.shadowSeedGroup = device.createBindGroup({
|
|
1800
2021
|
layout: (this.shadowSeedPipeline as GPUComputePipeline).getBindGroupLayout(0),
|
|
1801
2022
|
entries: [
|
|
@@ -1998,11 +2219,29 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
1998
2219
|
label: 'gpu-driven colour',
|
|
1999
2220
|
size: { width: stride, height },
|
|
2000
2221
|
format: 'rgba16float',
|
|
2222
|
+
/*
|
|
2223
|
+
* **A chain only where a material is glass**, which a frosted pane reads a coarser level of,
|
|
2224
|
+
* as the forward path's refraction copy does. A scene with no glass allocates exactly the one
|
|
2225
|
+
* level it always did.
|
|
2226
|
+
*/
|
|
2227
|
+
mipLevelCount: this.hasGlass ? Math.floor(Math.log2(Math.max(stride, height))) + 1 : 1,
|
|
2001
2228
|
/* `RENDER_ATTACHMENT` only so a clear-only render pass can empty it each frame: a storage
|
|
2002
2229
|
texture has no clear, and the alternative is a dispatch over every pixel. */
|
|
2003
2230
|
usage: STORAGE_BINDING | TEXTURE_BINDING | RENDER_ATTACHMENT,
|
|
2004
2231
|
});
|
|
2005
|
-
|
|
2232
|
+
/* A storage binding takes one level, so everything that writes or presents reads level 0. */
|
|
2233
|
+
this.colourView = this.colourTexture.createView({ baseMipLevel: 0, mipLevelCount: 1 });
|
|
2234
|
+
this.colourSampledView = this.colourTexture.createView();
|
|
2235
|
+
this.colourMips = this.hasGlass
|
|
2236
|
+
? new SnapshotMips(
|
|
2237
|
+
device,
|
|
2238
|
+
this.mipPipelines,
|
|
2239
|
+
this.colourTexture,
|
|
2240
|
+
'rgba16float',
|
|
2241
|
+
null,
|
|
2242
|
+
'gpu-driven colour mips',
|
|
2243
|
+
)
|
|
2244
|
+
: null;
|
|
2006
2245
|
this.oitAccum = device.createTexture({
|
|
2007
2246
|
label: 'gpu-driven oit accum',
|
|
2008
2247
|
size: { width: stride, height },
|
|
@@ -2158,13 +2397,23 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
2158
2397
|
{ binding: 16, resource: this.latentRepeat as GPUSampler },
|
|
2159
2398
|
{ binding: 17, resource: { buffer: this.decodeNodes as GPUBuffer } },
|
|
2160
2399
|
{ binding: 18, resource: { buffer: this.decodeWeights as GPUBuffer } },
|
|
2400
|
+
/* The sun's glass, or the opaque map and a white texel where none casts. */
|
|
2401
|
+
{
|
|
2402
|
+
binding: 19,
|
|
2403
|
+
resource: this.glassDepthView ?? (this.shadowView as GPUTextureView),
|
|
2404
|
+
},
|
|
2405
|
+
{
|
|
2406
|
+
binding: 20,
|
|
2407
|
+
resource: this.glassTintSampled ?? (this.glassTintNone as GPUTexture).createView(),
|
|
2408
|
+
},
|
|
2409
|
+
{ binding: 21, resource: this.glassSamplerFor(device) },
|
|
2161
2410
|
],
|
|
2162
2411
|
});
|
|
2163
2412
|
|
|
2164
2413
|
this.blitGroup = device.createBindGroup({
|
|
2165
2414
|
layout: (this.blitPipeline as GPURenderPipeline).getBindGroupLayout(0),
|
|
2166
2415
|
entries: [
|
|
2167
|
-
{ binding: 0, resource:
|
|
2416
|
+
{ binding: 0, resource: this.colourView as GPUTextureView },
|
|
2168
2417
|
/* The depth the raster wrote, sampled so the blit can hand it to the frame. */
|
|
2169
2418
|
...(this.presentDepth
|
|
2170
2419
|
? [
|
|
@@ -2209,6 +2458,12 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
2209
2458
|
{ binding: 13, resource: this.latentRepeat as GPUSampler },
|
|
2210
2459
|
{ binding: 14, resource: { buffer: this.decodeNodes as GPUBuffer } },
|
|
2211
2460
|
{ binding: 15, resource: { buffer: this.decodeWeights as GPUBuffer } },
|
|
2461
|
+
/* What the opaque half drew, for glass to show: `blendRaster.wgsl.ts`. */
|
|
2462
|
+
{ binding: 16, resource: this.colourSampledView as GPUTextureView },
|
|
2463
|
+
{
|
|
2464
|
+
binding: 17,
|
|
2465
|
+
resource: this.glassSamplerFor(device),
|
|
2466
|
+
},
|
|
2212
2467
|
],
|
|
2213
2468
|
});
|
|
2214
2469
|
|
|
@@ -2467,6 +2722,16 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
2467
2722
|
queue.writeBuffer(this.shadowCullSettings as GPUBuffer, 0, this.shadowCullValues);
|
|
2468
2723
|
this.shadowCullValues[3] = this.occlusion ? 1 : 0;
|
|
2469
2724
|
queue.writeBuffer(this.shadowCullSettingsTwo as GPUBuffer, 0, this.shadowCullValues);
|
|
2725
|
+
if (this.castsGlass) {
|
|
2726
|
+
/* No pyramid and no cones, and the cones put back for the next frame's first write. */
|
|
2727
|
+
this.shadowCullValues[3] = 0;
|
|
2728
|
+
this.shadowCullValues[CULL_CONES] = 0;
|
|
2729
|
+
queue.writeBuffer(this.shadowCullSettingsGlass as GPUBuffer, 0, this.shadowCullValues);
|
|
2730
|
+
this.shadowCullValues[CULL_CONES] = 1;
|
|
2731
|
+
this.lodParamsGlass.set(this.lodParamsBlend);
|
|
2732
|
+
this.lodParamsGlass[7] = 1;
|
|
2733
|
+
queue.writeBuffer(this.glassLodBuffer as GPUBuffer, 0, this.lodParamsGlass);
|
|
2734
|
+
}
|
|
2470
2735
|
queue.writeBuffer(this.planesBuffer as GPUBuffer, 0, this.planes);
|
|
2471
2736
|
queue.writeBuffer(this.frameBuffer as GPUBuffer, 0, params);
|
|
2472
2737
|
queue.writeBuffer(this.lodBuffer as GPUBuffer, 0, this.lodParams);
|
|
@@ -2524,7 +2789,9 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
2524
2789
|
* one: the table is written when the pass is built. A scene with nothing blended schedules the
|
|
2525
2790
|
* three transparent stages away entirely and encodes the frame it encoded before they existed.
|
|
2526
2791
|
*/
|
|
2527
|
-
|
|
2792
|
+
/* Glass is the blended half's whatever its flag says: a visibility buffer holds one surface. */
|
|
2793
|
+
this.shape.blended =
|
|
2794
|
+
this.hasGlass || this.materials.some((material) => material.blend === true);
|
|
2528
2795
|
|
|
2529
2796
|
/* `instanceCount` is the one word the compaction touches; the other three never change. */
|
|
2530
2797
|
encoder.clearBuffer(argsOne, 4, 4);
|
|
@@ -2707,6 +2974,8 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
2707
2974
|
*/
|
|
2708
2975
|
if (!this.blendUsable || this.blendPipeline === null || this.blendRasterGroup === null)
|
|
2709
2976
|
return;
|
|
2977
|
+
/* The shaded picture's chain, which glass reads: after `shade`, before the panes. */
|
|
2978
|
+
this.colourMips?.record(encoder);
|
|
2710
2979
|
const pass = encoder.beginRenderPass({
|
|
2711
2980
|
label: 'gpu-driven blend draw',
|
|
2712
2981
|
colorAttachments: [
|
|
@@ -3033,6 +3302,59 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
3033
3302
|
second.end();
|
|
3034
3303
|
this.drawShadowHalf(encoder, 1, writes);
|
|
3035
3304
|
this.shadowFlipped = !this.shadowFlipped;
|
|
3305
|
+
if (this.castsGlass && this.blendUsable) this.drawShadowGlass(encoder, groups);
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
/**
|
|
3309
|
+
* The sun's glass, after its opaque map: the glass cut from the light, then the panes drawn
|
|
3310
|
+
* twice — where the nearest one is, and what they let through, multiplied — and the tint's
|
|
3311
|
+
* chain filled for frost to read. The forward path's `flushSunGlass`, in this pipeline's terms.
|
|
3312
|
+
*/
|
|
3313
|
+
private drawShadowGlass(encoder: GPUCommandEncoder, groups: number): void {
|
|
3314
|
+
encoder.clearBuffer(this.glassArgs as GPUBuffer, 4, 4);
|
|
3315
|
+
const cut = encoder.beginComputePass({ label: 'gpu-driven shadow glass cut' });
|
|
3316
|
+
cut.setPipeline(this.lodPipeline as GPUComputePipeline);
|
|
3317
|
+
cut.setBindGroup(0, this.glassLodGroup as GPUBindGroup);
|
|
3318
|
+
cut.dispatchWorkgroups(groups);
|
|
3319
|
+
cut.setPipeline(this.cullPipeline as GPUComputePipeline);
|
|
3320
|
+
cut.setBindGroup(0, this.glassCullGroup as GPUBindGroup);
|
|
3321
|
+
cut.dispatchWorkgroups(groups);
|
|
3322
|
+
cut.setPipeline(this.compactPipeline as GPUComputePipeline);
|
|
3323
|
+
cut.setBindGroup(0, this.glassCompactGroup as GPUBindGroup);
|
|
3324
|
+
cut.dispatchWorkgroups(groups);
|
|
3325
|
+
cut.end();
|
|
3326
|
+
|
|
3327
|
+
const depth = encoder.beginRenderPass({
|
|
3328
|
+
label: 'gpu-driven shadow glass',
|
|
3329
|
+
colorAttachments: [],
|
|
3330
|
+
depthStencilAttachment: {
|
|
3331
|
+
view: this.glassDepthView as GPUTextureView,
|
|
3332
|
+
depthClearValue: SHADOW_DEPTH_CLEAR,
|
|
3333
|
+
depthLoadOp: 'clear',
|
|
3334
|
+
depthStoreOp: 'store',
|
|
3335
|
+
},
|
|
3336
|
+
});
|
|
3337
|
+
depth.setPipeline(this.glassDepthPipeline as GPURenderPipeline);
|
|
3338
|
+
depth.setBindGroup(0, this.glassDepthGroup as GPUBindGroup);
|
|
3339
|
+
depth.drawIndirect(this.glassArgs as GPUBuffer, 0);
|
|
3340
|
+
depth.end();
|
|
3341
|
+
|
|
3342
|
+
const tint = encoder.beginRenderPass({
|
|
3343
|
+
label: 'gpu-driven shadow tint',
|
|
3344
|
+
colorAttachments: [
|
|
3345
|
+
{
|
|
3346
|
+
view: this.glassTintTarget as GPUTextureView,
|
|
3347
|
+
clearValue: { r: 1, g: 1, b: 1, a: 1 },
|
|
3348
|
+
loadOp: 'clear',
|
|
3349
|
+
storeOp: 'store',
|
|
3350
|
+
},
|
|
3351
|
+
],
|
|
3352
|
+
});
|
|
3353
|
+
tint.setPipeline(this.glassTintPipeline as GPURenderPipeline);
|
|
3354
|
+
tint.setBindGroup(0, this.glassTintGroup as GPUBindGroup);
|
|
3355
|
+
tint.drawIndirect(this.glassArgs as GPUBuffer, 0);
|
|
3356
|
+
tint.end();
|
|
3357
|
+
this.glassTintMips?.record(encoder);
|
|
3036
3358
|
}
|
|
3037
3359
|
|
|
3038
3360
|
/** One half of the map: the first clears it, the second draws over it and closes the stage's time. */
|
|
@@ -3061,6 +3383,19 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
3061
3383
|
pass.end();
|
|
3062
3384
|
}
|
|
3063
3385
|
|
|
3386
|
+
/** The linear sampler glass reads the colour's and the tint's chains through, made once. */
|
|
3387
|
+
private glassSamplerFor(device: GPUDevice): GPUSampler {
|
|
3388
|
+
this.glassSampler ??= device.createSampler({
|
|
3389
|
+
label: 'gpu-driven glass',
|
|
3390
|
+
magFilter: 'linear',
|
|
3391
|
+
minFilter: 'linear',
|
|
3392
|
+
mipmapFilter: 'linear',
|
|
3393
|
+
addressModeU: 'clamp-to-edge',
|
|
3394
|
+
addressModeV: 'clamp-to-edge',
|
|
3395
|
+
});
|
|
3396
|
+
return this.glassSampler;
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3064
3399
|
private drawPhase(encoder: GPUCommandEncoder, phase: 0 | 1, clear: boolean): void {
|
|
3065
3400
|
const pass = encoder.beginRenderPass({
|
|
3066
3401
|
label: `gpu-driven phase ${phase + 1}`,
|
|
@@ -3118,6 +3453,8 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
3118
3453
|
if (device.backend !== 'webgpu') return;
|
|
3119
3454
|
this.disposeTargets();
|
|
3120
3455
|
this.shadowTexture?.destroy();
|
|
3456
|
+
this.glassTintTexture?.destroy();
|
|
3457
|
+
this.glassTintNone?.destroy();
|
|
3121
3458
|
this.emptyEnvironment?.destroy();
|
|
3122
3459
|
this.latents?.destroy();
|
|
3123
3460
|
this.queries?.destroy();
|
|
@@ -3156,6 +3493,10 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
3156
3493
|
this.shadowListTwo,
|
|
3157
3494
|
this.shadowSelected,
|
|
3158
3495
|
this.shadowKeep,
|
|
3496
|
+
this.glassList,
|
|
3497
|
+
this.glassArgs,
|
|
3498
|
+
this.glassLodBuffer,
|
|
3499
|
+
this.shadowCullSettingsGlass,
|
|
3159
3500
|
this.shadowPlanes,
|
|
3160
3501
|
this.shadowCullSettings,
|
|
3161
3502
|
this.shadowCullSettingsTwo,
|
|
@@ -3200,3 +3541,6 @@ function multiply(out: Float32Array, a: ArrayLike<number>, b: ArrayLike<number>)
|
|
|
3200
3541
|
}
|
|
3201
3542
|
}
|
|
3202
3543
|
}
|
|
3544
|
+
|
|
3545
|
+
/** Where `hasGlass` reads each material's glass through; only the answer is kept. */
|
|
3546
|
+
const glassProbe: ResolvedGlass = { transmission: 0, frost: 0, tint: [1, 1, 1] };
|
|
@@ -36,20 +36,40 @@ export class GpuInstancedBatch {
|
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/** Last frame's packed slots, for a reconstruction; made on first use by the renderer. */
|
|
40
|
+
previousBuffer: GPUBuffer | null = null;
|
|
41
|
+
/** How many slots the upload before the last one held, and how many the last one holds. */
|
|
42
|
+
previousCount = 0;
|
|
43
|
+
liveCount = 0;
|
|
44
|
+
/** The frame of the last upload. See `changeFrames.ts`. */
|
|
45
|
+
changed = -1;
|
|
46
|
+
|
|
39
47
|
/**
|
|
40
48
|
* Pack and push `data.count` instances, in one write.
|
|
41
49
|
*
|
|
42
50
|
* Only the live prefix, for the reason `uploadScatter` gives: the rest is not drawn and
|
|
43
51
|
* uploading it would be per-frame waste with nothing reading it.
|
|
52
|
+
*
|
|
53
|
+
* **Given `previous`, the placement still in the staging array — the last upload, which is last
|
|
54
|
+
* frame's — is written there first**, so a reconstruction can pair each slot with where it was.
|
|
55
|
+
* `writeBuffer` copies at the call, so packing afterwards cannot reach that copy.
|
|
44
56
|
*/
|
|
45
|
-
upload(queue: GPUQueue, data: MeshInstances): void {
|
|
57
|
+
upload(queue: GPUQueue, data: MeshInstances, previous: GPUBuffer | null = null): void {
|
|
46
58
|
const count = Math.min(data.count, this.capacity);
|
|
59
|
+
if (previous !== null) {
|
|
60
|
+
if (this.liveCount > 0) {
|
|
61
|
+
queue.writeBuffer(previous, 0, this.staging, 0, this.liveCount * INSTANCE_FLOATS);
|
|
62
|
+
}
|
|
63
|
+
this.previousCount = this.liveCount;
|
|
64
|
+
}
|
|
65
|
+
this.liveCount = count;
|
|
47
66
|
if (count === 0) return;
|
|
48
67
|
packInstances(data, this.staging);
|
|
49
68
|
queue.writeBuffer(this.buffer, 0, this.staging, 0, count * INSTANCE_FLOATS);
|
|
50
69
|
}
|
|
51
70
|
|
|
52
71
|
dispose(): void {
|
|
72
|
+
this.previousBuffer?.destroy();
|
|
53
73
|
this.buffer.destroy();
|
|
54
74
|
}
|
|
55
75
|
}
|