@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
|
@@ -117,6 +117,7 @@ import {
|
|
|
117
117
|
packSurfaceLayers,
|
|
118
118
|
} from '../../surfaceLayers.ts';
|
|
119
119
|
import type { SurfaceLayers } from '../../surfaceLayers.ts';
|
|
120
|
+
import { LOOK_FLOATS, asksLayerLooks, packLayerLooks } from '../../surfaceLayerLooks.ts';
|
|
120
121
|
import type { SurfaceProjection } from '../../surfaceProjection.ts';
|
|
121
122
|
import { FILM_FRAG, FILM_VERT } from '../../shaders/film.ts';
|
|
122
123
|
import { SceneTarget } from '../../sceneTarget.ts';
|
|
@@ -339,7 +340,9 @@ import {
|
|
|
339
340
|
RUSH_REACH_UV,
|
|
340
341
|
clampMotionShare,
|
|
341
342
|
} from '../../vertexDefaults.ts';
|
|
342
|
-
import { OUTPUT_TRANSFORM_CODE
|
|
343
|
+
import { OUTPUT_TRANSFORM_CODE } from '../../vertexDefaults.ts';
|
|
344
|
+
import { gradeColorInto } from '../../gradeColor.ts';
|
|
345
|
+
import { interfaceGrade, passGradeCode, passGradeExposure } from '../../passGrade.ts';
|
|
343
346
|
import type { DisplayRange } from '../../displayRange.ts';
|
|
344
347
|
import {
|
|
345
348
|
DEFAULT_FILMIC_CURVE,
|
|
@@ -1783,15 +1786,22 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
1783
1786
|
private readonly transmission = new Float32Array([-1, -1, -1, 0]);
|
|
1784
1787
|
/** `uLayers`, the current material's layers packed. See `surfaceLayers.ts`. */
|
|
1785
1788
|
private readonly layerFloats = new Float32Array(LAYER_FLOATS);
|
|
1789
|
+
/** `uLayerLooks`, the current material's layer picks and looks packed. See `surfaceLayerLooks.ts`. */
|
|
1790
|
+
private readonly lookFloats = new Float32Array(LOOK_FLOATS);
|
|
1786
1791
|
/** Whether the lit stage has room for layers' two vectors, and which refusals were said. */
|
|
1787
1792
|
private layersRoom: boolean | null = null;
|
|
1788
1793
|
private warnedLayersRoom = false;
|
|
1794
|
+
/** Whether it has room for the layers' looks beside them, and whether the refusal was said. */
|
|
1795
|
+
private looksRoom: boolean | null = null;
|
|
1796
|
+
private warnedLooksRoom = false;
|
|
1789
1797
|
private warnedLayersModelMap = false;
|
|
1790
1798
|
private warnedLayersTriplanar = false;
|
|
1791
1799
|
private warnedOverlayRoom = false;
|
|
1792
1800
|
private warnedOverlayBlocks = false;
|
|
1793
1801
|
/** Whether a probe is being baked, so the passes that would recurse into one can tell. */
|
|
1794
1802
|
private probePassActive = false;
|
|
1803
|
+
/** `clearOf`'s scratch: a clear colour as the open target takes it. */
|
|
1804
|
+
private readonly gradedClear: Vec3 = [0, 0, 0];
|
|
1795
1805
|
/**
|
|
1796
1806
|
* Whether a scene capture is being drawn (`captureScene`): an off-screen pass like a bake, so the
|
|
1797
1807
|
* frame's own view, its refraction copy and skin's spread are left alone, but lit as the frame is.
|
|
@@ -2557,8 +2567,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
2557
2567
|
sceneDepth: null,
|
|
2558
2568
|
};
|
|
2559
2569
|
const context = this.passContext;
|
|
2560
|
-
context.outputTransform = this.
|
|
2561
|
-
context.outputExposure = this.
|
|
2570
|
+
context.outputTransform = this.passGrade();
|
|
2571
|
+
context.outputExposure = this.passGradeExposure();
|
|
2562
2572
|
/*
|
|
2563
2573
|
* The copies a pass declared it reads, taken here with everything drawn before it: colour
|
|
2564
2574
|
* afresh at each reading pass, as WebGPU's `takePassColour` does, so a full-screen effect drawn
|
|
@@ -3887,11 +3897,11 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
3887
3897
|
} finally {
|
|
3888
3898
|
target.end(gl);
|
|
3889
3899
|
gl.frontFace(gl.CCW);
|
|
3900
|
+
this.capturePassActive = false;
|
|
3890
3901
|
this.useFlatProgram();
|
|
3891
|
-
gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.
|
|
3892
|
-
gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.
|
|
3902
|
+
gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.passGrade());
|
|
3903
|
+
gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
3893
3904
|
this.materials.dirty();
|
|
3894
|
-
this.capturePassActive = false;
|
|
3895
3905
|
this.temporalJittering = jittering;
|
|
3896
3906
|
this.restoreViewport();
|
|
3897
3907
|
}
|
|
@@ -4398,6 +4408,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4398
4408
|
packSurfaceLayers(layers, this.layerFloats);
|
|
4399
4409
|
if (layers !== null) this.askLit('LAYERED');
|
|
4400
4410
|
gl.uniform4fv(u['uLayers'] ?? null, this.layerFloats);
|
|
4411
|
+
packLayerLooks(layers, this.lookFloats);
|
|
4412
|
+
if (this.looksFit(layers)) this.askLit('LAYER_LOOKS');
|
|
4413
|
+
gl.uniform4fv(u['uLayerLooks'] ?? null, this.lookFloats);
|
|
4401
4414
|
gl.uniform1i(u['uModelMap'] ?? null, MODEL_MAP_TEXTURE_UNIT);
|
|
4402
4415
|
packModel(
|
|
4403
4416
|
material?.model ?? null,
|
|
@@ -4691,6 +4704,28 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4691
4704
|
return null;
|
|
4692
4705
|
}
|
|
4693
4706
|
|
|
4707
|
+
/**
|
|
4708
|
+
* Whether a layered material's picks and looks are drawn: asked for, and room for their fifteen
|
|
4709
|
+
* vectors beside the layers' four. Refused, the layers are drawn reading layer `i` of their arrays
|
|
4710
|
+
* as they are, said once — which on a material sharing its arrays reads the wrong textures, so
|
|
4711
|
+
* the sentence names the way out.
|
|
4712
|
+
*/
|
|
4713
|
+
private looksFit(layers: SurfaceLayers<SurfaceTexture> | null): boolean {
|
|
4714
|
+
if (!asksLayerLooks(layers)) return false;
|
|
4715
|
+
this.looksRoom ??= this.switchFits('LAYER_LOOKS', 'LAYERED');
|
|
4716
|
+
if (this.looksRoom) return true;
|
|
4717
|
+
if (!this.warnedLooksRoom) {
|
|
4718
|
+
this.warnedLooksRoom = true;
|
|
4719
|
+
console.warn(
|
|
4720
|
+
"Renderer: a layered material's picks and looks are refused on this device. They take " +
|
|
4721
|
+
'fifteen fragment uniform vectors the lit shader does not have, so its layers read layer ' +
|
|
4722
|
+
'i of its arrays, untinted, at one repeat each. A lower `maxLights` makes the room, or ' +
|
|
4723
|
+
'WebGPU has it.',
|
|
4724
|
+
);
|
|
4725
|
+
}
|
|
4726
|
+
return false;
|
|
4727
|
+
}
|
|
4728
|
+
|
|
4694
4729
|
/** Says once that a layered material's triplanar projection is laid on the horizontal plane. */
|
|
4695
4730
|
private warnLayersTriplanar(): void {
|
|
4696
4731
|
if (this.warnedLayersTriplanar) return;
|
|
@@ -4701,9 +4736,13 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
4701
4736
|
);
|
|
4702
4737
|
}
|
|
4703
4738
|
|
|
4704
|
-
/**
|
|
4705
|
-
|
|
4739
|
+
/**
|
|
4740
|
+
* Whether the lit shader with `feature` compiled in, and `beside` with it where a switch means
|
|
4741
|
+
* nothing alone, fits this GPU's fragment uniform vectors.
|
|
4742
|
+
*/
|
|
4743
|
+
private switchFits(feature: LitSwitch, beside?: LitSwitch): boolean {
|
|
4706
4744
|
const asIf: Partial<Record<LitSwitch, boolean>> = { [feature]: true };
|
|
4745
|
+
if (beside !== undefined) asIf[beside] = true;
|
|
4707
4746
|
return (
|
|
4708
4747
|
countUniformVectors(this.flatFragAt(this.lightBudget, asIf)) <= this.fragmentVectorLimit()
|
|
4709
4748
|
);
|
|
@@ -5254,7 +5293,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5254
5293
|
*/
|
|
5255
5294
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 0);
|
|
5256
5295
|
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, fog);
|
|
5257
|
-
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.
|
|
5296
|
+
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.passGrade(), 1));
|
|
5258
5297
|
|
|
5259
5298
|
if (blend) {
|
|
5260
5299
|
gl.enable(gl.BLEND);
|
|
@@ -5312,7 +5351,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5312
5351
|
if (refracting) this.unbindSeeThrough(u);
|
|
5313
5352
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
5314
5353
|
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, this.surfaceFog);
|
|
5315
|
-
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
5354
|
+
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
5316
5355
|
if (own) this.materials.dirty();
|
|
5317
5356
|
this.useFlatProgram();
|
|
5318
5357
|
}
|
|
@@ -5488,7 +5527,18 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5488
5527
|
// raining dust into the sea.
|
|
5489
5528
|
const surface = env.underwater?.surfaceY;
|
|
5490
5529
|
const submerged = surface !== undefined && (camera.position[1] ?? 0) < surface;
|
|
5491
|
-
if (
|
|
5530
|
+
if (
|
|
5531
|
+
streaks.draw(
|
|
5532
|
+
this.gl,
|
|
5533
|
+
this.frameViewFor(camera),
|
|
5534
|
+
wind,
|
|
5535
|
+
timeSeconds,
|
|
5536
|
+
tint,
|
|
5537
|
+
submerged,
|
|
5538
|
+
this.passGrade(),
|
|
5539
|
+
this.passGradeExposure(),
|
|
5540
|
+
)
|
|
5541
|
+
) {
|
|
5492
5542
|
this.windStreakBudget.ask();
|
|
5493
5543
|
}
|
|
5494
5544
|
}
|
|
@@ -5528,7 +5578,18 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5528
5578
|
timeSec: number,
|
|
5529
5579
|
): void {
|
|
5530
5580
|
this.scatterSkin();
|
|
5531
|
-
if (
|
|
5581
|
+
if (
|
|
5582
|
+
text.draw(
|
|
5583
|
+
viewportWidth,
|
|
5584
|
+
viewportHeight,
|
|
5585
|
+
originX,
|
|
5586
|
+
originY,
|
|
5587
|
+
style,
|
|
5588
|
+
timeSec,
|
|
5589
|
+
interfaceGrade(this.passGrade()),
|
|
5590
|
+
1,
|
|
5591
|
+
)
|
|
5592
|
+
) {
|
|
5532
5593
|
this.textBudget.ask();
|
|
5533
5594
|
}
|
|
5534
5595
|
}
|
|
@@ -5607,7 +5668,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5607
5668
|
* real draw call touches the unit in the first place.
|
|
5608
5669
|
*/
|
|
5609
5670
|
/**
|
|
5610
|
-
* The
|
|
5671
|
+
* The grade a pass applies to what it draws into the target open now, and the exposure it
|
|
5672
|
+
* applies it at. The decision is `passGrade.ts`'s, for both backends; this only gathers the
|
|
5673
|
+
* state it is taken from.
|
|
5611
5674
|
*
|
|
5612
5675
|
* **Only where that pass is genuinely the last one to touch the frame.** With a scene target
|
|
5613
5676
|
* the resolve grades, so a pass that graded as well would be applying a curve to its own
|
|
@@ -5615,21 +5678,37 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5615
5678
|
* `screenEffects` off there is no resolve at all and every pass writes straight to the canvas,
|
|
5616
5679
|
* so each one has to grade itself or the frame comes out half converted: linear values in an
|
|
5617
5680
|
* eight-bit buffer read as display values, which is a saturated, clipped version of the colour
|
|
5618
|
-
* the caller asked for rather than a slightly different one.
|
|
5681
|
+
* the caller asked for rather than a slightly different one. A probe's face or a capture is
|
|
5682
|
+
* never graded, and past the present every pass grades itself, composite or not.
|
|
5619
5683
|
*
|
|
5620
5684
|
* One pair of accessors rather than the expression written out at each site, because that is
|
|
5621
5685
|
* how the mesh pass and the particle pass came to disagree in the first place: the mesh pass
|
|
5622
5686
|
* gated, and the particle pass uploaded the transform unconditionally to a stage that did not
|
|
5623
5687
|
* yet declare it.
|
|
5624
5688
|
*/
|
|
5625
|
-
private
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5689
|
+
private passGrade(): number {
|
|
5690
|
+
const storing = this.probePassActive || this.capturePassActive;
|
|
5691
|
+
const transform = this.quality.outputTransform;
|
|
5692
|
+
return passGradeCode(storing, this.framePresented, this.resolveGrades(), transform);
|
|
5629
5693
|
}
|
|
5630
5694
|
|
|
5631
|
-
private
|
|
5632
|
-
|
|
5695
|
+
private passGradeExposure(): number {
|
|
5696
|
+
const storing = this.probePassActive || this.capturePassActive;
|
|
5697
|
+
return passGradeExposure(storing, this.framePresented, this.resolveGrades(), this.exposure);
|
|
5698
|
+
}
|
|
5699
|
+
|
|
5700
|
+
/** Whether the frame's resolve applies the transform, so the passes before it draw linear. */
|
|
5701
|
+
private resolveGrades(): boolean {
|
|
5702
|
+
return this.sceneTarget !== null && this.quality.hdrScene;
|
|
5703
|
+
}
|
|
5704
|
+
|
|
5705
|
+
/**
|
|
5706
|
+
* A clear colour as the target open now takes it: graded as a pass would grade it, so a colour
|
|
5707
|
+
* handed to the renderer is linear wherever it lands — the clear too, which the resolve grades
|
|
5708
|
+
* with everything else under `hdrScene`. See `gradeColor.ts`. Into one scratch, read at once.
|
|
5709
|
+
*/
|
|
5710
|
+
private clearOf(color: Readonly<Vec3>): Vec3 {
|
|
5711
|
+
return gradeColorInto(this.passGrade(), this.passGradeExposure(), color, this.gradedClear);
|
|
5633
5712
|
}
|
|
5634
5713
|
|
|
5635
5714
|
drawSdfText(handle: SdfTextRenderer, model: Float32Array, color: Vec3, opacity: number): void {
|
|
@@ -5644,8 +5723,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5644
5723
|
model,
|
|
5645
5724
|
color,
|
|
5646
5725
|
opacity,
|
|
5647
|
-
this.
|
|
5648
|
-
this.
|
|
5726
|
+
this.passGrade(),
|
|
5727
|
+
this.passGradeExposure(),
|
|
5649
5728
|
)
|
|
5650
5729
|
) {
|
|
5651
5730
|
this.sdfTextBudget.ask();
|
|
@@ -5672,7 +5751,17 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5672
5751
|
windZ = 0,
|
|
5673
5752
|
): void {
|
|
5674
5753
|
this.flockBudget.ask();
|
|
5675
|
-
flock.draw(
|
|
5754
|
+
flock.draw(
|
|
5755
|
+
this.gl,
|
|
5756
|
+
this.frameViewFor(camera),
|
|
5757
|
+
timeSeconds,
|
|
5758
|
+
params,
|
|
5759
|
+
tint,
|
|
5760
|
+
windX,
|
|
5761
|
+
windZ,
|
|
5762
|
+
this.passGrade(),
|
|
5763
|
+
this.passGradeExposure(),
|
|
5764
|
+
);
|
|
5676
5765
|
}
|
|
5677
5766
|
|
|
5678
5767
|
/**
|
|
@@ -5773,8 +5862,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5773
5862
|
the uniform at all, so it was a write to a location that did not exist; now that the
|
|
5774
5863
|
stage grades itself it has to obey the same "only where this pass is last" rule the mesh
|
|
5775
5864
|
pass does, or a scene with a composite grades its particles twice. */
|
|
5776
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
5777
|
-
gl.uniform1f(u['uOutputExposure'] ?? null, this.
|
|
5865
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
5866
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
5778
5867
|
gl.uniform3fv(u['uAmbient'] ?? null, env.ambient);
|
|
5779
5868
|
gl.uniform3fv(u['uAmbientGround'] ?? null, env.ambientGround ?? env.ambient);
|
|
5780
5869
|
gl.uniform1i(u['uNoiseOctaves'] ?? null, this.quality.plumeNoiseOctaves);
|
|
@@ -5882,6 +5971,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5882
5971
|
gl.uniform3fv(u['uCoreColor'] ?? null, core);
|
|
5883
5972
|
gl.uniform3fv(u['uEdgeColor'] ?? null, edge);
|
|
5884
5973
|
gl.uniform1f(u['uCoreGain'] ?? null, coreGain);
|
|
5974
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
5975
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
5885
5976
|
bindAtmosphere(
|
|
5886
5977
|
gl,
|
|
5887
5978
|
u,
|
|
@@ -5957,8 +6048,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
5957
6048
|
gl.uniform3fv(u['uColor'] ?? null, color);
|
|
5958
6049
|
gl.uniform1f(u['uOpacity'] ?? null, opacity);
|
|
5959
6050
|
gl.uniform1f(u['uSoftness'] ?? null, softness);
|
|
5960
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
5961
|
-
gl.uniform1f(u['uOutputExposure'] ?? null, this.
|
|
6051
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
6052
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
5962
6053
|
bindAtmosphere(
|
|
5963
6054
|
gl,
|
|
5964
6055
|
u,
|
|
@@ -6007,6 +6098,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6007
6098
|
gl.uniform3fv(u['uDirectionalColor'] ?? null, env.directionalColor);
|
|
6008
6099
|
gl.uniform3fv(u['uAmbient'] ?? null, env.ambient);
|
|
6009
6100
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
6101
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
6102
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
6010
6103
|
bindAtmosphere(
|
|
6011
6104
|
gl,
|
|
6012
6105
|
u,
|
|
@@ -6201,6 +6294,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6201
6294
|
originX,
|
|
6202
6295
|
originY,
|
|
6203
6296
|
originZ,
|
|
6297
|
+
this.passGrade(),
|
|
6298
|
+
this.passGradeExposure(),
|
|
6204
6299
|
);
|
|
6205
6300
|
}
|
|
6206
6301
|
|
|
@@ -6230,6 +6325,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6230
6325
|
this.quality.pointLightFalloff,
|
|
6231
6326
|
windX,
|
|
6232
6327
|
windZ,
|
|
6328
|
+
this.passGrade(),
|
|
6329
|
+
this.passGradeExposure(),
|
|
6233
6330
|
);
|
|
6234
6331
|
}
|
|
6235
6332
|
|
|
@@ -6260,6 +6357,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6260
6357
|
windX,
|
|
6261
6358
|
windZ,
|
|
6262
6359
|
strength,
|
|
6360
|
+
this.passGrade(),
|
|
6361
|
+
this.passGradeExposure(),
|
|
6263
6362
|
);
|
|
6264
6363
|
if (drew) this.causticsBudget.ask();
|
|
6265
6364
|
}
|
|
@@ -6302,7 +6401,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6302
6401
|
this.canvas.height,
|
|
6303
6402
|
source,
|
|
6304
6403
|
planeY,
|
|
6305
|
-
clearColor,
|
|
6404
|
+
this.clearOf(clearColor),
|
|
6306
6405
|
);
|
|
6307
6406
|
this.gpuTimer.begin('reflection');
|
|
6308
6407
|
this.reflectionPassActive = true;
|
|
@@ -6960,6 +7059,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
6960
7059
|
worldUvs: asIf.WORLD_UVS ?? this.litOn.WORLD_UVS,
|
|
6961
7060
|
movingSun: asIf.MOVING_SUN ?? this.litOn.MOVING_SUN,
|
|
6962
7061
|
layered: asIf.LAYERED ?? this.litOn.LAYERED,
|
|
7062
|
+
layerLooks: asIf.LAYER_LOOKS ?? this.litOn.LAYER_LOOKS,
|
|
6963
7063
|
maxLights: budget.maxLights,
|
|
6964
7064
|
maxAreaLights: budget.maxAreaLights,
|
|
6965
7065
|
});
|
|
@@ -7615,7 +7715,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7615
7715
|
// scene rather than over a rectangle of flat colour.
|
|
7616
7716
|
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
7617
7717
|
} else {
|
|
7618
|
-
|
|
7718
|
+
const clear = this.clearOf(clearColor);
|
|
7719
|
+
gl.clearColor(clear[0], clear[1], clear[2], 1);
|
|
7619
7720
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
7620
7721
|
}
|
|
7621
7722
|
/*
|
|
@@ -7725,6 +7826,9 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
7725
7826
|
gl.uniformMatrix4fv(this.panelUniforms['uClipCorrection'] ?? null, false, IDENTITY_MAT4);
|
|
7726
7827
|
gl.uniform3fv(this.panelUniforms['uColor'] ?? null, color);
|
|
7727
7828
|
gl.uniform1f(this.panelUniforms['uAlpha'] ?? null, alpha);
|
|
7829
|
+
/* An interface: the screen encode, never the curve. See `interfaceGrade`. */
|
|
7830
|
+
gl.uniform1i(this.panelUniforms['uOutputTransform'] ?? null, interfaceGrade(this.passGrade()));
|
|
7831
|
+
gl.uniform1f(this.panelUniforms['uOutputExposure'] ?? null, 1);
|
|
7728
7832
|
|
|
7729
7833
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
7730
7834
|
|
|
@@ -8451,7 +8555,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8451
8555
|
this.sceneTarget?.begin(this.canvas.width, this.canvas.height);
|
|
8452
8556
|
/* The materials' maps on the scene's framebuffer, cleared and disabled: `reflectionKeeps`. */
|
|
8453
8557
|
this.reflectionTargets?.begin(this.canvas.width, this.canvas.height);
|
|
8454
|
-
|
|
8558
|
+
const clear = this.clearOf(clearColor);
|
|
8559
|
+
gl.clearColor(clear[0], clear[1], clear[2], 1);
|
|
8455
8560
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
8456
8561
|
}
|
|
8457
8562
|
|
|
@@ -8606,7 +8711,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8606
8711
|
exposure: this.exposure,
|
|
8607
8712
|
film: this.filmConstants,
|
|
8608
8713
|
}
|
|
8609
|
-
: { transform: 0, exposure: 1 };
|
|
8714
|
+
: { transform: 0, exposure: 1, sceneGraded: this.passGrade() !== 0 };
|
|
8610
8715
|
/*
|
|
8611
8716
|
* Depth of field, on the same ceiling-and-dial split as bloom above: `depthOfField` decides
|
|
8612
8717
|
* how far a defocused point may spread and this frame's `setDepthOfField` decides where the
|
|
@@ -8669,6 +8774,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8669
8774
|
this.frameEye,
|
|
8670
8775
|
this.canvas.width,
|
|
8671
8776
|
this.canvas.height,
|
|
8777
|
+
this.passGrade(),
|
|
8672
8778
|
);
|
|
8673
8779
|
}
|
|
8674
8780
|
}
|
|
@@ -8866,7 +8972,13 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
8866
8972
|
/* The march finished on the default framebuffer, which is not where the frame is being
|
|
8867
8973
|
drawn. See `resolveReflections`, which is the same two-step for the same reason. */
|
|
8868
8974
|
this.sceneTarget.bind();
|
|
8869
|
-
this.medium.compositeMedium(
|
|
8975
|
+
this.medium.compositeMedium(
|
|
8976
|
+
depthCopy,
|
|
8977
|
+
this.canvas.width,
|
|
8978
|
+
this.canvas.height,
|
|
8979
|
+
this.passGrade(),
|
|
8980
|
+
this.passGradeExposure(),
|
|
8981
|
+
);
|
|
8870
8982
|
}
|
|
8871
8983
|
}
|
|
8872
8984
|
}
|
|
@@ -9116,6 +9228,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
9116
9228
|
resolveTransmission(null, this.transmission);
|
|
9117
9229
|
/* Nor layers: one layer until a material asks for more. */
|
|
9118
9230
|
this.layerFloats.fill(0);
|
|
9231
|
+
this.lookFloats.fill(0);
|
|
9119
9232
|
this.overlayMaps = null;
|
|
9120
9233
|
this.overlayTexture = null;
|
|
9121
9234
|
/* Nor an ambient of its own: the frame's, until a draw asks. See `setAmbientSH`. */
|
|
@@ -9290,6 +9403,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
9290
9403
|
gl.uniform4fv(u['uOverlay'] ?? null, this.overlayFloats);
|
|
9291
9404
|
gl.uniform4fv(u['uWorldUv'] ?? null, this.projection);
|
|
9292
9405
|
gl.uniform4fv(u['uLayers'] ?? null, this.layerFloats);
|
|
9406
|
+
gl.uniform4fv(u['uLayerLooks'] ?? null, this.lookFloats);
|
|
9293
9407
|
/* Neither refracting nor glass, which is every draw that does not say otherwise. See
|
|
9294
9408
|
`bindSeeThrough` for the four numbers in the one vector. */
|
|
9295
9409
|
gl.uniform4f(u['uSeeThrough'] ?? null, 0, 0, 0, 0);
|
|
@@ -9343,12 +9457,11 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
9343
9457
|
* exists to keep. With `screenEffects` off there is no resolve at all and the mesh pass
|
|
9344
9458
|
* writes straight to the canvas, so it stays where it always was.
|
|
9345
9459
|
*
|
|
9346
|
-
*
|
|
9347
|
-
*
|
|
9348
|
-
* inconsistency that existed everywhere before this moved.
|
|
9460
|
+
* Every other pass grades through the same gate, `passGrade`, so a frame without a composite
|
|
9461
|
+
* is graded pass by pass to the curve a composite would have applied once.
|
|
9349
9462
|
*/
|
|
9350
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
9351
|
-
gl.uniform1f(u['uOutputExposure'] ?? null, this.
|
|
9463
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
9464
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
9352
9465
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
9353
9466
|
/*
|
|
9354
9467
|
* Solid, every frame, before anything asks otherwise. A GL uniform starts at
|
|
@@ -9837,7 +9950,15 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
9837
9950
|
if (projection === null) return;
|
|
9838
9951
|
const depth = scene.snapshotDepth(true);
|
|
9839
9952
|
mat4.invert(this.skinInverseProjection, projection);
|
|
9840
|
-
skin.spread(
|
|
9953
|
+
skin.spread(
|
|
9954
|
+
scene,
|
|
9955
|
+
depth,
|
|
9956
|
+
this.emptyTexture2D,
|
|
9957
|
+
projection,
|
|
9958
|
+
this.skinInverseProjection,
|
|
9959
|
+
this.passGrade(),
|
|
9960
|
+
this.passGradeExposure(),
|
|
9961
|
+
);
|
|
9841
9962
|
this.useFlatProgram();
|
|
9842
9963
|
}
|
|
9843
9964
|
|
|
@@ -10150,7 +10271,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
10150
10271
|
/* `1` is sRGB alone: the conversion without the curve, which is what dropping the tone map
|
|
10151
10272
|
means rather than dropping the whole transform. `Math.min` rather than a literal, so a
|
|
10152
10273
|
renderer asked for `none` stays at none and one asked for `srgb` is already there. */
|
|
10153
|
-
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.
|
|
10274
|
+
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.passGrade(), 1));
|
|
10154
10275
|
/* Scoped and handed back like every other state here, so a tinted draw cannot leak its
|
|
10155
10276
|
colour onto the next one. See `TranslucentMeshOptions.tint`. */
|
|
10156
10277
|
const tint = options.tint ?? null;
|
|
@@ -10221,7 +10342,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
10221
10342
|
cannot inherit a material from the draw before it. */
|
|
10222
10343
|
if (!lit) gl.uniform1i(u['uLightingEnabled'] ?? null, 1);
|
|
10223
10344
|
if (fog !== this.surfaceFog) gl.uniform1i(u['uFogEnabled'] ?? null, this.surfaceFog);
|
|
10224
|
-
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
10345
|
+
if (!toneMapped) gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
10225
10346
|
if (own) this.materials.dirty();
|
|
10226
10347
|
}
|
|
10227
10348
|
|
|
@@ -10324,7 +10445,7 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
10324
10445
|
/*
|
|
10325
10446
|
* **A probe stores radiance, not display pixels.**
|
|
10326
10447
|
*
|
|
10327
|
-
* `
|
|
10448
|
+
* `passGrade()` is the ACES curve and the sRGB encode whenever the frame has no HDR target,
|
|
10328
10449
|
* so every face was baked through the whole output transform and the shader then sampled the
|
|
10329
10450
|
* result as though it were light. Two things came of that and both read as "the reflection is
|
|
10330
10451
|
* dull": the curve pulls everything bright toward 1 *before* it reaches the cube, so no
|
|
@@ -10380,16 +10501,17 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
10380
10501
|
}
|
|
10381
10502
|
} finally {
|
|
10382
10503
|
this.gl.frontFace(this.gl.CCW);
|
|
10383
|
-
this.useFlatProgram();
|
|
10384
|
-
this.gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.gradeCode());
|
|
10385
|
-
this.gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.gradeExposure());
|
|
10386
|
-
this.materials.dirty();
|
|
10387
10504
|
/*
|
|
10388
10505
|
* Cleared even if a caller's own draw threw, because leaving this set would keep every
|
|
10389
|
-
* later frame reading the placeholder and quietly reflecting nothing.
|
|
10506
|
+
* later frame reading the placeholder and quietly reflecting nothing. Before the grade is
|
|
10507
|
+
* put back, which asks it.
|
|
10390
10508
|
*/
|
|
10391
10509
|
this.probePassActive = false;
|
|
10392
10510
|
this.probeBounce = false;
|
|
10511
|
+
this.useFlatProgram();
|
|
10512
|
+
this.gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.passGrade());
|
|
10513
|
+
this.gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
10514
|
+
this.materials.dirty();
|
|
10393
10515
|
/* Back to the canvas, or to the frame's own target if one is bound. See `SceneTarget`. */
|
|
10394
10516
|
if (this.sceneTarget !== null && !this.framePresented) this.sceneTarget.bind();
|
|
10395
10517
|
else {
|
|
@@ -10617,6 +10739,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
10617
10739
|
gl.uniformMatrix4fv(u['uModel'] ?? null, false, model);
|
|
10618
10740
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
10619
10741
|
gl.uniform1f(u['uStrength'] ?? null, Math.min(shown, 1));
|
|
10742
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
10743
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
10620
10744
|
gl.uniform1f(u['uLength'] ?? null, length);
|
|
10621
10745
|
gl.uniform1f(u['uSpread'] ?? null, spread);
|
|
10622
10746
|
gl.uniform1f(u['uDust'] ?? null, clamp(options.dust ?? 0, 0, 1));
|
|
@@ -10782,6 +10906,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
10782
10906
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
10783
10907
|
gl.uniform1f(u['uTime'] ?? null, timeSeconds);
|
|
10784
10908
|
gl.uniform1f(u['uSheen'] ?? null, sheen);
|
|
10909
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
10910
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
10785
10911
|
gl.uniform1f(u['uFilmRoughness'] ?? null, Math.min(1, Math.max(0, options.roughness ?? 0)));
|
|
10786
10912
|
gl.uniform1f(
|
|
10787
10913
|
u['uFilmRoughnessCycles'] ?? null,
|
|
@@ -10837,6 +10963,8 @@ export class WebGL2Renderer implements RendererApi {
|
|
|
10837
10963
|
gl.uniform1f(u['uMoonPhase'] ?? null, sky.moonPhase);
|
|
10838
10964
|
gl.uniform1f(u['uNightFactor'] ?? null, sky.nightFactor);
|
|
10839
10965
|
gl.uniform2f(u['uCloudOffset'] ?? null, sky.cloudOffsetX, sky.cloudOffsetZ);
|
|
10966
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
10967
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
10840
10968
|
bindAtmosphere(
|
|
10841
10969
|
gl,
|
|
10842
10970
|
u,
|
|
@@ -147,6 +147,9 @@ export class GlSkinScatter {
|
|
|
147
147
|
empty: WebGLTexture,
|
|
148
148
|
projection: ArrayLike<number>,
|
|
149
149
|
inverse: ArrayLike<number>,
|
|
150
|
+
/** The frame's grade, which the second axis applies to the light it adds. */
|
|
151
|
+
outputTransform = 0,
|
|
152
|
+
outputExposure = 1,
|
|
150
153
|
): void {
|
|
151
154
|
const { gl } = this;
|
|
152
155
|
if (this.multisampled !== null) {
|
|
@@ -163,6 +166,8 @@ export class GlSkinScatter {
|
|
|
163
166
|
gl.uniform1i(u['uSkin'] ?? null, SKIN_BLUR_TEXTURE_UNIT);
|
|
164
167
|
gl.uniform1i(u['uDepth'] ?? null, SKIN_BLUR_DEPTH_UNIT);
|
|
165
168
|
gl.uniform1i(u['uAlbedo'] ?? null, SKIN_BLUR_ALBEDO_UNIT);
|
|
169
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
|
|
170
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, outputExposure);
|
|
166
171
|
gl.activeTexture(gl.TEXTURE0 + SKIN_BLUR_ALBEDO_UNIT);
|
|
167
172
|
gl.bindTexture(gl.TEXTURE_2D, this.albedo ?? empty);
|
|
168
173
|
/* The four terms that carry a depth back to view-space metres: the occlusion blur's own. */
|
|
@@ -41,7 +41,9 @@ const STORAGE = 0x0080;
|
|
|
41
41
|
* can look at, and looking is what a number cannot replace: if the geometry is in the right places
|
|
42
42
|
* at the right sizes the composition is right, and if a cascade boundary shows as a seam the fade
|
|
43
43
|
* is wrong. Wave 4A's own recorded failure — a phantom surface that passed 111,907 parity samples
|
|
44
|
-
* and was found by looking at a picture — is why this exists at all.
|
|
44
|
+
* and was found by looking at a picture — is why this exists at all. **So it is not graded**, alone
|
|
45
|
+
* of the passes that draw into a frame: what it shows are the field's values, which a curve would
|
|
46
|
+
* bend into a picture of something else.
|
|
45
47
|
*
|
|
46
48
|
* **The field it marches is one frame old**, because the renderer composes at `endFrame` and
|
|
47
49
|
* `prepare` runs at `beginFrame`. `PrepareContext.distanceField` says why that is right rather
|
|
@@ -962,7 +962,16 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
962
962
|
shadowed: true,
|
|
963
963
|
blended: false,
|
|
964
964
|
};
|
|
965
|
-
|
|
965
|
+
/**
|
|
966
|
+
* The frame's grade for the blit, `PassContext.outputTransform` and its exposure, and the code it
|
|
967
|
+
* was last written with, so a frame writes it only when it changes. See `present.wgsl.ts`.
|
|
968
|
+
*/
|
|
969
|
+
private gradeBuffer: GPUBuffer | null = null;
|
|
970
|
+
private readonly gradeStaging = new ArrayBuffer(16);
|
|
971
|
+
private readonly gradeInts = new Int32Array(this.gradeStaging);
|
|
972
|
+
private readonly gradeFloats = new Float32Array(this.gradeStaging);
|
|
973
|
+
private gradeWrittenCode = Number.NaN;
|
|
974
|
+
private gradeWrittenExposure = Number.NaN;
|
|
966
975
|
|
|
967
976
|
constructor(
|
|
968
977
|
scene: StreamingScene,
|
|
@@ -2410,10 +2419,17 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
2410
2419
|
],
|
|
2411
2420
|
});
|
|
2412
2421
|
|
|
2422
|
+
this.gradeBuffer ??= device.createBuffer({
|
|
2423
|
+
label: 'gpu-driven blit grade',
|
|
2424
|
+
size: this.gradeStaging.byteLength,
|
|
2425
|
+
usage: UNIFORM | COPY_DST,
|
|
2426
|
+
});
|
|
2427
|
+
this.gradeWrittenCode = Number.NaN;
|
|
2413
2428
|
this.blitGroup = device.createBindGroup({
|
|
2414
2429
|
layout: (this.blitPipeline as GPURenderPipeline).getBindGroupLayout(0),
|
|
2415
2430
|
entries: [
|
|
2416
2431
|
{ binding: 0, resource: this.colourView as GPUTextureView },
|
|
2432
|
+
{ binding: 2, resource: { buffer: this.gradeBuffer } },
|
|
2417
2433
|
/* The depth the raster wrote, sampled so the blit can hand it to the frame. */
|
|
2418
2434
|
...(this.presentDepth
|
|
2419
2435
|
? [
|
|
@@ -3429,18 +3445,16 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
3429
3445
|
/* The same gate as `prepare`: an unanswered or refused pipeline set encodes nothing at all. */
|
|
3430
3446
|
if (!this.usable) return;
|
|
3431
3447
|
if (this.blitPipeline === null || this.blitGroup === null) return;
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
'to grade it, so the picture will be flat. Use a quality profile with a scene target.',
|
|
3443
|
-
);
|
|
3448
|
+
/* The frame's grade, written when it changes: 0 where the resolve grades. See present.wgsl.ts. */
|
|
3449
|
+
const changed =
|
|
3450
|
+
ctx.outputTransform !== this.gradeWrittenCode ||
|
|
3451
|
+
ctx.outputExposure !== this.gradeWrittenExposure;
|
|
3452
|
+
if (changed && this.device !== null && this.gradeBuffer !== null) {
|
|
3453
|
+
this.gradeWrittenCode = ctx.outputTransform;
|
|
3454
|
+
this.gradeWrittenExposure = ctx.outputExposure;
|
|
3455
|
+
this.gradeInts[0] = ctx.outputTransform;
|
|
3456
|
+
this.gradeFloats[1] = ctx.outputExposure;
|
|
3457
|
+
this.device.queue.writeBuffer(this.gradeBuffer, 0, this.gradeStaging);
|
|
3444
3458
|
}
|
|
3445
3459
|
ctx.pass.setPipeline(this.blitPipeline);
|
|
3446
3460
|
ctx.pass.setBindGroup(0, this.blitGroup);
|
|
@@ -3452,6 +3466,8 @@ export class GpuDrivenPass implements PassDefinition {
|
|
|
3452
3466
|
this.scene.detach();
|
|
3453
3467
|
if (device.backend !== 'webgpu') return;
|
|
3454
3468
|
this.disposeTargets();
|
|
3469
|
+
this.gradeBuffer?.destroy();
|
|
3470
|
+
this.gradeBuffer = null;
|
|
3455
3471
|
this.shadowTexture?.destroy();
|
|
3456
3472
|
this.glassTintTexture?.destroy();
|
|
3457
3473
|
this.glassTintNone?.destroy();
|