@driftengine/core 4.12.0 → 4.13.1
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 +77 -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 +3 -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 +17 -4
- package/dist/render/backend/webgl2/renderer.js +82 -47
- 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 +19 -8
- package/dist/render/backend/webgpu/renderer.js +94 -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/layerLooks.js +11 -19
- package/dist/render/shaders/flat/layered.js +33 -18
- 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.js +23 -23
- 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 +16 -4
- package/dist/render/surfaceLayerLooks.js +33 -14
- package/dist/render/surfaceLayers.d.ts +2 -2
- 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/src/geometry/meshBuilder.ts +21 -2
- package/src/index.ts +11 -2
- package/src/math/color.ts +39 -0
- package/src/render/backend/webgl2/renderer.ts +134 -44
- 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 +104 -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/layerLooks.ts +11 -19
- package/src/render/shaders/flat/layered.ts +33 -18
- 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 +23 -23
- 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 +49 -18
- package/src/render/surfaceLayers.ts +2 -2
- 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
|
@@ -119,7 +119,9 @@ import { FlockRenderer } from '../../flockRenderer.js';
|
|
|
119
119
|
import { TextRenderer } from '../../textRenderer.js';
|
|
120
120
|
import { SdfTextRenderer } from '../../sdfTextRenderer.js';
|
|
121
121
|
import { MOTION_BLUR_MAX_UV, OBJECT_BLUR_UNKEPT, RUSH_REACH_UV, clampMotionShare, } from '../../vertexDefaults.js';
|
|
122
|
-
import { OUTPUT_TRANSFORM_CODE
|
|
122
|
+
import { OUTPUT_TRANSFORM_CODE } from '../../vertexDefaults.js';
|
|
123
|
+
import { gradeColorInto } from '../../gradeColor.js';
|
|
124
|
+
import { interfaceGrade, passGradeCode, passGradeExposure } from '../../passGrade.js';
|
|
123
125
|
import { DEFAULT_FILMIC_CURVE, FILMIC_CLAMPED, FILMIC_CONSTANTS, FILMIC_WITHOUT_COMPOSITE, resolveFilmicCurve, } from '../../filmicCurve.js';
|
|
124
126
|
import { deviceSnappedCellSize } from '../../textLayout.js';
|
|
125
127
|
import { WindStreakRenderer } from '../../windStreakRenderer.js';
|
|
@@ -978,6 +980,8 @@ export class WebGL2Renderer {
|
|
|
978
980
|
warnedOverlayBlocks = false;
|
|
979
981
|
/** Whether a probe is being baked, so the passes that would recurse into one can tell. */
|
|
980
982
|
probePassActive = false;
|
|
983
|
+
/** `clearOf`'s scratch: a clear colour as the open target takes it. */
|
|
984
|
+
gradedClear = [0, 0, 0];
|
|
981
985
|
/**
|
|
982
986
|
* Whether a scene capture is being drawn (`captureScene`): an off-screen pass like a bake, so the
|
|
983
987
|
* frame's own view, its refraction copy and skin's spread are left alone, but lit as the frame is.
|
|
@@ -1691,8 +1695,8 @@ export class WebGL2Renderer {
|
|
|
1691
1695
|
sceneDepth: null,
|
|
1692
1696
|
};
|
|
1693
1697
|
const context = this.passContext;
|
|
1694
|
-
context.outputTransform = this.
|
|
1695
|
-
context.outputExposure = this.
|
|
1698
|
+
context.outputTransform = this.passGrade();
|
|
1699
|
+
context.outputExposure = this.passGradeExposure();
|
|
1696
1700
|
/*
|
|
1697
1701
|
* The copies a pass declared it reads, taken here with everything drawn before it: colour
|
|
1698
1702
|
* afresh at each reading pass, as WebGPU's `takePassColour` does, so a full-screen effect drawn
|
|
@@ -2821,11 +2825,11 @@ export class WebGL2Renderer {
|
|
|
2821
2825
|
finally {
|
|
2822
2826
|
target.end(gl);
|
|
2823
2827
|
gl.frontFace(gl.CCW);
|
|
2828
|
+
this.capturePassActive = false;
|
|
2824
2829
|
this.useFlatProgram();
|
|
2825
|
-
gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.
|
|
2826
|
-
gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.
|
|
2830
|
+
gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.passGrade());
|
|
2831
|
+
gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
2827
2832
|
this.materials.dirty();
|
|
2828
|
-
this.capturePassActive = false;
|
|
2829
2833
|
this.temporalJittering = jittering;
|
|
2830
2834
|
this.restoreViewport();
|
|
2831
2835
|
}
|
|
@@ -4105,7 +4109,7 @@ export class WebGL2Renderer {
|
|
|
4105
4109
|
if (fog !== this.surfaceFog)
|
|
4106
4110
|
gl.uniform1i(u['uFogEnabled'] ?? null, fog);
|
|
4107
4111
|
if (!toneMapped)
|
|
4108
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.
|
|
4112
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.passGrade(), 1));
|
|
4109
4113
|
if (blend) {
|
|
4110
4114
|
gl.enable(gl.BLEND);
|
|
4111
4115
|
if (options.additive === true)
|
|
@@ -4176,7 +4180,7 @@ export class WebGL2Renderer {
|
|
|
4176
4180
|
if (fog !== this.surfaceFog)
|
|
4177
4181
|
gl.uniform1i(u['uFogEnabled'] ?? null, this.surfaceFog);
|
|
4178
4182
|
if (!toneMapped)
|
|
4179
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
4183
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
4180
4184
|
if (own)
|
|
4181
4185
|
this.materials.dirty();
|
|
4182
4186
|
this.useFlatProgram();
|
|
@@ -4328,7 +4332,7 @@ export class WebGL2Renderer {
|
|
|
4328
4332
|
// raining dust into the sea.
|
|
4329
4333
|
const surface = env.underwater?.surfaceY;
|
|
4330
4334
|
const submerged = surface !== undefined && (camera.position[1] ?? 0) < surface;
|
|
4331
|
-
if (streaks.draw(this.gl, this.frameViewFor(camera), wind, timeSeconds, tint, submerged)) {
|
|
4335
|
+
if (streaks.draw(this.gl, this.frameViewFor(camera), wind, timeSeconds, tint, submerged, this.passGrade(), this.passGradeExposure())) {
|
|
4332
4336
|
this.windStreakBudget.ask();
|
|
4333
4337
|
}
|
|
4334
4338
|
}
|
|
@@ -4356,7 +4360,7 @@ export class WebGL2Renderer {
|
|
|
4356
4360
|
*/
|
|
4357
4361
|
drawText(text, viewportWidth, viewportHeight, originX, originY, style, timeSec) {
|
|
4358
4362
|
this.scatterSkin();
|
|
4359
|
-
if (text.draw(viewportWidth, viewportHeight, originX, originY, style, timeSec)) {
|
|
4363
|
+
if (text.draw(viewportWidth, viewportHeight, originX, originY, style, timeSec, interfaceGrade(this.passGrade()), 1)) {
|
|
4360
4364
|
this.textBudget.ask();
|
|
4361
4365
|
}
|
|
4362
4366
|
}
|
|
@@ -4423,7 +4427,9 @@ export class WebGL2Renderer {
|
|
|
4423
4427
|
* real draw call touches the unit in the first place.
|
|
4424
4428
|
*/
|
|
4425
4429
|
/**
|
|
4426
|
-
* The
|
|
4430
|
+
* The grade a pass applies to what it draws into the target open now, and the exposure it
|
|
4431
|
+
* applies it at. The decision is `passGrade.ts`'s, for both backends; this only gathers the
|
|
4432
|
+
* state it is taken from.
|
|
4427
4433
|
*
|
|
4428
4434
|
* **Only where that pass is genuinely the last one to touch the frame.** With a scene target
|
|
4429
4435
|
* the resolve grades, so a pass that graded as well would be applying a curve to its own
|
|
@@ -4431,20 +4437,34 @@ export class WebGL2Renderer {
|
|
|
4431
4437
|
* `screenEffects` off there is no resolve at all and every pass writes straight to the canvas,
|
|
4432
4438
|
* so each one has to grade itself or the frame comes out half converted: linear values in an
|
|
4433
4439
|
* eight-bit buffer read as display values, which is a saturated, clipped version of the colour
|
|
4434
|
-
* the caller asked for rather than a slightly different one.
|
|
4440
|
+
* the caller asked for rather than a slightly different one. A probe's face or a capture is
|
|
4441
|
+
* never graded, and past the present every pass grades itself, composite or not.
|
|
4435
4442
|
*
|
|
4436
4443
|
* One pair of accessors rather than the expression written out at each site, because that is
|
|
4437
4444
|
* how the mesh pass and the particle pass came to disagree in the first place: the mesh pass
|
|
4438
4445
|
* gated, and the particle pass uploaded the transform unconditionally to a stage that did not
|
|
4439
4446
|
* yet declare it.
|
|
4440
4447
|
*/
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4448
|
+
passGrade() {
|
|
4449
|
+
const storing = this.probePassActive || this.capturePassActive;
|
|
4450
|
+
const transform = this.quality.outputTransform;
|
|
4451
|
+
return passGradeCode(storing, this.framePresented, this.resolveGrades(), transform);
|
|
4452
|
+
}
|
|
4453
|
+
passGradeExposure() {
|
|
4454
|
+
const storing = this.probePassActive || this.capturePassActive;
|
|
4455
|
+
return passGradeExposure(storing, this.framePresented, this.resolveGrades(), this.exposure);
|
|
4445
4456
|
}
|
|
4446
|
-
|
|
4447
|
-
|
|
4457
|
+
/** Whether the frame's resolve applies the transform, so the passes before it draw linear. */
|
|
4458
|
+
resolveGrades() {
|
|
4459
|
+
return this.sceneTarget !== null && this.quality.hdrScene;
|
|
4460
|
+
}
|
|
4461
|
+
/**
|
|
4462
|
+
* A clear colour as the target open now takes it: graded as a pass would grade it, so a colour
|
|
4463
|
+
* handed to the renderer is linear wherever it lands — the clear too, which the resolve grades
|
|
4464
|
+
* with everything else under `hdrScene`. See `gradeColor.ts`. Into one scratch, read at once.
|
|
4465
|
+
*/
|
|
4466
|
+
clearOf(color) {
|
|
4467
|
+
return gradeColorInto(this.passGrade(), this.passGradeExposure(), color, this.gradedClear);
|
|
4448
4468
|
}
|
|
4449
4469
|
drawSdfText(handle, model, color, opacity) {
|
|
4450
4470
|
this.scatterSkin();
|
|
@@ -4454,7 +4474,7 @@ export class WebGL2Renderer {
|
|
|
4454
4474
|
if (viewProj === null)
|
|
4455
4475
|
return;
|
|
4456
4476
|
/* Geometry, so the remapped matrix: `frameViewProj` itself stays raw for the motion blur. */
|
|
4457
|
-
if (handle.draw(this.sceneMatrix(viewProj), model, color, opacity, this.
|
|
4477
|
+
if (handle.draw(this.sceneMatrix(viewProj), model, color, opacity, this.passGrade(), this.passGradeExposure())) {
|
|
4458
4478
|
this.sdfTextBudget.ask();
|
|
4459
4479
|
this.restoreSurfaceTextureUnit();
|
|
4460
4480
|
}
|
|
@@ -4468,7 +4488,7 @@ export class WebGL2Renderer {
|
|
|
4468
4488
|
}
|
|
4469
4489
|
drawFlock(flock, camera, timeSeconds, params, tint, windX = 0, windZ = 0) {
|
|
4470
4490
|
this.flockBudget.ask();
|
|
4471
|
-
flock.draw(this.gl, this.frameViewFor(camera), timeSeconds, params, tint, windX, windZ);
|
|
4491
|
+
flock.draw(this.gl, this.frameViewFor(camera), timeSeconds, params, tint, windX, windZ, this.passGrade(), this.passGradeExposure());
|
|
4472
4492
|
}
|
|
4473
4493
|
/**
|
|
4474
4494
|
* Build a scatter batch and fill it. Takes the data rather than handing back
|
|
@@ -4552,8 +4572,8 @@ export class WebGL2Renderer {
|
|
|
4552
4572
|
the uniform at all, so it was a write to a location that did not exist; now that the
|
|
4553
4573
|
stage grades itself it has to obey the same "only where this pass is last" rule the mesh
|
|
4554
4574
|
pass does, or a scene with a composite grades its particles twice. */
|
|
4555
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
4556
|
-
gl.uniform1f(u['uOutputExposure'] ?? null, this.
|
|
4575
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
4576
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
4557
4577
|
gl.uniform3fv(u['uAmbient'] ?? null, env.ambient);
|
|
4558
4578
|
gl.uniform3fv(u['uAmbientGround'] ?? null, env.ambientGround ?? env.ambient);
|
|
4559
4579
|
gl.uniform1i(u['uNoiseOctaves'] ?? null, this.quality.plumeNoiseOctaves);
|
|
@@ -4631,6 +4651,8 @@ export class WebGL2Renderer {
|
|
|
4631
4651
|
gl.uniform3fv(u['uCoreColor'] ?? null, core);
|
|
4632
4652
|
gl.uniform3fv(u['uEdgeColor'] ?? null, edge);
|
|
4633
4653
|
gl.uniform1f(u['uCoreGain'] ?? null, coreGain);
|
|
4654
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
4655
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
4634
4656
|
bindAtmosphere(gl, u, env, this.reflectionPassActive ? this.reflectionAtmosphereY : (camera.position[1] ?? 0), this.quality.underwaterAtmosphere);
|
|
4635
4657
|
batch.drawTo(gl, count);
|
|
4636
4658
|
}
|
|
@@ -4688,8 +4710,8 @@ export class WebGL2Renderer {
|
|
|
4688
4710
|
gl.uniform3fv(u['uColor'] ?? null, color);
|
|
4689
4711
|
gl.uniform1f(u['uOpacity'] ?? null, opacity);
|
|
4690
4712
|
gl.uniform1f(u['uSoftness'] ?? null, softness);
|
|
4691
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
4692
|
-
gl.uniform1f(u['uOutputExposure'] ?? null, this.
|
|
4713
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
4714
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
4693
4715
|
bindAtmosphere(gl, u, env, this.reflectionPassActive ? this.reflectionAtmosphereY : (camera.position[1] ?? 0), this.quality.underwaterAtmosphere);
|
|
4694
4716
|
lines.drawTo(gl, count, additive);
|
|
4695
4717
|
}
|
|
@@ -4722,6 +4744,8 @@ export class WebGL2Renderer {
|
|
|
4722
4744
|
gl.uniform3fv(u['uDirectionalColor'] ?? null, env.directionalColor);
|
|
4723
4745
|
gl.uniform3fv(u['uAmbient'] ?? null, env.ambient);
|
|
4724
4746
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
4747
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
4748
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
4725
4749
|
bindAtmosphere(gl, u, env, this.reflectionPassActive ? this.reflectionAtmosphereY : (camera.position[1] ?? 0), this.quality.underwaterAtmosphere);
|
|
4726
4750
|
// Foliage is thin and seen from both faces; culling it loses half of it.
|
|
4727
4751
|
gl.disable(gl.CULL_FACE);
|
|
@@ -4855,13 +4879,13 @@ export class WebGL2Renderer {
|
|
|
4855
4879
|
// --- Draws that own their context ----------------------------------------
|
|
4856
4880
|
drawPlumes(plumes, camera, timeSeconds, env, windX = 0, windZ = 0, originX = 0, originY = 0, originZ = 0) {
|
|
4857
4881
|
this.scatterSkin();
|
|
4858
|
-
plumes.draw(this.gl, this.frameViewFor(camera), timeSeconds, env, this.quality.underwaterAtmosphere, this.reflectionPassActive ? this.reflectionAtmosphereY : (camera.position[1] ?? 0), this.reflectionPassActive ? (this.planarReflection?.clipPlane ?? null) : null, windX, windZ, originX, originY, originZ);
|
|
4882
|
+
plumes.draw(this.gl, this.frameViewFor(camera), timeSeconds, env, this.quality.underwaterAtmosphere, this.reflectionPassActive ? this.reflectionAtmosphereY : (camera.position[1] ?? 0), this.reflectionPassActive ? (this.planarReflection?.clipPlane ?? null) : null, windX, windZ, originX, originY, originZ, this.passGrade(), this.passGradeExposure());
|
|
4859
4883
|
}
|
|
4860
4884
|
drawWater(water, camera, timeSeconds, settings, env, windX = 0, windZ = 0) {
|
|
4861
4885
|
if (!this.quality.water)
|
|
4862
4886
|
return;
|
|
4863
4887
|
this.waterBudget.ask();
|
|
4864
|
-
water.draw(this.gl, this.frameViewFor(camera), timeSeconds, settings, env.directionalDir, env.directionalColor, env.ambient, env, this.quality.underwaterAtmosphere, this.reflectionReadyThisFrame ? this.planarReflection : null, env, this.quality.pointLightFalloff, windX, windZ);
|
|
4888
|
+
water.draw(this.gl, this.frameViewFor(camera), timeSeconds, settings, env.directionalDir, env.directionalColor, env.ambient, env, this.quality.underwaterAtmosphere, this.reflectionReadyThisFrame ? this.planarReflection : null, env, this.quality.pointLightFalloff, windX, windZ, this.passGrade(), this.passGradeExposure());
|
|
4865
4889
|
}
|
|
4866
4890
|
/**
|
|
4867
4891
|
* Draw after the opaque scene: this is light added to surfaces already shaded,
|
|
@@ -4871,7 +4895,7 @@ export class WebGL2Renderer {
|
|
|
4871
4895
|
this.scatterSkin();
|
|
4872
4896
|
if (caustics === null || !this.quality.water)
|
|
4873
4897
|
return;
|
|
4874
|
-
const drew = caustics.draw(this.gl, this.frameViewFor(camera), timeSeconds, env.directionalDir, env.directionalColor, env.ambient, env, this.quality.underwaterAtmosphere, windX, windZ, strength);
|
|
4898
|
+
const drew = caustics.draw(this.gl, this.frameViewFor(camera), timeSeconds, env.directionalDir, env.directionalColor, env.ambient, env, this.quality.underwaterAtmosphere, windX, windZ, strength, this.passGrade(), this.passGradeExposure());
|
|
4875
4899
|
if (drew)
|
|
4876
4900
|
this.causticsBudget.ask();
|
|
4877
4901
|
}
|
|
@@ -4908,7 +4932,7 @@ export class WebGL2Renderer {
|
|
|
4908
4932
|
return null;
|
|
4909
4933
|
this.reflectionReadyThisFrame = false;
|
|
4910
4934
|
this.reflectionAtmosphereY = source.position[1] ?? 0;
|
|
4911
|
-
const camera = reflection.begin(this.gl, this.canvas.width, this.canvas.height, source, planeY, clearColor);
|
|
4935
|
+
const camera = reflection.begin(this.gl, this.canvas.width, this.canvas.height, source, planeY, this.clearOf(clearColor));
|
|
4912
4936
|
this.gpuTimer.begin('reflection');
|
|
4913
4937
|
this.reflectionPassActive = true;
|
|
4914
4938
|
return camera;
|
|
@@ -6046,7 +6070,8 @@ export class WebGL2Renderer {
|
|
|
6046
6070
|
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
6047
6071
|
}
|
|
6048
6072
|
else {
|
|
6049
|
-
|
|
6073
|
+
const clear = this.clearOf(clearColor);
|
|
6074
|
+
gl.clearColor(clear[0], clear[1], clear[2], 1);
|
|
6050
6075
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
6051
6076
|
}
|
|
6052
6077
|
/*
|
|
@@ -6140,6 +6165,9 @@ export class WebGL2Renderer {
|
|
|
6140
6165
|
gl.uniformMatrix4fv(this.panelUniforms['uClipCorrection'] ?? null, false, IDENTITY_MAT4);
|
|
6141
6166
|
gl.uniform3fv(this.panelUniforms['uColor'] ?? null, color);
|
|
6142
6167
|
gl.uniform1f(this.panelUniforms['uAlpha'] ?? null, alpha);
|
|
6168
|
+
/* An interface: the screen encode, never the curve. See `interfaceGrade`. */
|
|
6169
|
+
gl.uniform1i(this.panelUniforms['uOutputTransform'] ?? null, interfaceGrade(this.passGrade()));
|
|
6170
|
+
gl.uniform1f(this.panelUniforms['uOutputExposure'] ?? null, 1);
|
|
6143
6171
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
6144
6172
|
gl.bindVertexArray(null);
|
|
6145
6173
|
gl.depthMask(true);
|
|
@@ -6822,7 +6850,8 @@ export class WebGL2Renderer {
|
|
|
6822
6850
|
this.sceneTarget?.begin(this.canvas.width, this.canvas.height);
|
|
6823
6851
|
/* The materials' maps on the scene's framebuffer, cleared and disabled: `reflectionKeeps`. */
|
|
6824
6852
|
this.reflectionTargets?.begin(this.canvas.width, this.canvas.height);
|
|
6825
|
-
|
|
6853
|
+
const clear = this.clearOf(clearColor);
|
|
6854
|
+
gl.clearColor(clear[0], clear[1], clear[2], 1);
|
|
6826
6855
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
6827
6856
|
}
|
|
6828
6857
|
/**
|
|
@@ -6957,7 +6986,7 @@ export class WebGL2Renderer {
|
|
|
6957
6986
|
exposure: this.exposure,
|
|
6958
6987
|
film: this.filmConstants,
|
|
6959
6988
|
}
|
|
6960
|
-
: { transform: 0, exposure: 1 };
|
|
6989
|
+
: { transform: 0, exposure: 1, sceneGraded: this.passGrade() !== 0 };
|
|
6961
6990
|
/*
|
|
6962
6991
|
* Depth of field, on the same ceiling-and-dial split as bloom above: `depthOfField` decides
|
|
6963
6992
|
* how far a defocused point may spread and this frame's `setDepthOfField` decides where the
|
|
@@ -7007,7 +7036,7 @@ export class WebGL2Renderer {
|
|
|
7007
7036
|
else if (this.sceneTarget !== null) {
|
|
7008
7037
|
this.decals ??= new DecalPass(this.gl);
|
|
7009
7038
|
this.sceneTarget.bind();
|
|
7010
|
-
this.decals.drawDecals(this.decalQueue, marks, this.frameViewProj, this.frameEye, this.canvas.width, this.canvas.height);
|
|
7039
|
+
this.decals.drawDecals(this.decalQueue, marks, this.frameViewProj, this.frameEye, this.canvas.width, this.canvas.height, this.passGrade());
|
|
7011
7040
|
}
|
|
7012
7041
|
}
|
|
7013
7042
|
/*
|
|
@@ -7159,7 +7188,7 @@ export class WebGL2Renderer {
|
|
|
7159
7188
|
/* The march finished on the default framebuffer, which is not where the frame is being
|
|
7160
7189
|
drawn. See `resolveReflections`, which is the same two-step for the same reason. */
|
|
7161
7190
|
this.sceneTarget.bind();
|
|
7162
|
-
this.medium.compositeMedium(depthCopy, this.canvas.width, this.canvas.height);
|
|
7191
|
+
this.medium.compositeMedium(depthCopy, this.canvas.width, this.canvas.height, this.passGrade(), this.passGradeExposure());
|
|
7163
7192
|
}
|
|
7164
7193
|
}
|
|
7165
7194
|
}
|
|
@@ -7580,12 +7609,11 @@ export class WebGL2Renderer {
|
|
|
7580
7609
|
* exists to keep. With `screenEffects` off there is no resolve at all and the mesh pass
|
|
7581
7610
|
* writes straight to the canvas, so it stays where it always was.
|
|
7582
7611
|
*
|
|
7583
|
-
*
|
|
7584
|
-
*
|
|
7585
|
-
* inconsistency that existed everywhere before this moved.
|
|
7612
|
+
* Every other pass grades through the same gate, `passGrade`, so a frame without a composite
|
|
7613
|
+
* is graded pass by pass to the curve a composite would have applied once.
|
|
7586
7614
|
*/
|
|
7587
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
7588
|
-
gl.uniform1f(u['uOutputExposure'] ?? null, this.
|
|
7615
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
7616
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
7589
7617
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
7590
7618
|
/*
|
|
7591
7619
|
* Solid, every frame, before anything asks otherwise. A GL uniform starts at
|
|
@@ -8038,7 +8066,7 @@ export class WebGL2Renderer {
|
|
|
8038
8066
|
return;
|
|
8039
8067
|
const depth = scene.snapshotDepth(true);
|
|
8040
8068
|
mat4.invert(this.skinInverseProjection, projection);
|
|
8041
|
-
skin.spread(scene, depth, this.emptyTexture2D, projection, this.skinInverseProjection);
|
|
8069
|
+
skin.spread(scene, depth, this.emptyTexture2D, projection, this.skinInverseProjection, this.passGrade(), this.passGradeExposure());
|
|
8042
8070
|
this.useFlatProgram();
|
|
8043
8071
|
}
|
|
8044
8072
|
/** One draw of a mesh, as `drawMesh` describes, of the half of a skin `half` names. */
|
|
@@ -8361,7 +8389,7 @@ export class WebGL2Renderer {
|
|
|
8361
8389
|
means rather than dropping the whole transform. `Math.min` rather than a literal, so a
|
|
8362
8390
|
renderer asked for `none` stays at none and one asked for `srgb` is already there. */
|
|
8363
8391
|
if (!toneMapped)
|
|
8364
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.
|
|
8392
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, Math.min(this.passGrade(), 1));
|
|
8365
8393
|
/* Scoped and handed back like every other state here, so a tinted draw cannot leak its
|
|
8366
8394
|
colour onto the next one. See `TranslucentMeshOptions.tint`. */
|
|
8367
8395
|
const tint = options.tint ?? null;
|
|
@@ -8446,7 +8474,7 @@ export class WebGL2Renderer {
|
|
|
8446
8474
|
if (fog !== this.surfaceFog)
|
|
8447
8475
|
gl.uniform1i(u['uFogEnabled'] ?? null, this.surfaceFog);
|
|
8448
8476
|
if (!toneMapped)
|
|
8449
|
-
gl.uniform1i(u['uOutputTransform'] ?? null, this.
|
|
8477
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
8450
8478
|
if (own)
|
|
8451
8479
|
this.materials.dirty();
|
|
8452
8480
|
}
|
|
@@ -8535,7 +8563,7 @@ export class WebGL2Renderer {
|
|
|
8535
8563
|
/*
|
|
8536
8564
|
* **A probe stores radiance, not display pixels.**
|
|
8537
8565
|
*
|
|
8538
|
-
* `
|
|
8566
|
+
* `passGrade()` is the ACES curve and the sRGB encode whenever the frame has no HDR target,
|
|
8539
8567
|
* so every face was baked through the whole output transform and the shader then sampled the
|
|
8540
8568
|
* result as though it were light. Two things came of that and both read as "the reflection is
|
|
8541
8569
|
* dull": the curve pulls everything bright toward 1 *before* it reaches the cube, so no
|
|
@@ -8585,16 +8613,17 @@ export class WebGL2Renderer {
|
|
|
8585
8613
|
}
|
|
8586
8614
|
finally {
|
|
8587
8615
|
this.gl.frontFace(this.gl.CCW);
|
|
8588
|
-
this.useFlatProgram();
|
|
8589
|
-
this.gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.gradeCode());
|
|
8590
|
-
this.gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.gradeExposure());
|
|
8591
|
-
this.materials.dirty();
|
|
8592
8616
|
/*
|
|
8593
8617
|
* Cleared even if a caller's own draw threw, because leaving this set would keep every
|
|
8594
|
-
* later frame reading the placeholder and quietly reflecting nothing.
|
|
8618
|
+
* later frame reading the placeholder and quietly reflecting nothing. Before the grade is
|
|
8619
|
+
* put back, which asks it.
|
|
8595
8620
|
*/
|
|
8596
8621
|
this.probePassActive = false;
|
|
8597
8622
|
this.probeBounce = false;
|
|
8623
|
+
this.useFlatProgram();
|
|
8624
|
+
this.gl.uniform1i(this.flatUniforms['uOutputTransform'] ?? null, this.passGrade());
|
|
8625
|
+
this.gl.uniform1f(this.flatUniforms['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
8626
|
+
this.materials.dirty();
|
|
8598
8627
|
/* Back to the canvas, or to the frame's own target if one is bound. See `SceneTarget`. */
|
|
8599
8628
|
if (this.sceneTarget !== null && !this.framePresented)
|
|
8600
8629
|
this.sceneTarget.bind();
|
|
@@ -8778,6 +8807,8 @@ export class WebGL2Renderer {
|
|
|
8778
8807
|
gl.uniformMatrix4fv(u['uModel'] ?? null, false, model);
|
|
8779
8808
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
8780
8809
|
gl.uniform1f(u['uStrength'] ?? null, Math.min(shown, 1));
|
|
8810
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
8811
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
8781
8812
|
gl.uniform1f(u['uLength'] ?? null, length);
|
|
8782
8813
|
gl.uniform1f(u['uSpread'] ?? null, spread);
|
|
8783
8814
|
gl.uniform1f(u['uDust'] ?? null, clamp(options.dust ?? 0, 0, 1));
|
|
@@ -8910,6 +8941,8 @@ export class WebGL2Renderer {
|
|
|
8910
8941
|
gl.uniform3fv(u['uCameraPos'] ?? null, camera.position);
|
|
8911
8942
|
gl.uniform1f(u['uTime'] ?? null, timeSeconds);
|
|
8912
8943
|
gl.uniform1f(u['uSheen'] ?? null, sheen);
|
|
8944
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
8945
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
8913
8946
|
gl.uniform1f(u['uFilmRoughness'] ?? null, Math.min(1, Math.max(0, options.roughness ?? 0)));
|
|
8914
8947
|
gl.uniform1f(u['uFilmRoughnessCycles'] ?? null, Math.max(0.01, options.roughnessCyclesPerMetre ?? 60));
|
|
8915
8948
|
gl.uniform1i(u['uClipEnabled'] ?? null, this.reflectionPassActive ? 1 : 0);
|
|
@@ -8953,6 +8986,8 @@ export class WebGL2Renderer {
|
|
|
8953
8986
|
gl.uniform1f(u['uMoonPhase'] ?? null, sky.moonPhase);
|
|
8954
8987
|
gl.uniform1f(u['uNightFactor'] ?? null, sky.nightFactor);
|
|
8955
8988
|
gl.uniform2f(u['uCloudOffset'] ?? null, sky.cloudOffsetX, sky.cloudOffsetZ);
|
|
8989
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, this.passGrade());
|
|
8990
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, this.passGradeExposure());
|
|
8956
8991
|
bindAtmosphere(gl, u, env, this.reflectionPassActive ? this.reflectionAtmosphereY : (camera.position[1] ?? 0), this.quality.underwaterAtmosphere);
|
|
8957
8992
|
gl.bindVertexArray(this.skyVao);
|
|
8958
8993
|
gl.depthMask(false);
|
|
@@ -46,7 +46,9 @@ export declare class GlSkinScatter {
|
|
|
46
46
|
* is the frame's depth as a single-sampled texture, or null where none could be had — and then
|
|
47
47
|
* the diffuse goes back unspread rather than not at all, so the skin keeps its light.
|
|
48
48
|
*/
|
|
49
|
-
spread(scene: SceneTarget, depth: WebGLTexture | null, empty: WebGLTexture, projection: ArrayLike<number>, inverse: ArrayLike<number
|
|
49
|
+
spread(scene: SceneTarget, depth: WebGLTexture | null, empty: WebGLTexture, projection: ArrayLike<number>, inverse: ArrayLike<number>,
|
|
50
|
+
/** The frame's grade, which the second axis applies to the light it adds. */
|
|
51
|
+
outputTransform?: number, outputExposure?: number): void;
|
|
50
52
|
/** Spent at the frame's start: what was drawn into the target was last frame's. */
|
|
51
53
|
reset(): void;
|
|
52
54
|
/** A multisampled target into its single-sampled texture. */
|
|
@@ -123,7 +123,9 @@ export class GlSkinScatter {
|
|
|
123
123
|
* is the frame's depth as a single-sampled texture, or null where none could be had — and then
|
|
124
124
|
* the diffuse goes back unspread rather than not at all, so the skin keeps its light.
|
|
125
125
|
*/
|
|
126
|
-
spread(scene, depth, empty, projection, inverse
|
|
126
|
+
spread(scene, depth, empty, projection, inverse,
|
|
127
|
+
/** The frame's grade, which the second axis applies to the light it adds. */
|
|
128
|
+
outputTransform = 0, outputExposure = 1) {
|
|
127
129
|
const { gl } = this;
|
|
128
130
|
if (this.multisampled !== null) {
|
|
129
131
|
this.resolve(this.drawFramebuffer, this.resolveFramebuffer);
|
|
@@ -139,6 +141,8 @@ export class GlSkinScatter {
|
|
|
139
141
|
gl.uniform1i(u['uSkin'] ?? null, SKIN_BLUR_TEXTURE_UNIT);
|
|
140
142
|
gl.uniform1i(u['uDepth'] ?? null, SKIN_BLUR_DEPTH_UNIT);
|
|
141
143
|
gl.uniform1i(u['uAlbedo'] ?? null, SKIN_BLUR_ALBEDO_UNIT);
|
|
144
|
+
gl.uniform1i(u['uOutputTransform'] ?? null, outputTransform);
|
|
145
|
+
gl.uniform1f(u['uOutputExposure'] ?? null, outputExposure);
|
|
142
146
|
gl.activeTexture(gl.TEXTURE0 + SKIN_BLUR_ALBEDO_UNIT);
|
|
143
147
|
gl.bindTexture(gl.TEXTURE_2D, this.albedo ?? empty);
|
|
144
148
|
/* The four terms that carry a depth back to view-space metres: the occlusion blur's own. */
|
|
@@ -11,7 +11,7 @@ import type { PipelineCache } from './pipelineCache.ts';
|
|
|
11
11
|
export declare const BOLT_VERT_FIELDS: UniformFields;
|
|
12
12
|
export declare const BOLT_VERT_SIZE: 96;
|
|
13
13
|
export declare const BOLT_FRAG_FIELDS: UniformFields;
|
|
14
|
-
export declare const BOLT_FRAG_SIZE:
|
|
14
|
+
export declare const BOLT_FRAG_SIZE: 144;
|
|
15
15
|
/** A batch of arcs on the device, behind the surface's opaque handle. */
|
|
16
16
|
export interface GpuBolts {
|
|
17
17
|
readonly fromBuffer: GPUBuffer;
|
|
@@ -10,7 +10,7 @@ import type { PipelineCache } from './pipelineCache.ts';
|
|
|
10
10
|
export declare const CAUSTICS_VERT_FIELDS: UniformFields;
|
|
11
11
|
export declare const CAUSTICS_VERT_SIZE: 64;
|
|
12
12
|
export declare const CAUSTICS_FRAG_FIELDS: UniformFields;
|
|
13
|
-
export declare const CAUSTICS_FRAG_SIZE:
|
|
13
|
+
export declare const CAUSTICS_FRAG_SIZE: 160;
|
|
14
14
|
/** A lit surface on the device, behind the API's opaque handle. */
|
|
15
15
|
export interface GpuCaustics {
|
|
16
16
|
readonly vertexBuffers: readonly GPUBuffer[];
|
|
@@ -14,7 +14,7 @@ import type { PipelineCache } from './pipelineCache.ts';
|
|
|
14
14
|
export declare const FILM_VERT_FIELDS: UniformFields;
|
|
15
15
|
export declare const FILM_VERT_SIZE: 128;
|
|
16
16
|
export declare const FILM_FRAG_FIELDS: UniformFields;
|
|
17
|
-
export declare const FILM_FRAG_SIZE:
|
|
17
|
+
export declare const FILM_FRAG_SIZE: 160;
|
|
18
18
|
export declare function createFilmBindGroupLayout(device: GPUDevice): GPUBindGroupLayout;
|
|
19
19
|
/** Bound once against both rings; a dynamic offset per film. See `createPanelBindGroup`. */
|
|
20
20
|
export declare function createFilmBindGroup(device: GPUDevice, layout: GPUBindGroupLayout, vertices: GPUBuffer, fragments: GPUBuffer, reflection: GPUTextureView, sampler: GPUSampler): GPUBindGroup;
|
|
@@ -10,7 +10,7 @@ import type { PipelineCache } from './pipelineCache.ts';
|
|
|
10
10
|
export declare const FLOCK_VERT_FIELDS: UniformFields;
|
|
11
11
|
export declare const FLOCK_VERT_SIZE: 112;
|
|
12
12
|
export declare const FLOCK_FRAG_FIELDS: UniformFields;
|
|
13
|
-
export declare const FLOCK_FRAG_SIZE:
|
|
13
|
+
export declare const FLOCK_FRAG_SIZE: 32;
|
|
14
14
|
/** A flock on the device, behind the surface's opaque handle. */
|
|
15
15
|
export interface GpuFlock {
|
|
16
16
|
readonly corners: GPUBuffer;
|
|
@@ -19,7 +19,9 @@ import type { PassContext, PassDefinition, PassDevice, PrepareContext } from '..
|
|
|
19
19
|
* can look at, and looking is what a number cannot replace: if the geometry is in the right places
|
|
20
20
|
* at the right sizes the composition is right, and if a cascade boundary shows as a seam the fade
|
|
21
21
|
* is wrong. Wave 4A's own recorded failure — a phantom surface that passed 111,907 parity samples
|
|
22
|
-
* and was found by looking at a picture — is why this exists at all.
|
|
22
|
+
* and was found by looking at a picture — is why this exists at all. **So it is not graded**, alone
|
|
23
|
+
* of the passes that draw into a frame: what it shows are the field's values, which a curve would
|
|
24
|
+
* bend into a picture of something else.
|
|
23
25
|
*
|
|
24
26
|
* **The field it marches is one frame old**, because the renderer composes at `endFrame` and
|
|
25
27
|
* `prepare` runs at `beginFrame`. `PrepareContext.distanceField` says why that is right rather
|
|
@@ -660,7 +660,16 @@ export declare class GpuDrivenPass implements PassDefinition {
|
|
|
660
660
|
private readonly scheduled;
|
|
661
661
|
private readonly graphScratch;
|
|
662
662
|
private readonly shape;
|
|
663
|
-
|
|
663
|
+
/**
|
|
664
|
+
* The frame's grade for the blit, `PassContext.outputTransform` and its exposure, and the code it
|
|
665
|
+
* was last written with, so a frame writes it only when it changes. See `present.wgsl.ts`.
|
|
666
|
+
*/
|
|
667
|
+
private gradeBuffer;
|
|
668
|
+
private readonly gradeStaging;
|
|
669
|
+
private readonly gradeInts;
|
|
670
|
+
private readonly gradeFloats;
|
|
671
|
+
private gradeWrittenCode;
|
|
672
|
+
private gradeWrittenExposure;
|
|
664
673
|
constructor(scene: StreamingScene, materials: readonly GpuDrivenMaterial[], shadow?: GpuDrivenShadowOptions);
|
|
665
674
|
/** How many clusters the scene holds, which every per-cluster dispatch is sized by. */
|
|
666
675
|
get clusterCount(): number;
|
|
@@ -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.
|