@driftengine/core 4.11.1 → 4.13.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 +102 -0
- package/README.md +18 -9
- package/dist/geometry/meshBuilder.d.ts +10 -0
- package/dist/geometry/meshBuilder.js +11 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -2
- package/dist/math/color.d.ts +25 -0
- package/dist/math/color.js +37 -0
- package/dist/render/backend/webgl2/renderer.d.ts +33 -5
- package/dist/render/backend/webgl2/renderer.js +123 -49
- package/dist/render/backend/webgl2/skinScatter.d.ts +3 -1
- package/dist/render/backend/webgl2/skinScatter.js +5 -1
- package/dist/render/backend/webgpu/boltPass.d.ts +1 -1
- package/dist/render/backend/webgpu/causticsPass.d.ts +1 -1
- package/dist/render/backend/webgpu/filmPass.d.ts +1 -1
- package/dist/render/backend/webgpu/flockPass.d.ts +1 -1
- package/dist/render/backend/webgpu/giFieldPass.d.ts +3 -1
- package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +10 -1
- package/dist/render/backend/webgpu/gpuDrivenPass.js +28 -11
- package/dist/render/backend/webgpu/panelPass.d.ts +1 -1
- package/dist/render/backend/webgpu/postPass.d.ts +2 -2
- package/dist/render/backend/webgpu/renderer.d.ts +21 -8
- package/dist/render/backend/webgpu/renderer.js +103 -38
- package/dist/render/backend/webgpu/scatterPass.d.ts +1 -1
- package/dist/render/backend/webgpu/skinScatterPass.d.ts +5 -1
- package/dist/render/backend/webgpu/skinScatterPass.js +9 -3
- package/dist/render/backend/webgpu/skyPass.d.ts +11 -1
- package/dist/render/backend/webgpu/waterPass.d.ts +1 -1
- package/dist/render/backend/webgpu/windStreakPass.d.ts +1 -1
- package/dist/render/causticsRenderer.d.ts +3 -1
- package/dist/render/causticsRenderer.js +5 -1
- package/dist/render/decalPass.d.ts +3 -1
- package/dist/render/decalPass.js +4 -1
- package/dist/render/flockRenderer.d.ts +1 -1
- package/dist/render/flockRenderer.js +4 -1
- package/dist/render/globalMediumPass.d.ts +3 -1
- package/dist/render/globalMediumPass.js +5 -1
- package/dist/render/gradeColor.d.ts +21 -0
- package/dist/render/gradeColor.js +64 -0
- package/dist/render/lightMatrix.d.ts +13 -0
- package/dist/render/lightMatrix.js +17 -0
- package/dist/render/passGrade.d.ts +13 -0
- package/dist/render/passGrade.js +47 -0
- package/dist/render/plumeRenderer.d.ts +1 -1
- package/dist/render/plumeRenderer.js +4 -1
- package/dist/render/renderQuality.d.ts +57 -18
- package/dist/render/renderQuality.js +3 -3
- package/dist/render/sceneTarget.d.ts +2 -0
- package/dist/render/sceneTarget.js +1 -0
- package/dist/render/sdfTextRenderer.d.ts +1 -1
- package/dist/render/sdfTextRenderer.js +1 -1
- package/dist/render/shaders/arcane.d.ts +1 -1
- package/dist/render/shaders/arcane.js +5 -1
- package/dist/render/shaders/bolt.d.ts +1 -1
- package/dist/render/shaders/bolt.js +4 -1
- package/dist/render/shaders/caustics.d.ts +1 -1
- package/dist/render/shaders/caustics.js +4 -1
- package/dist/render/shaders/decalProject.js +12 -2
- package/dist/render/shaders/film.d.ts +1 -1
- package/dist/render/shaders/film.js +22 -9
- package/dist/render/shaders/fire.d.ts +1 -1
- package/dist/render/shaders/fire.js +4 -1
- package/dist/render/shaders/flat/areaLight.d.ts +1 -1
- package/dist/render/shaders/flat/areaLight.js +1 -1
- package/dist/render/shaders/flat/glassTint.d.ts +1 -1
- package/dist/render/shaders/flat/glassTint.js +1 -0
- package/dist/render/shaders/flat/index.d.ts +5 -0
- package/dist/render/shaders/flat/index.js +1 -1
- package/dist/render/shaders/flat/layerLooks.d.ts +16 -0
- package/dist/render/shaders/flat/layerLooks.js +108 -0
- package/dist/render/shaders/flat/layered.d.ts +6 -4
- package/dist/render/shaders/flat/layered.js +77 -13
- package/dist/render/shaders/flat/main.d.ts +1 -1
- package/dist/render/shaders/flat/main.js +7 -2
- package/dist/render/shaders/flat/models.js +1 -1
- package/dist/render/shaders/flat/preamble.js +6 -0
- package/dist/render/shaders/flock.d.ts +1 -1
- package/dist/render/shaders/flock.js +4 -1
- package/dist/render/shaders/generated/arcane.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/arcane.wgsl.js +11 -1
- package/dist/render/shaders/generated/bolt.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/bolt.wgsl.js +12 -2
- package/dist/render/shaders/generated/caustics.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/caustics.wgsl.js +12 -2
- package/dist/render/shaders/generated/decalProject.wgsl.d.ts +6 -1
- package/dist/render/shaders/generated/decalProject.wgsl.js +6 -1
- package/dist/render/shaders/generated/film.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/film.wgsl.js +12 -2
- package/dist/render/shaders/generated/fire.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/fire.wgsl.js +11 -1
- package/dist/render/shaders/generated/flat.wgsl.d.ts +144 -16
- package/dist/render/shaders/generated/flat.wgsl.js +183 -55
- package/dist/render/shaders/generated/flock.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/flock.wgsl.js +12 -2
- package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/globalMedium.wgsl.js +12 -2
- package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +36 -16
- package/dist/render/shaders/generated/lightVolume.wgsl.js +39 -19
- package/dist/render/shaders/generated/panel.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/panel.wgsl.js +12 -2
- package/dist/render/shaders/generated/rush.wgsl.d.ts +31 -26
- package/dist/render/shaders/generated/rush.wgsl.js +31 -26
- package/dist/render/shaders/generated/scatter.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/scatter.wgsl.js +12 -2
- package/dist/render/shaders/generated/skinBlur.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/skinBlur.wgsl.js +11 -1
- package/dist/render/shaders/generated/sky.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/sky.wgsl.js +12 -2
- package/dist/render/shaders/generated/smoke.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/smoke.wgsl.js +11 -1
- package/dist/render/shaders/generated/text.wgsl.d.ts +11 -1
- package/dist/render/shaders/generated/text.wgsl.js +11 -1
- package/dist/render/shaders/generated/water.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/water.wgsl.js +12 -2
- package/dist/render/shaders/generated/windStreaks.wgsl.d.ts +12 -2
- package/dist/render/shaders/generated/windStreaks.wgsl.js +12 -2
- package/dist/render/shaders/globalMedium.js +14 -1
- package/dist/render/shaders/gpudriven/present.wgsl.d.ts +15 -6
- package/dist/render/shaders/gpudriven/present.wgsl.js +71 -8
- package/dist/render/shaders/lightVolume.js +4 -1
- package/dist/render/shaders/line.d.ts +1 -1
- package/dist/render/shaders/outputTransform.d.ts +8 -2
- package/dist/render/shaders/outputTransform.js +18 -11
- package/dist/render/shaders/panel.d.ts +1 -1
- package/dist/render/shaders/panel.js +5 -1
- package/dist/render/shaders/particle.d.ts +3 -3
- package/dist/render/shaders/rush.js +8 -0
- package/dist/render/shaders/scatter.d.ts +1 -1
- package/dist/render/shaders/scatter.js +4 -1
- package/dist/render/shaders/sdfText.d.ts +1 -1
- package/dist/render/shaders/skinBlur.js +5 -1
- package/dist/render/shaders/sky.d.ts +1 -1
- package/dist/render/shaders/sky.js +5 -1
- package/dist/render/shaders/smoke.d.ts +1 -1
- package/dist/render/shaders/smoke.js +4 -1
- package/dist/render/shaders/text.d.ts +1 -1
- package/dist/render/shaders/text.js +4 -1
- package/dist/render/shaders/water.d.ts +1 -1
- package/dist/render/shaders/water.js +12 -2
- package/dist/render/shaders/windStreaks.d.ts +1 -1
- package/dist/render/shaders/windStreaks.js +4 -1
- package/dist/render/surfaceLayerLooks.d.ts +92 -0
- package/dist/render/surfaceLayerLooks.js +102 -0
- package/dist/render/surfaceLayers.d.ts +47 -6
- package/dist/render/surfaceLayers.js +5 -1
- package/dist/render/textRenderer.d.ts +3 -1
- package/dist/render/textRenderer.js +7 -1
- package/dist/render/vertexDefaults.d.ts +1 -1
- package/dist/render/vertexDefaults.js +1 -1
- package/dist/render/waterRenderer.d.ts +1 -1
- package/dist/render/waterRenderer.js +4 -1
- package/dist/render/windStreakRenderer.d.ts +3 -1
- package/dist/render/windStreakRenderer.js +5 -1
- package/package.json +6 -6
- package/scripts/browser.d.mts +5 -0
- package/scripts/browser.mjs +68 -14
- package/scripts/look.d.mts +81 -0
- package/scripts/look.mjs +380 -0
- package/src/geometry/meshBuilder.ts +21 -2
- package/src/index.ts +13 -2
- package/src/math/color.ts +39 -0
- package/src/render/backend/webgl2/renderer.ts +174 -46
- package/src/render/backend/webgl2/skinScatter.ts +5 -0
- package/src/render/backend/webgpu/giFieldPass.ts +3 -1
- package/src/render/backend/webgpu/gpuDrivenPass.ts +29 -13
- package/src/render/backend/webgpu/renderer.ts +112 -37
- package/src/render/backend/webgpu/skinScatterPass.ts +17 -1
- package/src/render/causticsRenderer.ts +5 -0
- package/src/render/decalPass.ts +3 -0
- package/src/render/flockRenderer.ts +5 -0
- package/src/render/globalMediumPass.ts +10 -1
- package/src/render/gradeColor.ts +90 -0
- package/src/render/lightMatrix.ts +32 -0
- package/src/render/passGrade.ts +58 -0
- package/src/render/plumeRenderer.ts +5 -0
- package/src/render/renderQuality.ts +60 -21
- package/src/render/sceneTarget.ts +3 -0
- package/src/render/sdfTextRenderer.ts +1 -1
- package/src/render/shaders/arcane.ts +5 -1
- package/src/render/shaders/bolt.ts +4 -1
- package/src/render/shaders/caustics.ts +4 -1
- package/src/render/shaders/decalProject.ts +12 -2
- package/src/render/shaders/film.ts +22 -9
- package/src/render/shaders/fire.ts +4 -1
- package/src/render/shaders/flat/areaLight.ts +1 -1
- package/src/render/shaders/flat/glassTint.ts +3 -1
- package/src/render/shaders/flat/index.ts +6 -1
- package/src/render/shaders/flat/layerLooks.ts +108 -0
- package/src/render/shaders/flat/layered.ts +78 -13
- package/src/render/shaders/flat/main.ts +7 -2
- package/src/render/shaders/flat/models.ts +1 -1
- package/src/render/shaders/flat/preamble.ts +6 -0
- package/src/render/shaders/flock.ts +4 -1
- package/src/render/shaders/generated/arcane.wgsl.ts +11 -1
- package/src/render/shaders/generated/bolt.wgsl.ts +12 -2
- package/src/render/shaders/generated/caustics.wgsl.ts +12 -2
- package/src/render/shaders/generated/decalProject.wgsl.ts +6 -1
- package/src/render/shaders/generated/film.wgsl.ts +12 -2
- package/src/render/shaders/generated/fire.wgsl.ts +11 -1
- package/src/render/shaders/generated/flat.wgsl.ts +183 -55
- package/src/render/shaders/generated/flock.wgsl.ts +12 -2
- package/src/render/shaders/generated/globalMedium.wgsl.ts +12 -2
- package/src/render/shaders/generated/lightVolume.wgsl.ts +39 -19
- package/src/render/shaders/generated/panel.wgsl.ts +12 -2
- package/src/render/shaders/generated/rush.wgsl.ts +31 -26
- package/src/render/shaders/generated/scatter.wgsl.ts +12 -2
- package/src/render/shaders/generated/skinBlur.wgsl.ts +11 -1
- package/src/render/shaders/generated/sky.wgsl.ts +12 -2
- package/src/render/shaders/generated/smoke.wgsl.ts +11 -1
- package/src/render/shaders/generated/text.wgsl.ts +11 -1
- package/src/render/shaders/generated/water.wgsl.ts +12 -2
- package/src/render/shaders/generated/windStreaks.wgsl.ts +12 -2
- package/src/render/shaders/globalMedium.ts +14 -1
- package/src/render/shaders/gpudriven/present.wgsl.ts +72 -8
- package/src/render/shaders/lightVolume.ts +4 -1
- package/src/render/shaders/outputTransform.ts +19 -11
- package/src/render/shaders/panel.ts +5 -1
- package/src/render/shaders/rush.ts +8 -0
- package/src/render/shaders/scatter.ts +4 -1
- package/src/render/shaders/skinBlur.ts +5 -1
- package/src/render/shaders/sky.ts +5 -1
- package/src/render/shaders/smoke.ts +4 -1
- package/src/render/shaders/text.ts +4 -1
- package/src/render/shaders/water.ts +12 -2
- package/src/render/shaders/windStreaks.ts +4 -1
- package/src/render/surfaceLayerLooks.ts +186 -0
- package/src/render/surfaceLayers.ts +52 -7
- package/src/render/textRenderer.ts +6 -0
- package/src/render/vertexDefaults.ts +1 -1
- package/src/render/waterRenderer.ts +5 -0
- package/src/render/windStreakRenderer.ts +5 -0
|
@@ -646,7 +646,16 @@ export class GpuDrivenPass {
|
|
|
646
646
|
shadowed: true,
|
|
647
647
|
blended: false,
|
|
648
648
|
};
|
|
649
|
-
|
|
649
|
+
/**
|
|
650
|
+
* The frame's grade for the blit, `PassContext.outputTransform` and its exposure, and the code it
|
|
651
|
+
* was last written with, so a frame writes it only when it changes. See `present.wgsl.ts`.
|
|
652
|
+
*/
|
|
653
|
+
gradeBuffer = null;
|
|
654
|
+
gradeStaging = new ArrayBuffer(16);
|
|
655
|
+
gradeInts = new Int32Array(this.gradeStaging);
|
|
656
|
+
gradeFloats = new Float32Array(this.gradeStaging);
|
|
657
|
+
gradeWrittenCode = Number.NaN;
|
|
658
|
+
gradeWrittenExposure = Number.NaN;
|
|
650
659
|
constructor(scene, materials, shadow = {}) {
|
|
651
660
|
if (materials.length > MATERIAL_SLOTS) {
|
|
652
661
|
throw new Error(`[driftengine] the gpu-driven pass holds ${MATERIAL_SLOTS} materials and was given ` +
|
|
@@ -1937,10 +1946,17 @@ export class GpuDrivenPass {
|
|
|
1937
1946
|
{ binding: 21, resource: this.glassSamplerFor(device) },
|
|
1938
1947
|
],
|
|
1939
1948
|
});
|
|
1949
|
+
this.gradeBuffer ??= device.createBuffer({
|
|
1950
|
+
label: 'gpu-driven blit grade',
|
|
1951
|
+
size: this.gradeStaging.byteLength,
|
|
1952
|
+
usage: UNIFORM | COPY_DST,
|
|
1953
|
+
});
|
|
1954
|
+
this.gradeWrittenCode = Number.NaN;
|
|
1940
1955
|
this.blitGroup = device.createBindGroup({
|
|
1941
1956
|
layout: this.blitPipeline.getBindGroupLayout(0),
|
|
1942
1957
|
entries: [
|
|
1943
1958
|
{ binding: 0, resource: this.colourView },
|
|
1959
|
+
{ binding: 2, resource: { buffer: this.gradeBuffer } },
|
|
1944
1960
|
/* The depth the raster wrote, sampled so the blit can hand it to the frame. */
|
|
1945
1961
|
...(this.presentDepth
|
|
1946
1962
|
? [
|
|
@@ -2867,16 +2883,15 @@ export class GpuDrivenPass {
|
|
|
2867
2883
|
return;
|
|
2868
2884
|
if (this.blitPipeline === null || this.blitGroup === null)
|
|
2869
2885
|
return;
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
'to grade it, so the picture will be flat. Use a quality profile with a scene target.');
|
|
2886
|
+
/* The frame's grade, written when it changes: 0 where the resolve grades. See present.wgsl.ts. */
|
|
2887
|
+
const changed = ctx.outputTransform !== this.gradeWrittenCode ||
|
|
2888
|
+
ctx.outputExposure !== this.gradeWrittenExposure;
|
|
2889
|
+
if (changed && this.device !== null && this.gradeBuffer !== null) {
|
|
2890
|
+
this.gradeWrittenCode = ctx.outputTransform;
|
|
2891
|
+
this.gradeWrittenExposure = ctx.outputExposure;
|
|
2892
|
+
this.gradeInts[0] = ctx.outputTransform;
|
|
2893
|
+
this.gradeFloats[1] = ctx.outputExposure;
|
|
2894
|
+
this.device.queue.writeBuffer(this.gradeBuffer, 0, this.gradeStaging);
|
|
2880
2895
|
}
|
|
2881
2896
|
ctx.pass.setPipeline(this.blitPipeline);
|
|
2882
2897
|
ctx.pass.setBindGroup(0, this.blitGroup);
|
|
@@ -2888,6 +2903,8 @@ export class GpuDrivenPass {
|
|
|
2888
2903
|
if (device.backend !== 'webgpu')
|
|
2889
2904
|
return;
|
|
2890
2905
|
this.disposeTargets();
|
|
2906
|
+
this.gradeBuffer?.destroy();
|
|
2907
|
+
this.gradeBuffer = null;
|
|
2891
2908
|
this.shadowTexture?.destroy();
|
|
2892
2909
|
this.glassTintTexture?.destroy();
|
|
2893
2910
|
this.glassTintNone?.destroy();
|
|
@@ -13,7 +13,7 @@ import type { PipelineCache } from './pipelineCache.ts';
|
|
|
13
13
|
export declare const PANEL_VERT_FIELDS: UniformFields;
|
|
14
14
|
export declare const PANEL_VERT_SIZE: 96;
|
|
15
15
|
export declare const PANEL_FRAG_FIELDS: UniformFields;
|
|
16
|
-
export declare const PANEL_FRAG_SIZE:
|
|
16
|
+
export declare const PANEL_FRAG_SIZE: 32;
|
|
17
17
|
export declare const PANEL_VERTEX_COUNT: number;
|
|
18
18
|
export declare function createPanelCorners(device: GPUDevice): GPUBuffer;
|
|
19
19
|
export declare function createPanelBindGroupLayout(device: GPUDevice): GPUBindGroupLayout;
|
|
@@ -26,7 +26,7 @@ import type { PipelineCache } from './pipelineCache.ts';
|
|
|
26
26
|
* float target the generated shaders can sample as an ordinary texture.
|
|
27
27
|
*/
|
|
28
28
|
export declare const RUSH_FRAG_FIELDS: UniformFields;
|
|
29
|
-
export declare const RUSH_FRAG_SIZE:
|
|
29
|
+
export declare const RUSH_FRAG_SIZE: 288;
|
|
30
30
|
declare const RUSH_UNIFORMS: 1;
|
|
31
31
|
declare const RUSH_TEXTURES: {
|
|
32
32
|
readonly uScene: {
|
|
@@ -77,7 +77,7 @@ export declare const AO_BLUR_SIZE: 48;
|
|
|
77
77
|
export declare const MEDIUM_FRAG_FIELDS: UniformFields;
|
|
78
78
|
export declare const MEDIUM_FRAG_SIZE: 304;
|
|
79
79
|
export declare const MEDIUM_UPSAMPLE_FIELDS: UniformFields;
|
|
80
|
-
export declare const MEDIUM_UPSAMPLE_SIZE:
|
|
80
|
+
export declare const MEDIUM_UPSAMPLE_SIZE: 48;
|
|
81
81
|
export declare const BLOOM_PREFILTER_FIELDS: UniformFields;
|
|
82
82
|
/**
|
|
83
83
|
* The other two stages' blocks, read by name like every other block here.
|
|
@@ -99,7 +99,7 @@ export declare class WebGPURenderer implements RendererApi {
|
|
|
99
99
|
* **Resolved by the caller and held, rather than defaulted per use.** Every shadow term
|
|
100
100
|
* below reads it, and the constants they replaced were `DEFAULT_RENDER_QUALITY` copies —
|
|
101
101
|
* which measured wrong the moment a scene overrode one. `demo/dayClock` resolves
|
|
102
|
-
* `directionalShadowMaxSlope` to 9 where the default
|
|
102
|
+
* `directionalShadowMaxSlope` to 9 where the default was 3 (60 since 4.13.0).
|
|
103
103
|
*/
|
|
104
104
|
readonly quality: Readonly<RenderQuality>;
|
|
105
105
|
/** Whether `endFrame` put an image on the canvas. Read by the recorder and the harness. */
|
|
@@ -716,6 +716,7 @@ export declare class WebGPURenderer implements RendererApi {
|
|
|
716
716
|
private readonly mediumUpsampleUniforms;
|
|
717
717
|
private readonly mediumUpsampleStaging;
|
|
718
718
|
private readonly mediumUpsampleFloats;
|
|
719
|
+
private readonly mediumUpsampleInts;
|
|
719
720
|
private mediumUpsampleGroup;
|
|
720
721
|
/** The inverse projection the composite linearises a depth with, built once per frame. */
|
|
721
722
|
private readonly mediumInvProjection;
|
|
@@ -944,6 +945,12 @@ export declare class WebGPURenderer implements RendererApi {
|
|
|
944
945
|
*/
|
|
945
946
|
private readonly skyUniforms;
|
|
946
947
|
private readonly skyFloats;
|
|
948
|
+
/** The same block's ints: the grade the sky draws with. */
|
|
949
|
+
private readonly skyInts;
|
|
950
|
+
/** `clearOf`'s scratch: a clear colour as the open target takes it. */
|
|
951
|
+
private readonly gradedClear;
|
|
952
|
+
/** An inset's clear as its quad's uniform, rewritten in place: the colour and an alpha of 1. */
|
|
953
|
+
private readonly insetClear;
|
|
947
954
|
private readonly skyBindGroup;
|
|
948
955
|
/** The camera's inverse with the clip correction undone, rebuilt once a frame. */
|
|
949
956
|
private readonly skyInvViewProj;
|
|
@@ -1026,6 +1033,8 @@ export declare class WebGPURenderer implements RendererApi {
|
|
|
1026
1033
|
private decalUniforms;
|
|
1027
1034
|
private readonly decalStaging;
|
|
1028
1035
|
private readonly decalFloats;
|
|
1036
|
+
/** The same slots' ints: the grade the frame under the marks was drawn with. */
|
|
1037
|
+
private readonly decalInts;
|
|
1029
1038
|
private decalBindGroup;
|
|
1030
1039
|
/** Said once where a mark cannot be drawn at all, rather than dropped in silence. */
|
|
1031
1040
|
private decalsRefused;
|
|
@@ -1189,6 +1198,8 @@ export declare class WebGPURenderer implements RendererApi {
|
|
|
1189
1198
|
private readonly projection;
|
|
1190
1199
|
/** `uLayers`, the material's layers packed by `packSurfaceLayers`. */
|
|
1191
1200
|
private readonly layerFloats;
|
|
1201
|
+
/** `uLayerLooks`, the material's layer picks and looks packed by `packLayerLooks`. */
|
|
1202
|
+
private readonly lookFloats;
|
|
1192
1203
|
/**
|
|
1193
1204
|
* `uGlassTint` as the material leaves it, its light from behind and that light's colour, which a
|
|
1194
1205
|
* pane overwrites for its own draw and `releaseSeeThrough` puts back. See `transmission.ts`.
|
|
@@ -1544,14 +1555,16 @@ export declare class WebGPURenderer implements RendererApi {
|
|
|
1544
1555
|
* array allocated with the batch, so the frame loop still allocates nothing.
|
|
1545
1556
|
*/
|
|
1546
1557
|
/**
|
|
1547
|
-
* The
|
|
1548
|
-
*
|
|
1549
|
-
* The
|
|
1550
|
-
* one verb with two implementations, and a frame that grades on one backend and not the other
|
|
1551
|
-
* is the silent kind of disagreement. See that method for what the gate is protecting.
|
|
1558
|
+
* The grade a pass applies to what it draws into the target open now, and the exposure it
|
|
1559
|
+
* applies it at: the WebGPU half of `Renderer.passGrade`, and it has to agree with it draw for
|
|
1560
|
+
* draw. The decision is `passGrade.ts`'s, so both halves only gather the state it is taken from.
|
|
1552
1561
|
*/
|
|
1553
|
-
private
|
|
1554
|
-
private
|
|
1562
|
+
private passGrade;
|
|
1563
|
+
private passGradeExposure;
|
|
1564
|
+
/** Whether the frame's resolve applies the transform, so the passes before it draw linear. */
|
|
1565
|
+
private resolveGrades;
|
|
1566
|
+
/** A clear colour as the open target takes it, graded as a pass would. See `gradeColor.ts`. */
|
|
1567
|
+
private clearOf;
|
|
1555
1568
|
drawParticles(batch: GpuParticles, data: ParticleInstances, camera: Camera, env: Environment, timeSeconds: number): void;
|
|
1556
1569
|
/**
|
|
1557
1570
|
* Draw particles a caller's own compute wrote, where they lie. See `DeviceParticles`.
|
|
@@ -67,6 +67,7 @@ import { resolveTransmission } from '../../transmission.js';
|
|
|
67
67
|
import { resolveOcclusionFade } from '../../occlusionFade.js';
|
|
68
68
|
import { orthographicDepthSpan } from '../../lightMatrix.js';
|
|
69
69
|
import { LAYER_FLOATS, layerMaskMap, layeredProjection, layersFitBeside, packSurfaceLayers, } from '../../surfaceLayers.js';
|
|
70
|
+
import { LOOK_FLOATS, asksLayerLooks, packLayerLooks } from '../../surfaceLayerLooks.js';
|
|
70
71
|
import { frameReflectionsRefused, resolveFrameReflections, } from '../../frameReflections.js';
|
|
71
72
|
import { REFLECTION_SURFACE_FORMAT, ReflectionSurfacePass } from './reflectionSurfacePass.js';
|
|
72
73
|
import { validateClothBinding } from '../../clothBindingData.js';
|
|
@@ -74,7 +75,9 @@ import { createSdfTextBindGroup, createSdfTextBindGroupLayout, GpuSdfText, sdfTe
|
|
|
74
75
|
import { createFilmBindGroup, createFilmBindGroupLayout, filmPipeline, FILM_FRAG_FIELDS, FILM_FRAG_SIZE, FILM_VERT_FIELDS, FILM_VERT_SIZE, } from './filmPass.js';
|
|
75
76
|
import { reflectionTargetSize } from '../../planarReflectionDraw.js';
|
|
76
77
|
import { drawingBufferSize } from '../../drawingBuffer.js';
|
|
77
|
-
import { MOTION_BLUR_MAX_UV, OBJECT_BLUR_UNKEPT, OUTPUT_TRANSFORM_CODE, RUSH_REACH_UV, clampMotionShare,
|
|
78
|
+
import { MOTION_BLUR_MAX_UV, OBJECT_BLUR_UNKEPT, OUTPUT_TRANSFORM_CODE, RUSH_REACH_UV, clampMotionShare, } from '../../vertexDefaults.js';
|
|
79
|
+
import { gradeColorInto } from '../../gradeColor.js';
|
|
80
|
+
import { interfaceGrade, passGradeCode, passGradeExposure } from '../../passGrade.js';
|
|
78
81
|
import { FRINGE_FLOATS, resolveFringe } from '../../shaders/fringe.js';
|
|
79
82
|
import { displayHeadroom } from '../../displayRange.js';
|
|
80
83
|
import { DEFAULT_FILMIC_CURVE, FILMIC_CLAMPED, FILMIC_CONSTANTS, FILMIC_WITHOUT_COMPOSITE, resolveFilmicCurve, } from '../../filmicCurve.js';
|
|
@@ -833,7 +836,7 @@ export class WebGPURenderer {
|
|
|
833
836
|
* **Resolved by the caller and held, rather than defaulted per use.** Every shadow term
|
|
834
837
|
* below reads it, and the constants they replaced were `DEFAULT_RENDER_QUALITY` copies —
|
|
835
838
|
* which measured wrong the moment a scene overrode one. `demo/dayClock` resolves
|
|
836
|
-
* `directionalShadowMaxSlope` to 9 where the default
|
|
839
|
+
* `directionalShadowMaxSlope` to 9 where the default was 3 (60 since 4.13.0).
|
|
837
840
|
*/
|
|
838
841
|
quality;
|
|
839
842
|
/** Whether `endFrame` put an image on the canvas. Read by the recorder and the harness. */
|
|
@@ -1518,6 +1521,7 @@ export class WebGPURenderer {
|
|
|
1518
1521
|
mediumUpsampleUniforms;
|
|
1519
1522
|
mediumUpsampleStaging = new ArrayBuffer(MEDIUM_UPSAMPLE_SIZE);
|
|
1520
1523
|
mediumUpsampleFloats = new Float32Array(this.mediumUpsampleStaging);
|
|
1524
|
+
mediumUpsampleInts = new Int32Array(this.mediumUpsampleStaging);
|
|
1521
1525
|
mediumUpsampleGroup = null;
|
|
1522
1526
|
/** The inverse projection the composite linearises a depth with, built once per frame. */
|
|
1523
1527
|
mediumInvProjection = mat4.create();
|
|
@@ -1763,6 +1767,12 @@ export class WebGPURenderer {
|
|
|
1763
1767
|
*/
|
|
1764
1768
|
skyUniforms;
|
|
1765
1769
|
skyFloats = new Float32Array(SKY_UNIFORM_SIZE / 4);
|
|
1770
|
+
/** The same block's ints: the grade the sky draws with. */
|
|
1771
|
+
skyInts = new Int32Array(this.skyFloats.buffer);
|
|
1772
|
+
/** `clearOf`'s scratch: a clear colour as the open target takes it. */
|
|
1773
|
+
gradedClear = [0, 0, 0];
|
|
1774
|
+
/** An inset's clear as its quad's uniform, rewritten in place: the colour and an alpha of 1. */
|
|
1775
|
+
insetClear = new Float32Array([0, 0, 0, 1]);
|
|
1766
1776
|
skyBindGroup;
|
|
1767
1777
|
/** The camera's inverse with the clip correction undone, rebuilt once a frame. */
|
|
1768
1778
|
skyInvViewProj = new Float32Array(16);
|
|
@@ -1846,6 +1856,8 @@ export class WebGPURenderer {
|
|
|
1846
1856
|
decalUniforms;
|
|
1847
1857
|
decalStaging = new ArrayBuffer(DECAL_SLOT * MAX_DRAWN_DECALS);
|
|
1848
1858
|
decalFloats = new Float32Array(this.decalStaging);
|
|
1859
|
+
/** The same slots' ints: the grade the frame under the marks was drawn with. */
|
|
1860
|
+
decalInts = new Int32Array(this.decalStaging);
|
|
1849
1861
|
decalBindGroup = null;
|
|
1850
1862
|
/** Said once where a mark cannot be drawn at all, rather than dropped in silence. */
|
|
1851
1863
|
decalsRefused = false;
|
|
@@ -2016,9 +2028,10 @@ export class WebGPURenderer {
|
|
|
2016
2028
|
* still owed.
|
|
2017
2029
|
*/
|
|
2018
2030
|
this.pass = null;
|
|
2019
|
-
|
|
2020
|
-
this.mirrorClearColor[
|
|
2021
|
-
this.mirrorClearColor[
|
|
2031
|
+
const mirrorClear = this.clearOf(clearColor);
|
|
2032
|
+
this.mirrorClearColor[0] = mirrorClear[0];
|
|
2033
|
+
this.mirrorClearColor[1] = mirrorClear[1];
|
|
2034
|
+
this.mirrorClearColor[2] = mirrorClear[2];
|
|
2022
2035
|
this.pendingClearMask |= MIRROR_TARGET;
|
|
2023
2036
|
this.reflectionPassActive = true;
|
|
2024
2037
|
/* Closed in `endPlanarReflection`, matching `renderer.ts:2054`. */
|
|
@@ -2170,6 +2183,8 @@ export class WebGPURenderer {
|
|
|
2170
2183
|
i[atF('uClipEnabled')] = this.reflectionPassActive ? 1 : 0;
|
|
2171
2184
|
f.set(this.reflection?.clipPlane ?? NO_CLIP_PLANE, atF('uClipPlane'));
|
|
2172
2185
|
f[atF('uSheen')] = sheen;
|
|
2186
|
+
i[atF('uOutputTransform')] = this.passGrade();
|
|
2187
|
+
f[atF('uOutputExposure')] = this.passGradeExposure();
|
|
2173
2188
|
f[atF('uFilmRoughness')] = Math.min(1, Math.max(0, options.roughness ?? 0));
|
|
2174
2189
|
f[atF('uFilmRoughnessCycles')] = Math.max(0.01, options.roughnessCyclesPerMetre ?? 60);
|
|
2175
2190
|
const medium = resolveAtmosphere(env, this.atmosphereHeight(camera), this.quality.underwaterAtmosphere, this.medium);
|
|
@@ -2256,6 +2271,8 @@ export class WebGPURenderer {
|
|
|
2256
2271
|
projection = new Float32Array(PROJECTION_FLOATS);
|
|
2257
2272
|
/** `uLayers`, the material's layers packed by `packSurfaceLayers`. */
|
|
2258
2273
|
layerFloats = new Float32Array(LAYER_FLOATS);
|
|
2274
|
+
/** `uLayerLooks`, the material's layer picks and looks packed by `packLayerLooks`. */
|
|
2275
|
+
lookFloats = new Float32Array(LOOK_FLOATS);
|
|
2259
2276
|
/**
|
|
2260
2277
|
* `uGlassTint` as the material leaves it, its light from behind and that light's colour, which a
|
|
2261
2278
|
* pane overwrites for its own draw and `releaseSeeThrough` puts back. See `transmission.ts`.
|
|
@@ -2745,6 +2762,11 @@ export class WebGPURenderer {
|
|
|
2745
2762
|
f.set(this.layerFloats, this.materialField('uLayers'));
|
|
2746
2763
|
if (layers !== null)
|
|
2747
2764
|
this.enableLit('LAYERED');
|
|
2765
|
+
/* And which layer of shared arrays each reads, with its look: layerLooks.ts. */
|
|
2766
|
+
packLayerLooks(layers, this.lookFloats);
|
|
2767
|
+
f.set(this.lookFloats, this.materialField('uLayerLooks'));
|
|
2768
|
+
if (asksLayerLooks(layers))
|
|
2769
|
+
this.enableLit('LAYER_LOOKS');
|
|
2748
2770
|
f.set(this.modelParams, this.materialField('uModelParams'));
|
|
2749
2771
|
});
|
|
2750
2772
|
/*
|
|
@@ -3012,6 +3034,9 @@ export class WebGPURenderer {
|
|
|
3012
3034
|
const fragAt = (name) => PANEL_FRAG_FIELDS[name]?.offset ?? 0;
|
|
3013
3035
|
this.panelFrags.writeFloats(fragmentSlot, fragAt('uColor'), color);
|
|
3014
3036
|
this.panelFrags.writeFloat(fragmentSlot, fragAt('uAlpha'), alpha);
|
|
3037
|
+
/* An interface: the screen encode, never the curve. See `interfaceGrade`. */
|
|
3038
|
+
this.panelFrags.writeInt(fragmentSlot, fragAt('uOutputTransform'), interfaceGrade(this.passGrade()));
|
|
3039
|
+
this.panelFrags.writeFloat(fragmentSlot, fragAt('uOutputExposure'), 1);
|
|
3015
3040
|
const panelPipe = panelPipeline(this.targetPipelines(), this.surface.device, this.panelLayout);
|
|
3016
3041
|
/* `allocate` already returns a byte offset, not an index. Multiplying by the stride
|
|
3017
3042
|
again put the second panel 64 KB into a 16 KB ring — the device said so, in as many
|
|
@@ -3119,8 +3144,8 @@ export class WebGPURenderer {
|
|
|
3119
3144
|
font.atlasWidth,
|
|
3120
3145
|
font.atlasHeight,
|
|
3121
3146
|
]);
|
|
3122
|
-
this.sdfTextFrags.writeInt(fragmentSlot, fragAt('uOutputTransform'), this.
|
|
3123
|
-
this.sdfTextFrags.writeFloat(fragmentSlot, fragAt('uOutputExposure'), this.
|
|
3147
|
+
this.sdfTextFrags.writeInt(fragmentSlot, fragAt('uOutputTransform'), this.passGrade());
|
|
3148
|
+
this.sdfTextFrags.writeFloat(fragmentSlot, fragAt('uOutputExposure'), this.passGradeExposure());
|
|
3124
3149
|
const sdfPipe = sdfTextPipeline(this.blendedPipelines(), this.surface.device, this.sdfTextLayout);
|
|
3125
3150
|
const sdfGroup = this.sdfTextBindGroupFor(atlas);
|
|
3126
3151
|
const sdfCommand = this.recordBlended(0);
|
|
@@ -3222,6 +3247,9 @@ export class WebGPURenderer {
|
|
|
3222
3247
|
this.textFrags.writeFloats(fragmentSlot, fragAt('uColor'), style.color);
|
|
3223
3248
|
this.textFrags.writeFloat(fragmentSlot, fragAt('uGlow'), style.glow);
|
|
3224
3249
|
this.textFrags.writeFloat(fragmentSlot, fragAt('uAlpha'), style.alpha);
|
|
3250
|
+
/* An interface: the screen encode, never the curve. See `interfaceGrade`. */
|
|
3251
|
+
this.textFrags.writeInt(fragmentSlot, fragAt('uOutputTransform'), interfaceGrade(this.passGrade()));
|
|
3252
|
+
this.textFrags.writeFloat(fragmentSlot, fragAt('uOutputExposure'), 1);
|
|
3225
3253
|
const pass = this.openTextPass();
|
|
3226
3254
|
if (pass === null)
|
|
3227
3255
|
return;
|
|
@@ -3565,19 +3593,26 @@ export class WebGPURenderer {
|
|
|
3565
3593
|
* array allocated with the batch, so the frame loop still allocates nothing.
|
|
3566
3594
|
*/
|
|
3567
3595
|
/**
|
|
3568
|
-
* The
|
|
3569
|
-
*
|
|
3570
|
-
* The
|
|
3571
|
-
* one verb with two implementations, and a frame that grades on one backend and not the other
|
|
3572
|
-
* is the silent kind of disagreement. See that method for what the gate is protecting.
|
|
3596
|
+
* The grade a pass applies to what it draws into the target open now, and the exposure it
|
|
3597
|
+
* applies it at: the WebGPU half of `Renderer.passGrade`, and it has to agree with it draw for
|
|
3598
|
+
* draw. The decision is `passGrade.ts`'s, so both halves only gather the state it is taken from.
|
|
3573
3599
|
*/
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3600
|
+
passGrade() {
|
|
3601
|
+
const storing = this.probePassActive || this.capturePassActive;
|
|
3602
|
+
const transform = this.quality.outputTransform;
|
|
3603
|
+
return passGradeCode(storing, this.framePresented, this.resolveGrades(), transform);
|
|
3604
|
+
}
|
|
3605
|
+
passGradeExposure() {
|
|
3606
|
+
const storing = this.probePassActive || this.capturePassActive;
|
|
3607
|
+
return passGradeExposure(storing, this.framePresented, this.resolveGrades(), this.exposure);
|
|
3608
|
+
}
|
|
3609
|
+
/** Whether the frame's resolve applies the transform, so the passes before it draw linear. */
|
|
3610
|
+
resolveGrades() {
|
|
3611
|
+
return this.hasComposite && this.quality.hdrScene;
|
|
3578
3612
|
}
|
|
3579
|
-
|
|
3580
|
-
|
|
3613
|
+
/** A clear colour as the open target takes it, graded as a pass would. See `gradeColor.ts`. */
|
|
3614
|
+
clearOf(color) {
|
|
3615
|
+
return gradeColorInto(this.passGrade(), this.passGradeExposure(), color, this.gradedClear);
|
|
3581
3616
|
}
|
|
3582
3617
|
drawParticles(batch, data, camera, env, timeSeconds) {
|
|
3583
3618
|
if (!this.canDraw() || data.count === 0)
|
|
@@ -3679,8 +3714,8 @@ export class WebGPURenderer {
|
|
|
3679
3714
|
i[atF('uFogEnabled')] = batch.fog ? 1 : 0;
|
|
3680
3715
|
/* Every material's fragment stage declares these, so they are unconditional like
|
|
3681
3716
|
`uCameraPos` rather than guarded like the material-specific fields above. */
|
|
3682
|
-
i[atF('uOutputTransform')] = this.
|
|
3683
|
-
f[atF('uOutputExposure')] = this.
|
|
3717
|
+
i[atF('uOutputTransform')] = this.passGrade();
|
|
3718
|
+
f[atF('uOutputExposure')] = this.passGradeExposure();
|
|
3684
3719
|
const spriteGroup = batch.material === 'sprite' ? this.spriteFades(batch, camera, f) : null;
|
|
3685
3720
|
device.queue.writeBuffer(batch.vertUniforms, 0, batch.vertStaging);
|
|
3686
3721
|
device.queue.writeBuffer(batch.fragUniforms, 0, batch.fragStaging);
|
|
@@ -3886,6 +3921,8 @@ export class WebGPURenderer {
|
|
|
3886
3921
|
frags.writeInt(fragmentSlot, atF('uFogMode'), medium.fogMode);
|
|
3887
3922
|
frags.writeFloat(fragmentSlot, atF('uFogNear'), medium.fogNear);
|
|
3888
3923
|
frags.writeFloat(fragmentSlot, atF('uFogFar'), medium.fogFar);
|
|
3924
|
+
frags.writeInt(fragmentSlot, atF('uOutputTransform'), this.passGrade());
|
|
3925
|
+
frags.writeFloat(fragmentSlot, atF('uOutputExposure'), this.passGradeExposure());
|
|
3889
3926
|
/*
|
|
3890
3927
|
* **Written for every material, not only the one that reads it.** `arcane` is the only
|
|
3891
3928
|
* plume whose block declares `uTint`, and the slot it lands in is past the end of fire's
|
|
@@ -4037,6 +4074,8 @@ export class WebGPURenderer {
|
|
|
4037
4074
|
/* No reflection pass yet: the shader's own "off" path, not an improvised one. */
|
|
4038
4075
|
i[atF('uReflectionEnabled')] = mirror === null ? 0 : 1;
|
|
4039
4076
|
i[atF('uReflectionFilterTaps')] = water.reflectionFilterTaps;
|
|
4077
|
+
i[atF('uOutputTransform')] = this.passGrade();
|
|
4078
|
+
f[atF('uOutputExposure')] = this.passGradeExposure();
|
|
4040
4079
|
f[atF('uReflectionTexelSize')] = mirror === null ? 1 : 1 / mirror.width;
|
|
4041
4080
|
f[atF('uReflectionTexelSize') + 1] = mirror === null ? 1 : 1 / mirror.height;
|
|
4042
4081
|
/*
|
|
@@ -4166,6 +4205,8 @@ export class WebGPURenderer {
|
|
|
4166
4205
|
ring.writeFloats(fragmentSlot, at('uDustOffset'), options.driftM ?? NO_DRIFT);
|
|
4167
4206
|
ring.writeFloat(fragmentSlot, at('uNear'), options.nearM ?? 0);
|
|
4168
4207
|
ring.writeInt(fragmentSlot, at('uSamples'), this.quality.lightVolumeSamples);
|
|
4208
|
+
ring.writeInt(fragmentSlot, at('uOutputTransform'), this.passGrade());
|
|
4209
|
+
ring.writeFloat(fragmentSlot, at('uOutputExposure'), this.passGradeExposure());
|
|
4169
4210
|
/*
|
|
4170
4211
|
* The clamp that makes a beam end on the floor, and the snapshot it reads.
|
|
4171
4212
|
*
|
|
@@ -4340,6 +4381,10 @@ export class WebGPURenderer {
|
|
|
4340
4381
|
v[at('uCellSize')] = streaks.cellSize;
|
|
4341
4382
|
v[at('uTime')] = timeSeconds;
|
|
4342
4383
|
this.windStreakFragFloats.set(tint, (WIND_STREAK_FRAG_FIELDS.uTint.offset ?? 0) / 4);
|
|
4384
|
+
this.windStreakFragBlock[WIND_STREAK_FRAG_FIELDS.uOutputTransform.offset / 4] =
|
|
4385
|
+
this.passGrade();
|
|
4386
|
+
this.windStreakFragFloats[WIND_STREAK_FRAG_FIELDS.uOutputExposure.offset / 4] =
|
|
4387
|
+
this.passGradeExposure();
|
|
4343
4388
|
this.windStreakVerts.writeBlock(vertexSlot, this.windStreakVertBlock);
|
|
4344
4389
|
this.windStreakFrags.writeBlock(fragmentSlot, this.windStreakFragBlock);
|
|
4345
4390
|
const windPipe = windStreakPipeline(this.blendedPipelines(), this.surface.device, this.windStreakLayout);
|
|
@@ -4425,6 +4470,8 @@ export class WebGPURenderer {
|
|
|
4425
4470
|
v[at('uWind')] = windX;
|
|
4426
4471
|
v[at('uWind') + 1] = windZ;
|
|
4427
4472
|
this.flockFragFloats.set(tint, (FLOCK_FRAG_FIELDS.uTint.offset ?? 0) / 4);
|
|
4473
|
+
this.flockFragBlock[FLOCK_FRAG_FIELDS.uOutputTransform.offset / 4] = this.passGrade();
|
|
4474
|
+
this.flockFragFloats[FLOCK_FRAG_FIELDS.uOutputExposure.offset / 4] = this.passGradeExposure();
|
|
4428
4475
|
this.flockVerts.writeBlock(vertexSlot, this.flockVertBlock);
|
|
4429
4476
|
this.flockFrags.writeBlock(fragmentSlot, this.flockFragBlock);
|
|
4430
4477
|
const flockPipe = flockPipeline(this.pipelines, this.surface.device, this.flockLayout);
|
|
@@ -4517,6 +4564,8 @@ export class WebGPURenderer {
|
|
|
4517
4564
|
f.set(core, atF('uCoreColor'));
|
|
4518
4565
|
f.set(edge, atF('uEdgeColor'));
|
|
4519
4566
|
f[atF('uCoreGain')] = coreGain;
|
|
4567
|
+
i[atF('uOutputTransform')] = this.passGrade();
|
|
4568
|
+
f[atF('uOutputExposure')] = this.passGradeExposure();
|
|
4520
4569
|
f.set(camera.position, atF('uCameraPos'));
|
|
4521
4570
|
/* The medium, through the same resolver every other pass here binds from. */
|
|
4522
4571
|
const medium = resolveAtmosphere(env, camera.position[1] ?? 0, this.quality.underwaterAtmosphere, this.medium);
|
|
@@ -4628,8 +4677,8 @@ export class WebGPURenderer {
|
|
|
4628
4677
|
this.lineFrags.writeFloat(fragmentSlot, atF('uOpacity'), opacity);
|
|
4629
4678
|
this.lineFrags.writeFloats(fragmentSlot, atF('uCameraPos'), camera.position);
|
|
4630
4679
|
this.lineFrags.writeFloat(fragmentSlot, atF('uSoftness'), softness);
|
|
4631
|
-
this.lineFrags.writeInt(fragmentSlot, atF('uOutputTransform'), this.
|
|
4632
|
-
this.lineFrags.writeFloat(fragmentSlot, atF('uOutputExposure'), this.
|
|
4680
|
+
this.lineFrags.writeInt(fragmentSlot, atF('uOutputTransform'), this.passGrade());
|
|
4681
|
+
this.lineFrags.writeFloat(fragmentSlot, atF('uOutputExposure'), this.passGradeExposure());
|
|
4633
4682
|
/* The medium, through the same resolver every other pass here binds from. */
|
|
4634
4683
|
const medium = resolveAtmosphere(env, camera.position[1] ?? 0, this.quality.underwaterAtmosphere, this.medium);
|
|
4635
4684
|
this.lineFrags.writeFloats(fragmentSlot, atF('uFogColor'), medium.fogColor);
|
|
@@ -6726,9 +6775,10 @@ export class WebGPURenderer {
|
|
|
6726
6775
|
* at 92 MB a frame at 824x1830. `ensurePass` opens it on the first draw that wants it, which
|
|
6727
6776
|
* for such a scene is after the last mirror, so it is opened once and cleared once.
|
|
6728
6777
|
*/
|
|
6729
|
-
|
|
6730
|
-
this.pendingClearColor[
|
|
6731
|
-
this.pendingClearColor[
|
|
6778
|
+
const frameClear = this.clearOf(clearColor);
|
|
6779
|
+
this.pendingClearColor[0] = frameClear[0];
|
|
6780
|
+
this.pendingClearColor[1] = frameClear[1];
|
|
6781
|
+
this.pendingClearColor[2] = frameClear[2];
|
|
6732
6782
|
this.pendingClearMask = SCENE_TARGET;
|
|
6733
6783
|
if (this.quality.deferFramePass) {
|
|
6734
6784
|
this.pass = null;
|
|
@@ -7186,6 +7236,7 @@ export class WebGPURenderer {
|
|
|
7186
7236
|
f.set(this.transmission, at('uGlassTint'));
|
|
7187
7237
|
/* Nor layers: one layer until a material asks for more. */
|
|
7188
7238
|
f.fill(0, at('uLayers'), at('uLayers') + LAYER_FLOATS);
|
|
7239
|
+
f.fill(0, at('uLayerLooks'), at('uLayerLooks') + LOOK_FLOATS);
|
|
7189
7240
|
f[at('uCutout')] = 0;
|
|
7190
7241
|
f[at('uCutout') + 1] = 0;
|
|
7191
7242
|
this.cutoutResolveStaged = 'hard';
|
|
@@ -7429,8 +7480,8 @@ export class WebGPURenderer {
|
|
|
7429
7480
|
* `screenEffects` off, or on without `hdrScene`, the mesh pass writes what reaches the
|
|
7430
7481
|
* canvas and grades as it always did.
|
|
7431
7482
|
*/
|
|
7432
|
-
i[at('uOutputTransform')] = this.
|
|
7433
|
-
f[at('uOutputExposure')] = this.
|
|
7483
|
+
i[at('uOutputTransform')] = this.passGrade();
|
|
7484
|
+
f[at('uOutputExposure')] = this.passGradeExposure();
|
|
7434
7485
|
/* The projection occlusion needs, settled by the pass that has a camera. */
|
|
7435
7486
|
this.frameProjection = camera.projection;
|
|
7436
7487
|
/*
|
|
@@ -8148,7 +8199,7 @@ export class WebGPURenderer {
|
|
|
8148
8199
|
/* `1` is sRGB alone: the conversion without the curve. `Math.min` rather than a literal, so
|
|
8149
8200
|
a renderer asked for `none` stays at none. See `TranslucentMeshOptions.toneMapped`. */
|
|
8150
8201
|
if (!toneMapped) {
|
|
8151
|
-
this.perFrameInts[this.materialField('uOutputTransform')] = Math.min(this.
|
|
8202
|
+
this.perFrameInts[this.materialField('uOutputTransform')] = Math.min(this.passGrade(), 1);
|
|
8152
8203
|
}
|
|
8153
8204
|
/*
|
|
8154
8205
|
* **Refraction, and the snapshot it reads is taken here or the draw does not refract.**
|
|
@@ -8289,7 +8340,7 @@ export class WebGPURenderer {
|
|
|
8289
8340
|
if (refracting)
|
|
8290
8341
|
this.releaseSeeThrough();
|
|
8291
8342
|
if (!toneMapped) {
|
|
8292
|
-
this.perFrameInts[this.materialField('uOutputTransform')] = this.
|
|
8343
|
+
this.perFrameInts[this.materialField('uOutputTransform')] = this.passGrade();
|
|
8293
8344
|
}
|
|
8294
8345
|
if (ditheredBlend) {
|
|
8295
8346
|
this.perFrameFloats[this.materialField('uCutout') + 1] =
|
|
@@ -8646,7 +8697,7 @@ export class WebGPURenderer {
|
|
|
8646
8697
|
this.perFrameInts[this.materialField('uFogEnabled')] = fog;
|
|
8647
8698
|
}
|
|
8648
8699
|
if (!toneMapped) {
|
|
8649
|
-
this.perFrameInts[this.materialField('uOutputTransform')] = Math.min(this.
|
|
8700
|
+
this.perFrameInts[this.materialField('uOutputTransform')] = Math.min(this.passGrade(), 1);
|
|
8650
8701
|
}
|
|
8651
8702
|
const depthWrite = options.depthWrite ?? true;
|
|
8652
8703
|
const layer = Math.min(Math.max(Math.round(options.depthLayer ?? 0), 0), MAX_DEPTH_LAYER);
|
|
@@ -8729,7 +8780,7 @@ export class WebGPURenderer {
|
|
|
8729
8780
|
this.perFrameInts[this.materialField('uFogEnabled')] = this.surfaceFog;
|
|
8730
8781
|
}
|
|
8731
8782
|
if (!toneMapped) {
|
|
8732
|
-
this.perFrameInts[this.materialField('uOutputTransform')] = this.
|
|
8783
|
+
this.perFrameInts[this.materialField('uOutputTransform')] = this.passGrade();
|
|
8733
8784
|
}
|
|
8734
8785
|
if (refracting)
|
|
8735
8786
|
this.releaseSeeThrough();
|
|
@@ -8828,6 +8879,8 @@ export class WebGPURenderer {
|
|
|
8828
8879
|
i[atF('uFogMode')] = medium.fogMode;
|
|
8829
8880
|
f[atF('uFogNear')] = medium.fogNear;
|
|
8830
8881
|
f[atF('uFogFar')] = medium.fogFar;
|
|
8882
|
+
i[atF('uOutputTransform')] = this.passGrade();
|
|
8883
|
+
f[atF('uOutputExposure')] = this.passGradeExposure();
|
|
8831
8884
|
const fragmentSlot = this.scatterFrags.allocate();
|
|
8832
8885
|
if (fragmentSlot === null)
|
|
8833
8886
|
return;
|
|
@@ -10219,6 +10272,8 @@ export class WebGPURenderer {
|
|
|
10219
10272
|
const medium = resolveAtmosphere(env, this.atmosphereHeight(camera), this.quality.underwaterAtmosphere, this.medium);
|
|
10220
10273
|
f.set(medium.underwaterColor, at('uUnderwaterColor'));
|
|
10221
10274
|
f[at('uUnderwaterFactor')] = medium.underwaterFactor;
|
|
10275
|
+
this.skyInts[at('uOutputTransform')] = this.passGrade();
|
|
10276
|
+
f[at('uOutputExposure')] = this.passGradeExposure();
|
|
10222
10277
|
const slot = this.skyUniforms.allocate();
|
|
10223
10278
|
if (slot === null) {
|
|
10224
10279
|
if (!this.warnedSkyFull) {
|
|
@@ -10383,6 +10438,8 @@ export class WebGPURenderer {
|
|
|
10383
10438
|
? (OUTPUT_TRANSFORM_CODE[this.quality.outputTransform] ?? 0)
|
|
10384
10439
|
: 0;
|
|
10385
10440
|
f[at('uOutputExposure')] = graded ? this.exposure : 1;
|
|
10441
|
+
/* The occlusion multiplied in as an encoded pixel takes it, where the passes graded the scene. */
|
|
10442
|
+
i[at('uSceneGraded')] = this.passGrade() !== 0 ? 1 : 0;
|
|
10386
10443
|
f.set(this.filmA, at('uFilmA'));
|
|
10387
10444
|
f.set(this.filmB, at('uFilmB'));
|
|
10388
10445
|
f[at('uDisplayHeadroom')] = this.headroom;
|
|
@@ -10917,8 +10974,8 @@ export class WebGPURenderer {
|
|
|
10917
10974
|
});
|
|
10918
10975
|
const context = this.passContext;
|
|
10919
10976
|
context.pass = pass;
|
|
10920
|
-
context.outputTransform = this.
|
|
10921
|
-
context.outputExposure = this.
|
|
10977
|
+
context.outputTransform = this.passGrade();
|
|
10978
|
+
context.outputExposure = this.passGradeExposure();
|
|
10922
10979
|
context.jitter = this.latePassJitter;
|
|
10923
10980
|
context.format = RECON_HISTORY_FORMAT;
|
|
10924
10981
|
context.depthFormat = DEPTH_FORMAT;
|
|
@@ -11471,6 +11528,7 @@ export class WebGPURenderer {
|
|
|
11471
11528
|
f[base + at('uDecalOpacity')] = decal.opacity;
|
|
11472
11529
|
f[base + at('uDecalFacingCos')] = decal.facingCos;
|
|
11473
11530
|
f[base + at('uDecalSoftness')] = decal.softness;
|
|
11531
|
+
this.decalInts[base + at('uOutputTransform')] = this.passGrade();
|
|
11474
11532
|
slot++;
|
|
11475
11533
|
});
|
|
11476
11534
|
device.queue.writeBuffer(this.decalUniforms, 0, this.decalStaging, 0, slot * DECAL_SLOT);
|
|
@@ -11680,6 +11738,8 @@ export class WebGPURenderer {
|
|
|
11680
11738
|
g[upsampleAt('uDepthToViewZ') + 1] = inv[14] ?? 0;
|
|
11681
11739
|
g[upsampleAt('uDepthToViewZ') + 2] = inv[11] ?? 0;
|
|
11682
11740
|
g[upsampleAt('uDepthToViewZ') + 3] = inv[15] ?? 1;
|
|
11741
|
+
this.mediumUpsampleInts[upsampleAt('uOutputTransform')] = this.passGrade();
|
|
11742
|
+
g[upsampleAt('uOutputExposure')] = this.passGradeExposure();
|
|
11683
11743
|
device.queue.writeBuffer(this.mediumUpsampleUniforms, 0, this.mediumUpsampleStaging);
|
|
11684
11744
|
const march = encoder.beginRenderPass({
|
|
11685
11745
|
label: 'post.medium',
|
|
@@ -12213,7 +12273,7 @@ export class WebGPURenderer {
|
|
|
12213
12273
|
this.resolveDepth(encoder);
|
|
12214
12274
|
mat4.invert(this.skinInverseProjection, projection);
|
|
12215
12275
|
const multisampled = this.compositeMsaa();
|
|
12216
|
-
skin.spread(encoder, this.pipelines, resolved, multisampled ?? target, multisampled === null ? null : target, this.samples, projection, this.skinInverseProjection, () => this.gpuTimer.writesFor());
|
|
12276
|
+
skin.spread(encoder, this.pipelines, resolved, multisampled ?? target, multisampled === null ? null : target, this.samples, projection, this.skinInverseProjection, () => this.gpuTimer.writesFor(), this.passGrade(), this.passGradeExposure());
|
|
12217
12277
|
this.pass = encoder.beginRenderPass({
|
|
12218
12278
|
label: 'skin.scattered',
|
|
12219
12279
|
timestampWrites: this.gpuTimer.writesFor(),
|
|
@@ -13365,8 +13425,8 @@ export class WebGPURenderer {
|
|
|
13365
13425
|
const context = this.passContext;
|
|
13366
13426
|
context.pass = pass;
|
|
13367
13427
|
/* The frame's grade, so a contributed pass can obey the 2026-08-17 rule. See `PassContext`. */
|
|
13368
|
-
context.outputTransform = this.
|
|
13369
|
-
context.outputExposure = this.
|
|
13428
|
+
context.outputTransform = this.passGrade();
|
|
13429
|
+
context.outputExposure = this.passGradeExposure();
|
|
13370
13430
|
context.format = target.format;
|
|
13371
13431
|
context.samples = target.sampleCount;
|
|
13372
13432
|
return context;
|
|
@@ -13824,8 +13884,11 @@ export class WebGPURenderer {
|
|
|
13824
13884
|
const slot = this.insetUniforms.allocate();
|
|
13825
13885
|
if (slot !== null) {
|
|
13826
13886
|
/* Only the colour: the quad covers the viewport set above, so it needs no geometry. */
|
|
13827
|
-
const color = clearColor ?? BLACK_CLEAR;
|
|
13828
|
-
this.
|
|
13887
|
+
const color = this.clearOf(clearColor ?? BLACK_CLEAR);
|
|
13888
|
+
this.insetClear[0] = color[0];
|
|
13889
|
+
this.insetClear[1] = color[1];
|
|
13890
|
+
this.insetClear[2] = color[2];
|
|
13891
|
+
this.insetUniforms.writeFloats(slot, 0, this.insetClear);
|
|
13829
13892
|
const insetPipe = insetPipeline(this.targetPipelines(), this.surface.device, this.insetLayout, clearColor !== null);
|
|
13830
13893
|
/*
|
|
13831
13894
|
* Recorded even though the viewport it fills is state on the pass, because it is set
|
|
@@ -14418,6 +14481,8 @@ export class WebGPURenderer {
|
|
|
14418
14481
|
f[atF('uTime')] = timeSeconds;
|
|
14419
14482
|
f[atF('uMaxDrop')] = CAUSTICS_MAX_DROP_M;
|
|
14420
14483
|
f[atF('uStrength')] = strength;
|
|
14484
|
+
i[atF('uOutputTransform')] = this.passGrade();
|
|
14485
|
+
f[atF('uOutputExposure')] = this.passGradeExposure();
|
|
14421
14486
|
f.set(env.directionalDir, atF('uLightDir'));
|
|
14422
14487
|
/*
|
|
14423
14488
|
* What the water is reflecting: the dominant source plus a share of the ambient standing in
|
|
@@ -21,7 +21,7 @@ export declare const SCATTER_DEPTH_SIZE: 240;
|
|
|
21
21
|
export declare const SCATTER_VERT_FIELDS: UniformFields;
|
|
22
22
|
export declare const SCATTER_VERT_SIZE: 240;
|
|
23
23
|
export declare const SCATTER_FRAG_FIELDS: UniformFields;
|
|
24
|
-
export declare const SCATTER_FRAG_SIZE:
|
|
24
|
+
export declare const SCATTER_FRAG_SIZE: 144;
|
|
25
25
|
export declare function scatterVertexLayouts(): GPUVertexBufferLayout[];
|
|
26
26
|
/** Geometry and placement on the device, behind the opaque handle the surface hands out. */
|
|
27
27
|
export interface GpuScatter {
|
|
@@ -7,6 +7,8 @@ export declare class SkinScatterPass {
|
|
|
7
7
|
private readonly layout;
|
|
8
8
|
private readonly uniforms;
|
|
9
9
|
private readonly staging;
|
|
10
|
+
/** The same blocks' ints: the frame's grade, which the second axis applies. */
|
|
11
|
+
private readonly stagingInts;
|
|
10
12
|
private readonly linear;
|
|
11
13
|
private readonly nearest;
|
|
12
14
|
private readonly commands;
|
|
@@ -48,7 +50,9 @@ export declare class SkinScatterPass {
|
|
|
48
50
|
* attachment its pass draws into, `resolve` where a multisampled one resolves, `samples` its
|
|
49
51
|
* count. `projection` is the frame's, `height` the frame's height in pixels.
|
|
50
52
|
*/
|
|
51
|
-
spread(encoder: GPUCommandEncoder, pipelines: PipelineCache, depth: GPUTextureView, frame: GPUTextureView, resolve: GPUTextureView | null, samples: number, projection: ArrayLike<number>, inverseProjection: ArrayLike<number>, timestampWrites: () => GPURenderPassTimestampWrites | undefined
|
|
53
|
+
spread(encoder: GPUCommandEncoder, pipelines: PipelineCache, depth: GPUTextureView, frame: GPUTextureView, resolve: GPUTextureView | null, samples: number, projection: ArrayLike<number>, inverseProjection: ArrayLike<number>, timestampWrites: () => GPURenderPassTimestampWrites | undefined,
|
|
54
|
+
/** The frame's grade, which the second axis applies to the light it adds. */
|
|
55
|
+
outputTransform?: number, outputExposure?: number): void;
|
|
52
56
|
/** Spent at the frame's start: the kept draws were this frame's. */
|
|
53
57
|
reset(): void;
|
|
54
58
|
dispose(): void;
|