@aura3d/rendering 4.3.7 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DepthPass.d.ts.map +1 -1
- package/dist/DepthPass.js +3 -2
- package/dist/DepthPass.js.map +1 -1
- package/dist/ForwardPass.d.ts +13 -0
- package/dist/ForwardPass.d.ts.map +1 -1
- package/dist/ForwardPass.js +64 -11
- package/dist/ForwardPass.js.map +1 -1
- package/dist/MaterialBinding.js +6 -2
- package/dist/MaterialBinding.js.map +1 -1
- package/dist/Renderer.d.ts +8 -0
- package/dist/Renderer.d.ts.map +1 -1
- package/dist/Renderer.js +37 -6
- package/dist/Renderer.js.map +1 -1
- package/dist/ShaderChunks.d.ts.map +1 -1
- package/dist/ShaderChunks.js +3 -1
- package/dist/ShaderChunks.js.map +1 -1
- package/dist/ShaderLibrary.d.ts.map +1 -1
- package/dist/ShaderLibrary.js +17 -5
- package/dist/ShaderLibrary.js.map +1 -1
- package/dist/ShaderLibraryCore.d.ts.map +1 -1
- package/dist/ShaderLibraryCore.js +2 -1
- package/dist/ShaderLibraryCore.js.map +1 -1
- package/dist/WebGL2Device.d.ts +16 -1
- package/dist/WebGL2Device.d.ts.map +1 -1
- package/dist/WebGL2Device.js +94 -37
- package/dist/WebGL2Device.js.map +1 -1
- package/dist/WebGL2StateCache.d.ts +22 -0
- package/dist/WebGL2StateCache.d.ts.map +1 -1
- package/dist/WebGL2StateCache.js +71 -42
- package/dist/WebGL2StateCache.js.map +1 -1
- package/dist/contracts/core.d.ts.map +1 -1
- package/dist/contracts/core.js +22 -2
- package/dist/contracts/core.js.map +1 -1
- package/dist/contracts/program.d.ts.map +1 -1
- package/dist/contracts/program.js +8 -1
- package/dist/contracts/program.js.map +1 -1
- package/dist/contracts/quality.d.ts +21 -0
- package/dist/contracts/quality.d.ts.map +1 -1
- package/dist/contracts/quality.js +5 -0
- package/dist/contracts/quality.js.map +1 -1
- package/dist/contracts/renderItem.d.ts +6 -0
- package/dist/contracts/renderItem.d.ts.map +1 -1
- package/dist/contracts/structuralMemo.d.ts +23 -0
- package/dist/contracts/structuralMemo.d.ts.map +1 -0
- package/dist/contracts/structuralMemo.js +81 -0
- package/dist/contracts/structuralMemo.js.map +1 -0
- package/dist/environment/EnvironmentCache.d.ts.map +1 -1
- package/dist/environment/EnvironmentCache.js +6 -1
- package/dist/environment/EnvironmentCache.js.map +1 -1
- package/dist/environment/FirstFrameGate.d.ts +23 -0
- package/dist/environment/FirstFrameGate.d.ts.map +1 -0
- package/dist/environment/FirstFrameGate.js +58 -0
- package/dist/environment/FirstFrameGate.js.map +1 -0
- package/dist/environment/Rgb9e5Cube.d.ts.map +1 -1
- package/dist/environment/Rgb9e5Cube.js +8 -4
- package/dist/environment/Rgb9e5Cube.js.map +1 -1
- package/dist/environment/probeBuild.d.ts +29 -0
- package/dist/environment/probeBuild.d.ts.map +1 -1
- package/dist/environment/probeBuild.js +124 -45
- package/dist/environment/probeBuild.js.map +1 -1
- package/dist/forward/Lighting.d.ts +11 -3
- package/dist/forward/Lighting.d.ts.map +1 -1
- package/dist/forward/Lighting.js +25 -15
- package/dist/forward/Lighting.js.map +1 -1
- package/dist/forward/contactShadowMaskStore.d.ts +41 -0
- package/dist/forward/contactShadowMaskStore.d.ts.map +1 -0
- package/dist/forward/contactShadowMaskStore.js +85 -0
- package/dist/forward/contactShadowMaskStore.js.map +1 -0
- package/dist/geometry/Shape.d.ts.map +1 -1
- package/dist/geometry/Shape.js +7 -2
- package/dist/geometry/Shape.js.map +1 -1
- package/dist/geometry/Support.d.ts +4 -0
- package/dist/geometry/Support.d.ts.map +1 -1
- package/dist/geometry/Support.js +3 -2
- package/dist/geometry/Support.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/passes/ContactShadowPass.d.ts +40 -3
- package/dist/passes/ContactShadowPass.d.ts.map +1 -1
- package/dist/passes/ContactShadowPass.js +73 -13
- package/dist/passes/ContactShadowPass.js.map +1 -1
- package/dist/passes/Prd02ContactShadowsContributor.d.ts +19 -0
- package/dist/passes/Prd02ContactShadowsContributor.d.ts.map +1 -1
- package/dist/passes/Prd02ContactShadowsContributor.js +179 -28
- package/dist/passes/Prd02ContactShadowsContributor.js.map +1 -1
- package/dist/program/ProgramFeatures.d.ts +6 -0
- package/dist/program/ProgramFeatures.d.ts.map +1 -1
- package/dist/program/ProgramFeatures.js +11 -5
- package/dist/program/ProgramFeatures.js.map +1 -1
- package/dist/program/ProgramGenerator.d.ts +6 -0
- package/dist/program/ProgramGenerator.d.ts.map +1 -1
- package/dist/program/ProgramGenerator.js +36 -1
- package/dist/program/ProgramGenerator.js.map +1 -1
- package/dist/program/ProgramKey.d.ts.map +1 -1
- package/dist/program/ProgramKey.js +4 -1
- package/dist/program/ProgramKey.js.map +1 -1
- package/dist/program/chunks/shadow_forward.glsl.d.ts +1 -1
- package/dist/program/chunks/shadow_forward.glsl.d.ts.map +1 -1
- package/dist/program/chunks/shadow_forward.glsl.js +4 -1
- package/dist/program/chunks/shadow_forward.glsl.js.map +1 -1
- package/dist/quality/DirectPath.d.ts +43 -0
- package/dist/quality/DirectPath.d.ts.map +1 -0
- package/dist/quality/DirectPath.js +42 -0
- package/dist/quality/DirectPath.js.map +1 -0
- package/dist/renderer/Background.d.ts +0 -5
- package/dist/renderer/Background.d.ts.map +1 -1
- package/dist/renderer/Background.js +25 -2
- package/dist/renderer/Background.js.map +1 -1
- package/dist/renderer/InstanceFrustumCull.d.ts +39 -0
- package/dist/renderer/InstanceFrustumCull.d.ts.map +1 -0
- package/dist/renderer/InstanceFrustumCull.js +127 -0
- package/dist/renderer/InstanceFrustumCull.js.map +1 -0
- package/dist/renderer/ShadowOrchestration.d.ts +2 -0
- package/dist/renderer/ShadowOrchestration.d.ts.map +1 -1
- package/dist/renderer/ShadowOrchestration.js +1 -0
- package/dist/renderer/ShadowOrchestration.js.map +1 -1
- package/dist/renderer/coreOutputPostRoute.d.ts +0 -5
- package/dist/renderer/coreOutputPostRoute.d.ts.map +1 -1
- package/dist/renderer/coreOutputPostRoute.js +12 -2
- package/dist/renderer/coreOutputPostRoute.js.map +1 -1
- package/dist/resources/InstanceBuffer.d.ts +2 -0
- package/dist/resources/InstanceBuffer.d.ts.map +1 -1
- package/dist/resources/InstanceBuffer.js +23 -0
- package/dist/resources/InstanceBuffer.js.map +1 -1
- package/dist/shaders/chunks/contact_shadow.glsl.d.ts +11 -6
- package/dist/shaders/chunks/contact_shadow.glsl.d.ts.map +1 -1
- package/dist/shaders/chunks/contact_shadow.glsl.js +41 -19
- package/dist/shaders/chunks/contact_shadow.glsl.js.map +1 -1
- package/dist/shaders/chunks/contact_shadow_mask.glsl.d.ts +12 -0
- package/dist/shaders/chunks/contact_shadow_mask.glsl.d.ts.map +1 -0
- package/dist/shaders/chunks/contact_shadow_mask.glsl.js +21 -0
- package/dist/shaders/chunks/contact_shadow_mask.glsl.js.map +1 -0
- package/dist/shadows/CascadeUse.d.ts +28 -0
- package/dist/shadows/CascadeUse.d.ts.map +1 -0
- package/dist/shadows/CascadeUse.js +45 -0
- package/dist/shadows/CascadeUse.js.map +1 -0
- package/dist/shadows/Prd02DepthShaderLibrary.d.ts +7 -1
- package/dist/shadows/Prd02DepthShaderLibrary.d.ts.map +1 -1
- package/dist/shadows/Prd02DepthShaderLibrary.js +12 -3
- package/dist/shadows/Prd02DepthShaderLibrary.js.map +1 -1
- package/dist/shadows/Prd02ShadowBridge.d.ts +12 -1
- package/dist/shadows/Prd02ShadowBridge.d.ts.map +1 -1
- package/dist/shadows/Prd02ShadowBridge.js +17 -5
- package/dist/shadows/Prd02ShadowBridge.js.map +1 -1
- package/dist/shadows/ShadowFilterTier.d.ts +51 -0
- package/dist/shadows/ShadowFilterTier.d.ts.map +1 -0
- package/dist/shadows/ShadowFilterTier.js +89 -0
- package/dist/shadows/ShadowFilterTier.js.map +1 -0
- package/dist/shadows/ShadowSystem.d.ts +15 -0
- package/dist/shadows/ShadowSystem.d.ts.map +1 -1
- package/dist/shadows/ShadowSystem.js +12 -2
- package/dist/shadows/ShadowSystem.js.map +1 -1
- package/dist/shadows/shadowLegacy.d.ts +12 -0
- package/dist/shadows/shadowLegacy.d.ts.map +1 -1
- package/dist/shadows/shadowLegacy.js +24 -0
- package/dist/shadows/shadowLegacy.js.map +1 -1
- package/dist/webgl2/BloomFusion.d.ts +31 -0
- package/dist/webgl2/BloomFusion.d.ts.map +1 -0
- package/dist/webgl2/BloomFusion.js +25 -0
- package/dist/webgl2/BloomFusion.js.map +1 -0
- package/dist/webgl2/ContextLifecycle.d.ts +14 -0
- package/dist/webgl2/ContextLifecycle.d.ts.map +1 -1
- package/dist/webgl2/ContextLifecycle.js +30 -3
- package/dist/webgl2/ContextLifecycle.js.map +1 -1
- package/dist/webgl2/LegacyPost.d.ts +30 -0
- package/dist/webgl2/LegacyPost.d.ts.map +1 -1
- package/dist/webgl2/LegacyPost.js +259 -27
- package/dist/webgl2/LegacyPost.js.map +1 -1
- package/dist/webgl2/MultiDraw.d.ts.map +1 -1
- package/dist/webgl2/MultiDraw.js +9 -1
- package/dist/webgl2/MultiDraw.js.map +1 -1
- package/dist/webgl2/Samplers.d.ts +10 -1
- package/dist/webgl2/Samplers.d.ts.map +1 -1
- package/dist/webgl2/Samplers.js +24 -1
- package/dist/webgl2/Samplers.js.map +1 -1
- package/dist/webgl2/TextureFormats.d.ts +12 -0
- package/dist/webgl2/TextureFormats.d.ts.map +1 -1
- package/dist/webgl2/TextureFormats.js +16 -0
- package/dist/webgl2/TextureFormats.js.map +1 -1
- package/package.json +3 -3
|
@@ -5,6 +5,7 @@ import { temporalAccumulationWeight } from "../TemporalMath.js";
|
|
|
5
5
|
import { WebGL2RenderTarget } from "../WebGL2Device.js";
|
|
6
6
|
import { normalizeBloomQualityPreset, resolveBloomPyramidBlurRadii, resolveBloomPyramidPlan, resolveBloomPyramidResponseGain, resolveBloomPyramidV2Response } from "../postprocess/NativeBloomPyramid.js";
|
|
7
7
|
import { BLOOM_BRIGHT_LUT_HEIGHT, BLOOM_BRIGHT_LUT_WIDTH, BLOOM_COMPOSITE_LUT_SIZE, OUTLINE_BLEND_LUT_WIDTH, OUTLINE_LIMB_RADIX, createBloomBrightThresholdLut, createBloomCompositeLut, createOutlineBlendLut, createOutlineGradientBound } from "../postprocess/NativeLdrEffectLuts.js";
|
|
8
|
+
import { BLOOM_FUSED_BLUR_TAP_BUDGET, bloomLevelBlursIn2d } from "./BloomFusion.js";
|
|
8
9
|
// PRD-03 Phase 1 — the r185 FXAA finalize (post/shaders/fxaa.glsl.ts). The
|
|
9
10
|
// split is opt-in via `fxaa: { variant: "r185" }`; the legacy in-shader
|
|
10
11
|
// `u_hasFxaa` taps stay the default path.
|
|
@@ -14,12 +15,24 @@ import { vignetteColorRgb } from "../post/vignetteColor.js";
|
|
|
14
15
|
import { outputPassForDevice } from "../output/OutputPass.js";
|
|
15
16
|
import { TONE_MAP_OPERATOR_FUNCTIONS } from "../output/ToneMappingOperators.glsl.js";
|
|
16
17
|
import { ldrFragmentSource, ldrVariantKey } from "./LdrPostprocessShader.js";
|
|
18
|
+
/** Pass fusion (auto/cinematic): the fused mip sum samples at most this many mips in one pass. */
|
|
19
|
+
export const BLOOM_FUSED_MAX_MIPS = 5;
|
|
20
|
+
export { BLOOM_FUSED_BLUR_TAP_BUDGET };
|
|
21
|
+
/** Texture units the fullscreen presentation snapshot saves and restores: 0..4 (the fused bloom mip sum samples five). */
|
|
22
|
+
export const PRESENTATION_TEXTURE_UNITS = BLOOM_FUSED_MAX_MIPS;
|
|
17
23
|
export class WebGL2LegacyPostPipeline {
|
|
18
24
|
host;
|
|
19
25
|
constructor(host) {
|
|
20
26
|
this.host = host;
|
|
21
27
|
}
|
|
22
28
|
bloomAccumulateProgram = null;
|
|
29
|
+
/** Look-neutral pass fusion (auto/cinematic only): single-pass 2-D Gaussian for small mips, one-pass weighted mip sum, upsample folded into the composite. */
|
|
30
|
+
bloomBlur2dProgram = null;
|
|
31
|
+
bloomFusedAccumulateProgram = null;
|
|
32
|
+
bloomFusedCompositeProgram = null;
|
|
33
|
+
bloomPrefilterDownsampleProgram = null;
|
|
34
|
+
/** True when the last `executeNativeBloomPyramidPasses` returned the level-0 accumulator (not a full-resolution copy). */
|
|
35
|
+
lastPyramidFused = false;
|
|
23
36
|
bloomBlurProgram = null;
|
|
24
37
|
bloomBrightExtractProgram = null;
|
|
25
38
|
bloomBrightLutTexture = null;
|
|
@@ -211,17 +224,19 @@ export class WebGL2LegacyPostPipeline {
|
|
|
211
224
|
// source through the proven single-scale composite program.
|
|
212
225
|
this.host.gl.bindFramebuffer(this.host.gl.FRAMEBUFFER, bloomResources.framebuffers[1]);
|
|
213
226
|
this.host.gl.viewport(0, 0, source.width, source.height);
|
|
214
|
-
const pyramidComposite = this.ensureBloomCompositeProgram();
|
|
227
|
+
const pyramidComposite = this.lastPyramidFused ? this.ensureBloomFusedCompositeProgram() : this.ensureBloomCompositeProgram();
|
|
215
228
|
this.host.gl.useProgram(pyramidComposite);
|
|
216
229
|
this.host.gl.bindVertexArray(vertexArray);
|
|
217
230
|
this.bindFullscreenTexture(0, ldrSourceHandle);
|
|
218
231
|
this.bindFullscreenTexture(1, pyramidResult);
|
|
219
|
-
if (this.bloomCompositeLutTexture)
|
|
232
|
+
if (this.bloomCompositeLutTexture && !this.lastPyramidFused)
|
|
220
233
|
this.bindFullscreenTexture(2, this.bloomCompositeLutTexture);
|
|
221
234
|
this.host.gl.uniform1i(this.host.gl.getUniformLocation(pyramidComposite, "u_source"), 0);
|
|
222
235
|
this.host.gl.uniform1i(this.host.gl.getUniformLocation(pyramidComposite, "u_blurred"), 1);
|
|
223
|
-
|
|
224
|
-
|
|
236
|
+
if (!this.lastPyramidFused) {
|
|
237
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(pyramidComposite, "u_compositeLut"), 2);
|
|
238
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(pyramidComposite, "u_hdr"), sourceIsHdr ? 1 : 0);
|
|
239
|
+
}
|
|
225
240
|
this.host.gl.uniform1f(this.host.gl.getUniformLocation(pyramidComposite, "u_intensity"), bloomOptions.intensity * nativeBloomResponseGain(plan, bloomOptions));
|
|
226
241
|
this.host.gl.drawArrays(this.host.gl.TRIANGLES, 0, 3);
|
|
227
242
|
ldrSourceHandle = bloomResources.textures[1];
|
|
@@ -343,17 +358,19 @@ export class WebGL2LegacyPostPipeline {
|
|
|
343
358
|
}, bloomOptions, vertexArray, true);
|
|
344
359
|
this.host.gl.bindFramebuffer(this.host.gl.FRAMEBUFFER, destination.framebuffer);
|
|
345
360
|
this.host.gl.viewport(0, 0, source.width, source.height);
|
|
346
|
-
const composite = this.ensureBloomCompositeProgram();
|
|
361
|
+
const composite = this.lastPyramidFused ? this.ensureBloomFusedCompositeProgram() : this.ensureBloomCompositeProgram();
|
|
347
362
|
this.host.gl.useProgram(composite);
|
|
348
363
|
this.host.gl.bindVertexArray(vertexArray);
|
|
349
364
|
this.bindFullscreenTexture(0, source.colorHandle);
|
|
350
365
|
this.bindFullscreenTexture(1, pyramidResult);
|
|
351
|
-
if (this.bloomCompositeLutTexture)
|
|
366
|
+
if (this.bloomCompositeLutTexture && !this.lastPyramidFused)
|
|
352
367
|
this.bindFullscreenTexture(2, this.bloomCompositeLutTexture);
|
|
353
368
|
this.host.gl.uniform1i(this.host.gl.getUniformLocation(composite, "u_source"), 0);
|
|
354
369
|
this.host.gl.uniform1i(this.host.gl.getUniformLocation(composite, "u_blurred"), 1);
|
|
355
|
-
|
|
356
|
-
|
|
370
|
+
if (!this.lastPyramidFused) {
|
|
371
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(composite, "u_compositeLut"), 2);
|
|
372
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(composite, "u_hdr"), 1);
|
|
373
|
+
}
|
|
357
374
|
this.host.gl.uniform1f(this.host.gl.getUniformLocation(composite, "u_intensity"), bloomOptions.intensity * nativeBloomResponseGain(plan, bloomOptions));
|
|
358
375
|
this.host.gl.drawArrays(this.host.gl.TRIANGLES, 0, 3);
|
|
359
376
|
this.recordBloomDiagnostics(bloomOptions, source.width, source.height, true, plan.mipCount);
|
|
@@ -669,8 +686,16 @@ export class WebGL2LegacyPostPipeline {
|
|
|
669
686
|
const mipTexture = (level, slot) => resources.textures[level * 2 + slot];
|
|
670
687
|
const mipFramebuffer = (level, slot) => resources.framebuffers[level * 2 + slot];
|
|
671
688
|
const mipSize = (level) => plan.mips[level];
|
|
672
|
-
//
|
|
673
|
-
|
|
689
|
+
// Pass fusion (hdr-msaa path under quality auto/cinematic; `production` never sets the device flag): small mips blur in one
|
|
690
|
+
// 2-D pass, the mip sum is one pass, and the final full-resolution upsample is folded into the composite.
|
|
691
|
+
const fused = hdr && this.host.device.bloomFusedPasses === true && mipCount <= BLOOM_FUSED_MAX_MIPS;
|
|
692
|
+
const fusion = this.host.device.bloomFusion;
|
|
693
|
+
const fuseAccumulate = fused && fusion.accumulate;
|
|
694
|
+
this.lastPyramidFused = fuseAccumulate;
|
|
695
|
+
// Every level settles in slot 0 after the two-pass vertical blur; a single-pass 2-D blur settles in slot 1.
|
|
696
|
+
const settledSlot = [];
|
|
697
|
+
const blurredSlot = (level) => settledSlot[level] ?? 0;
|
|
698
|
+
const blur2dProgram = fused && fusion.blur2dFromLevel < mipCount ? this.ensureBloomBlur2dProgram() : null;
|
|
674
699
|
const drawDownsample = (fromTexture, fromWidth, fromHeight, toFramebuffer, toWidth, toHeight) => {
|
|
675
700
|
this.host.gl.bindFramebuffer(this.host.gl.FRAMEBUFFER, toFramebuffer);
|
|
676
701
|
this.host.gl.viewport(0, 0, toWidth, toHeight);
|
|
@@ -716,35 +741,95 @@ export class WebGL2LegacyPostPipeline {
|
|
|
716
741
|
this.host.gl.uniform1i(this.host.gl.getUniformLocation(blurProgram, "u_horizontal"), 0);
|
|
717
742
|
this.host.gl.drawArrays(this.host.gl.TRIANGLES, 0, 3);
|
|
718
743
|
};
|
|
744
|
+
// Blur one mip that was just downsampled into slot 0. Two passes (H into slot 1, V back into slot 0) normally; a single
|
|
745
|
+
// 2-D pass (slot 0 into slot 1) when fusion is on and the tap count stays under the budget.
|
|
746
|
+
const blurLevel = (level, size, radius) => {
|
|
747
|
+
if (blur2dProgram && bloomLevelBlursIn2d(fusion, level, size, radius)) {
|
|
748
|
+
this.host.gl.bindFramebuffer(this.host.gl.FRAMEBUFFER, mipFramebuffer(level, 1));
|
|
749
|
+
this.host.gl.viewport(0, 0, size.width, size.height);
|
|
750
|
+
this.host.gl.useProgram(blur2dProgram);
|
|
751
|
+
this.host.gl.bindVertexArray(vertexArray);
|
|
752
|
+
this.bindFullscreenTexture(0, mipTexture(level, 0));
|
|
753
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(blur2dProgram, "u_source"), 0);
|
|
754
|
+
this.host.gl.uniform2i(this.host.gl.getUniformLocation(blur2dProgram, "u_size"), size.width, size.height);
|
|
755
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(blur2dProgram, "u_radius"), radius);
|
|
756
|
+
this.host.gl.drawArrays(this.host.gl.TRIANGLES, 0, 3);
|
|
757
|
+
settledSlot[level] = 1;
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
drawSeparableBlur(mipTexture(level, 0), mipTexture(level, 1), mipFramebuffer(level, 1), mipFramebuffer(level, 0), size, radius);
|
|
761
|
+
settledSlot[level] = 0;
|
|
762
|
+
};
|
|
719
763
|
// Extract highlights at the source resolution before the first downsample.
|
|
720
764
|
// Downsampling the complete scene first averaged narrow emissive sources
|
|
721
765
|
// below the authored threshold, so balanced/cinematic bloom could execute
|
|
722
766
|
// all native passes yet remain pixel-identical to disabled output.
|
|
723
|
-
this.host.gl.bindFramebuffer(this.host.gl.FRAMEBUFFER, fullResStaging.framebufferA);
|
|
724
|
-
this.host.gl.viewport(0, 0, sourceWidth, sourceHeight);
|
|
725
|
-
this.host.gl.useProgram(brightProgram);
|
|
726
|
-
this.host.gl.bindVertexArray(vertexArray);
|
|
727
|
-
this.bindFullscreenTexture(0, sourceTexture);
|
|
728
|
-
if (brightLut)
|
|
729
|
-
this.bindFullscreenTexture(1, brightLut);
|
|
730
|
-
this.host.gl.uniform1i(this.host.gl.getUniformLocation(brightProgram, "u_source"), 0);
|
|
731
|
-
this.host.gl.uniform1i(this.host.gl.getUniformLocation(brightProgram, "u_brightLut"), 1);
|
|
732
|
-
this.host.gl.uniform1i(this.host.gl.getUniformLocation(brightProgram, "u_hdr"), hdr ? 1 : 0);
|
|
733
|
-
this.host.gl.uniform1f(this.host.gl.getUniformLocation(brightProgram, "u_threshold"), options.threshold);
|
|
734
|
-
this.host.gl.uniform1f(this.host.gl.getUniformLocation(brightProgram, "u_softKnee"), options.softKnee);
|
|
735
|
-
this.host.gl.uniform1i(this.host.gl.getUniformLocation(brightProgram, "u_excess"), options.excess === true ? 1 : 0);
|
|
736
|
-
this.host.gl.drawArrays(this.host.gl.TRIANGLES, 0, 3);
|
|
737
767
|
// Level 0 downsamples the extracted highlight field, then blurs H into
|
|
738
768
|
// slot 1 and V back into slot 0. The result therefore settles in slot 0.
|
|
739
769
|
const level0 = mipSize(0);
|
|
740
|
-
|
|
741
|
-
|
|
770
|
+
// Extract + level-0 downsample in one pass when the source is exactly 2:1: each destination texel averages the four
|
|
771
|
+
// source texels the unfused box downsample reads (its taps land on texel centres), extracting each first, so the
|
|
772
|
+
// result matches the two-pass chain without the full-resolution extract target or its pass.
|
|
773
|
+
const extractFolded = fused && fusion.extract && level0.width * 2 === sourceWidth && level0.height * 2 === sourceHeight;
|
|
774
|
+
if (extractFolded) {
|
|
775
|
+
const prefilter = this.ensureBloomPrefilterDownsampleProgram();
|
|
776
|
+
this.host.gl.bindFramebuffer(this.host.gl.FRAMEBUFFER, mipFramebuffer(0, 0));
|
|
777
|
+
this.host.gl.viewport(0, 0, level0.width, level0.height);
|
|
778
|
+
this.host.gl.useProgram(prefilter);
|
|
779
|
+
this.host.gl.bindVertexArray(vertexArray);
|
|
780
|
+
this.bindFullscreenTexture(0, sourceTexture);
|
|
781
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(prefilter, "u_source"), 0);
|
|
782
|
+
this.host.gl.uniform1f(this.host.gl.getUniformLocation(prefilter, "u_threshold"), options.threshold);
|
|
783
|
+
this.host.gl.uniform1f(this.host.gl.getUniformLocation(prefilter, "u_softKnee"), options.softKnee);
|
|
784
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(prefilter, "u_excess"), options.excess === true ? 1 : 0);
|
|
785
|
+
this.host.gl.drawArrays(this.host.gl.TRIANGLES, 0, 3);
|
|
786
|
+
}
|
|
787
|
+
else {
|
|
788
|
+
this.host.gl.bindFramebuffer(this.host.gl.FRAMEBUFFER, fullResStaging.framebufferA);
|
|
789
|
+
this.host.gl.viewport(0, 0, sourceWidth, sourceHeight);
|
|
790
|
+
this.host.gl.useProgram(brightProgram);
|
|
791
|
+
this.host.gl.bindVertexArray(vertexArray);
|
|
792
|
+
this.bindFullscreenTexture(0, sourceTexture);
|
|
793
|
+
if (brightLut)
|
|
794
|
+
this.bindFullscreenTexture(1, brightLut);
|
|
795
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(brightProgram, "u_source"), 0);
|
|
796
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(brightProgram, "u_brightLut"), 1);
|
|
797
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(brightProgram, "u_hdr"), hdr ? 1 : 0);
|
|
798
|
+
this.host.gl.uniform1f(this.host.gl.getUniformLocation(brightProgram, "u_threshold"), options.threshold);
|
|
799
|
+
this.host.gl.uniform1f(this.host.gl.getUniformLocation(brightProgram, "u_softKnee"), options.softKnee);
|
|
800
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(brightProgram, "u_excess"), options.excess === true ? 1 : 0);
|
|
801
|
+
this.host.gl.drawArrays(this.host.gl.TRIANGLES, 0, 3);
|
|
802
|
+
drawDownsample(fullResStaging.textureA, sourceWidth, sourceHeight, mipFramebuffer(0, 0), level0.width, level0.height);
|
|
803
|
+
}
|
|
804
|
+
blurLevel(0, level0, blurRadii[0]);
|
|
742
805
|
for (let level = 1; level < mipCount; level += 1) {
|
|
743
806
|
const size = mipSize(level);
|
|
744
807
|
const previous = mipSize(level - 1);
|
|
745
808
|
drawDownsample(mipTexture(level - 1, blurredSlot(level - 1)), previous.width, previous.height, mipFramebuffer(level, 0), size.width, size.height);
|
|
746
809
|
// H into slot 1, V back into slot 0: blurred result settles in slot 0.
|
|
747
|
-
|
|
810
|
+
blurLevel(level, size, blurRadii[level]);
|
|
811
|
+
}
|
|
812
|
+
if (fuseAccumulate) {
|
|
813
|
+
// Weighted mip sum in one pass (smallest to largest, as the sequential passes accumulate), left at level-0 size.
|
|
814
|
+
const fusedWeights = v2Response ? v2Response.weights : plan.weights;
|
|
815
|
+
const fusedProgram = this.ensureBloomFusedAccumulateProgram();
|
|
816
|
+
this.host.gl.bindFramebuffer(this.host.gl.FRAMEBUFFER, resources.accumulatorFramebufferA);
|
|
817
|
+
this.host.gl.viewport(0, 0, level0.width, level0.height);
|
|
818
|
+
this.host.gl.useProgram(fusedProgram);
|
|
819
|
+
this.host.gl.bindVertexArray(vertexArray);
|
|
820
|
+
const weightValues = new Float32Array(5);
|
|
821
|
+
for (let level = 0; level < 5; level += 1) {
|
|
822
|
+
// Unused samplers still need a valid texture; bind mip 0 so no unit is left pointing at the target.
|
|
823
|
+
const bound = level < mipCount ? level : 0;
|
|
824
|
+
this.bindFullscreenTexture(level, mipTexture(bound, blurredSlot(bound)));
|
|
825
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(fusedProgram, `u_mip${level}`), level);
|
|
826
|
+
weightValues[level] = level < mipCount ? fusedWeights[level] : 0;
|
|
827
|
+
}
|
|
828
|
+
this.host.gl.uniform1fv(this.host.gl.getUniformLocation(fusedProgram, "u_weights"), weightValues);
|
|
829
|
+
this.host.gl.uniform1i(this.host.gl.getUniformLocation(fusedProgram, "u_count"), mipCount);
|
|
830
|
+
this.host.gl.uniform2f(this.host.gl.getUniformLocation(fusedProgram, "u_targetSize"), level0.width, level0.height);
|
|
831
|
+
this.host.gl.drawArrays(this.host.gl.TRIANGLES, 0, 3);
|
|
832
|
+
return resources.accumulatorTextureA;
|
|
748
833
|
}
|
|
749
834
|
// Accumulate smallest-to-largest, ping-ponging between the two
|
|
750
835
|
// accumulators (a pass must never sample its own bound target).
|
|
@@ -1187,6 +1272,10 @@ export class WebGL2LegacyPostPipeline {
|
|
|
1187
1272
|
const textureUnit0 = this.host.lifecycle.captureTextureUnit0();
|
|
1188
1273
|
const textureUnit1 = this.host.lifecycle.captureTextureUnitBinding(1);
|
|
1189
1274
|
const textureUnit2 = this.host.lifecycle.captureTextureUnitBinding(2);
|
|
1275
|
+
const extraTextureUnits = [];
|
|
1276
|
+
for (let unit = 3; unit < PRESENTATION_TEXTURE_UNITS; unit += 1) {
|
|
1277
|
+
extraTextureUnits.push({ unit, binding: this.host.lifecycle.captureTextureUnitBinding(unit) });
|
|
1278
|
+
}
|
|
1190
1279
|
this.host.gl.activeTexture(textureUnit0.activeTexture);
|
|
1191
1280
|
const snapshot = {
|
|
1192
1281
|
framebuffer: this.host.gl.getParameter(this.host.gl.FRAMEBUFFER_BINDING),
|
|
@@ -1194,6 +1283,7 @@ export class WebGL2LegacyPostPipeline {
|
|
|
1194
1283
|
textureUnit0,
|
|
1195
1284
|
textureUnit1,
|
|
1196
1285
|
textureUnit2,
|
|
1286
|
+
extraTextureUnits,
|
|
1197
1287
|
vertexArray: this.host.gl.getParameter(this.host.gl.VERTEX_ARRAY_BINDING),
|
|
1198
1288
|
viewport: this.host.gl.getParameter(this.host.gl.VIEWPORT),
|
|
1199
1289
|
colorMask: this.host.gl.getParameter(this.host.gl.COLOR_WRITEMASK),
|
|
@@ -1218,6 +1308,10 @@ export class WebGL2LegacyPostPipeline {
|
|
|
1218
1308
|
}
|
|
1219
1309
|
restoreFullscreenPresentationState(snapshot, fallbackWidth, fallbackHeight) {
|
|
1220
1310
|
this.host.gl.bindVertexArray(snapshot.vertexArray);
|
|
1311
|
+
for (let index = snapshot.extraTextureUnits.length - 1; index >= 0; index -= 1) {
|
|
1312
|
+
const extra = snapshot.extraTextureUnits[index];
|
|
1313
|
+
this.host.lifecycle.restoreTextureUnitBinding(extra.unit, extra.binding);
|
|
1314
|
+
}
|
|
1221
1315
|
this.host.lifecycle.restoreTextureUnitBinding(2, snapshot.textureUnit2);
|
|
1222
1316
|
this.host.lifecycle.restoreTextureUnitBinding(1, snapshot.textureUnit1);
|
|
1223
1317
|
this.host.lifecycle.restoreTextureUnit0(snapshot.textureUnit0);
|
|
@@ -1417,6 +1511,144 @@ void main() {
|
|
|
1417
1511
|
`, "webgl2-bloom-downsample");
|
|
1418
1512
|
return this.bloomDownsampleProgram;
|
|
1419
1513
|
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Single-pass 2-D Gaussian: the product of the two normalised 1-D kernels the separable blur applies, with the same
|
|
1516
|
+
* per-axis edge clamp, so it equals horizontal-then-vertical (up to the half-float round trip the two-pass version
|
|
1517
|
+
* stores between passes). Used only for mips small enough that (2r+1)^2 taps cost less than a draw.
|
|
1518
|
+
*/
|
|
1519
|
+
ensureBloomBlur2dProgram() {
|
|
1520
|
+
if (this.bloomBlur2dProgram)
|
|
1521
|
+
return this.bloomBlur2dProgram;
|
|
1522
|
+
this.bloomBlur2dProgram = this.createFullscreenProgram(`#version 300 es
|
|
1523
|
+
precision highp float;
|
|
1524
|
+
precision highp int;
|
|
1525
|
+
uniform sampler2D u_source;
|
|
1526
|
+
uniform ivec2 u_size;
|
|
1527
|
+
uniform int u_radius;
|
|
1528
|
+
out vec4 outColor;
|
|
1529
|
+
|
|
1530
|
+
vec4 sourcePixel(ivec2 coordinate) {
|
|
1531
|
+
return texelFetch(u_source, clamp(coordinate, ivec2(0), u_size - ivec2(1)), 0);
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
void main() {
|
|
1535
|
+
ivec2 pixel = ivec2(gl_FragCoord.xy);
|
|
1536
|
+
float sigma = max(float(u_radius) / 3.0, 0.5);
|
|
1537
|
+
float coefficient = 0.39894 / sigma;
|
|
1538
|
+
// One-dimensional weights, identical to the separable pass.
|
|
1539
|
+
float kernel[25];
|
|
1540
|
+
float weightSum = coefficient;
|
|
1541
|
+
kernel[0] = coefficient;
|
|
1542
|
+
for (int offset = 1; offset <= 24; offset += 1) {
|
|
1543
|
+
float distance = float(offset);
|
|
1544
|
+
float weight = coefficient * exp(-0.5 * distance * distance / (sigma * sigma));
|
|
1545
|
+
kernel[offset] = offset > u_radius ? 0.0 : weight;
|
|
1546
|
+
if (offset <= u_radius) weightSum += 2.0 * weight;
|
|
1547
|
+
}
|
|
1548
|
+
weightSum = max(weightSum, 0.000001);
|
|
1549
|
+
vec4 sum = vec4(0.0);
|
|
1550
|
+
for (int dy = -24; dy <= 24; dy += 1) {
|
|
1551
|
+
int ay = abs(dy);
|
|
1552
|
+
if (ay > u_radius) continue;
|
|
1553
|
+
float wy = kernel[ay];
|
|
1554
|
+
for (int dx = -24; dx <= 24; dx += 1) {
|
|
1555
|
+
int ax = abs(dx);
|
|
1556
|
+
if (ax > u_radius) continue;
|
|
1557
|
+
sum += sourcePixel(pixel + ivec2(dx, dy)) * (kernel[ax] * wy);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
outColor = sum / (weightSum * weightSum);
|
|
1561
|
+
}
|
|
1562
|
+
`, "webgl2-bloom-blur-2d");
|
|
1563
|
+
return this.bloomBlur2dProgram;
|
|
1564
|
+
}
|
|
1565
|
+
/** Weighted sum of up to five blurred mips, bilinearly upsampled to level-0 size, in one pass (smallest mip first, like the sequential accumulate). */
|
|
1566
|
+
ensureBloomFusedAccumulateProgram() {
|
|
1567
|
+
if (this.bloomFusedAccumulateProgram)
|
|
1568
|
+
return this.bloomFusedAccumulateProgram;
|
|
1569
|
+
this.bloomFusedAccumulateProgram = this.createFullscreenProgram(`#version 300 es
|
|
1570
|
+
precision highp float;
|
|
1571
|
+
uniform sampler2D u_mip0;
|
|
1572
|
+
uniform sampler2D u_mip1;
|
|
1573
|
+
uniform sampler2D u_mip2;
|
|
1574
|
+
uniform sampler2D u_mip3;
|
|
1575
|
+
uniform sampler2D u_mip4;
|
|
1576
|
+
uniform float u_weights[5];
|
|
1577
|
+
uniform int u_count;
|
|
1578
|
+
uniform vec2 u_targetSize;
|
|
1579
|
+
out vec4 outColor;
|
|
1580
|
+
void main() {
|
|
1581
|
+
vec2 uv = gl_FragCoord.xy / u_targetSize;
|
|
1582
|
+
vec3 sum = vec3(0.0);
|
|
1583
|
+
if (u_count > 4) sum += texture(u_mip4, uv).rgb * u_weights[4];
|
|
1584
|
+
if (u_count > 3) sum += texture(u_mip3, uv).rgb * u_weights[3];
|
|
1585
|
+
if (u_count > 2) sum += texture(u_mip2, uv).rgb * u_weights[2];
|
|
1586
|
+
if (u_count > 1) sum += texture(u_mip1, uv).rgb * u_weights[1];
|
|
1587
|
+
sum += texture(u_mip0, uv).rgb * u_weights[0];
|
|
1588
|
+
outColor = vec4(sum, 0.0);
|
|
1589
|
+
}
|
|
1590
|
+
`, "webgl2-bloom-fused-accumulate");
|
|
1591
|
+
return this.bloomFusedAccumulateProgram;
|
|
1592
|
+
}
|
|
1593
|
+
/** HDR bloom composite that upsamples the level-0 accumulator itself (bilinear at the pixel centre) instead of reading a full-resolution copy. */
|
|
1594
|
+
ensureBloomFusedCompositeProgram() {
|
|
1595
|
+
if (this.bloomFusedCompositeProgram)
|
|
1596
|
+
return this.bloomFusedCompositeProgram;
|
|
1597
|
+
this.bloomFusedCompositeProgram = this.createFullscreenProgram(`#version 300 es
|
|
1598
|
+
precision highp float;
|
|
1599
|
+
precision highp int;
|
|
1600
|
+
uniform sampler2D u_source;
|
|
1601
|
+
uniform sampler2D u_blurred;
|
|
1602
|
+
uniform float u_intensity;
|
|
1603
|
+
out vec4 outColor;
|
|
1604
|
+
void main() {
|
|
1605
|
+
ivec2 pixel = ivec2(gl_FragCoord.xy);
|
|
1606
|
+
vec4 source = texelFetch(u_source, pixel, 0);
|
|
1607
|
+
vec3 blurred = texture(u_blurred, gl_FragCoord.xy / vec2(textureSize(u_source, 0))).rgb;
|
|
1608
|
+
outColor = vec4(source.rgb + blurred * u_intensity, source.a);
|
|
1609
|
+
}
|
|
1610
|
+
`, "webgl2-bloom-fused-composite");
|
|
1611
|
+
return this.bloomFusedCompositeProgram;
|
|
1612
|
+
}
|
|
1613
|
+
/** Bright extract (HDR) + level-0 box downsample in one pass over an exactly 2:1 source; see `executeNativeBloomPyramidPasses`. */
|
|
1614
|
+
ensureBloomPrefilterDownsampleProgram() {
|
|
1615
|
+
if (this.bloomPrefilterDownsampleProgram)
|
|
1616
|
+
return this.bloomPrefilterDownsampleProgram;
|
|
1617
|
+
this.bloomPrefilterDownsampleProgram = this.createFullscreenProgram(`#version 300 es
|
|
1618
|
+
precision highp float;
|
|
1619
|
+
precision highp int;
|
|
1620
|
+
uniform sampler2D u_source;
|
|
1621
|
+
uniform float u_threshold;
|
|
1622
|
+
uniform float u_softKnee;
|
|
1623
|
+
uniform int u_excess;
|
|
1624
|
+
out vec4 outColor;
|
|
1625
|
+
vec4 a3dFinite(vec4 c) { return (any(isnan(c)) || any(isinf(c))) ? vec4(0.0) : c; }
|
|
1626
|
+
vec4 extractTexel(ivec2 pixel) {
|
|
1627
|
+
vec4 source = texelFetch(u_source, pixel, 0);
|
|
1628
|
+
float luma = dot(source.rgb, vec3(0.2126, 0.7152, 0.0722));
|
|
1629
|
+
if (u_excess == 1) {
|
|
1630
|
+
float knee = max(u_softKnee, 0.0);
|
|
1631
|
+
float soft = clamp(luma - u_threshold + knee, 0.0, 2.0 * knee);
|
|
1632
|
+
soft = soft * soft / (4.0 * knee + 1e-5);
|
|
1633
|
+
float excessWeight = max(soft, luma - u_threshold) / max(luma, 1e-5);
|
|
1634
|
+
return vec4(source.rgb * excessWeight, source.a);
|
|
1635
|
+
}
|
|
1636
|
+
float kneeLow = max(u_threshold - u_softKnee, 0.0);
|
|
1637
|
+
float kneeHigh = min(u_threshold + u_softKnee, 1.0);
|
|
1638
|
+
float weight = u_softKnee <= 0.0
|
|
1639
|
+
? (luma >= u_threshold ? 1.0 : 0.0)
|
|
1640
|
+
: smoothstep(kneeLow, kneeHigh, luma);
|
|
1641
|
+
return source * weight;
|
|
1642
|
+
}
|
|
1643
|
+
void main() {
|
|
1644
|
+
ivec2 base = ivec2(gl_FragCoord.xy) * 2;
|
|
1645
|
+
vec4 sum = a3dFinite(extractTexel(base)) + a3dFinite(extractTexel(base + ivec2(1, 0)))
|
|
1646
|
+
+ a3dFinite(extractTexel(base + ivec2(0, 1))) + a3dFinite(extractTexel(base + ivec2(1, 1)));
|
|
1647
|
+
outColor = sum * 0.25;
|
|
1648
|
+
}
|
|
1649
|
+
`, "webgl2-bloom-prefilter-downsample");
|
|
1650
|
+
return this.bloomPrefilterDownsampleProgram;
|
|
1651
|
+
}
|
|
1420
1652
|
ensureBloomAccumulateProgram() {
|
|
1421
1653
|
if (this.bloomAccumulateProgram)
|
|
1422
1654
|
return this.bloomAccumulateProgram;
|