@zephyr3d/scene 0.9.21 → 0.9.22

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssgi.js","sources":["../../src/posteffect/ssgi.ts"],"sourcesContent":["import { AbstractPostEffect, PostEffectLayer } from './posteffect';\nimport type { PostEffectSetupContext } from './posteffect';\nimport { linearToGamma } from '../shaders/misc';\nimport type { BindGroup, FrameBuffer, GPUProgram, Texture2D } from '@zephyr3d/device';\nimport type { DrawContext } from '../render';\nimport { screenSpaceRayTracing_HiZ, screenSpaceRayTracing_Linear2D } from '../shaders/ssr';\nimport { SSGI_rand2, SSGI_cosineSampleHemisphere } from '../shaders/ssgi';\nimport type { Nullable } from '@zephyr3d/base';\nimport { Matrix4x4, Vector2, Vector4 } from '@zephyr3d/base';\nimport { copyTexture, fetchSampler } from '../utility/misc';\nimport { BilateralBlurBlitter } from '../blitter/bilateralblur';\nimport { ShaderHelper } from '../material';\nimport { RGHistoryResources } from '../render/rendergraph/history_resources';\nimport { FrameResources } from '../render/rendergraph/blackboard';\nimport type { RGExecuteContext, RGHandle, RGPassBuilder, RGTextureDesc } from '../render/rendergraph/types';\n\n/**\n * SSGI post effect\n *\n * @remarks\n * Screen space global illumination: gathers one-bounce indirect diffuse\n * lighting by cosine-weighted hemisphere ray marching against the scene\n * depth buffer (Hi-Z accelerated when available), then denoises the result\n * with a bilateral blur and optional temporal accumulation before adding\n * it to the scene color. Internal used in light pass.\n *\n * @internal\n */\nexport class SSGI extends AbstractPostEffect {\n private static _tracePrograms: Record<string, GPUProgram> = {};\n private static _combineProgram?: GPUProgram;\n private static _temporalProgram?: GPUProgram;\n private static _blurBlitterH: Nullable<BilateralBlurBlitter> = null;\n private static _blurBlitterV: Nullable<BilateralBlurBlitter> = null;\n private _traceBindGroups: Record<string, BindGroup>;\n private _combineBindGroup: Nullable<BindGroup>;\n private _temporalBindGroup: Nullable<BindGroup>;\n /**\n * Creates an instance of SSGI post effect\n */\n constructor() {\n super();\n this._layer = PostEffectLayer.opaque;\n this._traceBindGroups = {};\n this._combineBindGroup = null;\n this._temporalBindGroup = null;\n }\n /** {@inheritDoc AbstractPostEffect.requireLinearDepthTexture} */\n requireLinearDepthTexture() {\n return true;\n }\n /** {@inheritDoc AbstractPostEffect.requireDepthAttachment} */\n requireDepthAttachment() {\n return true;\n }\n /** {@inheritDoc AbstractPostEffect.requireMotionVectorTexture} */\n requireMotionVectorTexture(ctx: DrawContext) {\n return !!ctx.camera.ssgiTemporal;\n }\n /**\n * Declares SSGI's internal steps (trace, optional bilateral blur, optional\n * temporal resolve, combine) as individual render graph passes.\n */\n setup(s: PostEffectSetupContext): RGHandle {\n const { graph, ctx, history } = s;\n // SSGI needs the surface normal MRT and dynamic loops; neither is\n // available on WebGL1. Pass the input through untouched in that case.\n if (ctx.device.type === 'webgl' || !s.blackboard.get(FrameResources.SSRNormal)) {\n return s.input;\n }\n const camera = ctx.camera;\n const halfRes = !!camera.ssgiHalfResolution;\n const traceWidth = Math.max(1, halfRes ? s.width >> 1 : s.width);\n const traceHeight = Math.max(1, halfRes ? s.height >> 1 : s.height);\n const linearDepthHandle = s.blackboard.get(FrameResources.LinearDepth);\n const texDesc: RGTextureDesc = {\n format: 'rgba16f',\n sizeMode: 'absolute',\n width: traceWidth,\n height: traceHeight\n };\n const readCommon = (builder: RGPassBuilder) => {\n if (linearDepthHandle) {\n builder.read(linearDepthHandle);\n }\n // Normal MRT, HiZ and the scene color are reached through DrawContext\n // fields; the dependency list carries their handles.\n for (const dep of s.dependencies) {\n builder.read(dep);\n }\n };\n const getLinearDepth = (rg: RGExecuteContext) =>\n linearDepthHandle ? rg.getTexture<Texture2D>(linearDepthHandle) : ctx.linearDepthTexture!;\n\n // 1. Trace cosine-weighted hemisphere rays against the depth buffer and\n // gather the radiance at the hit points.\n const traceHandle = graph.addPass('SSGI:Trace', (builder) => {\n builder.read(s.input);\n readCommon(builder);\n const out = builder.createTexture({ ...texDesc, label: 'SSGI:trace' });\n const fb = builder.createFramebuffer({\n label: 'SSGI:traceFB',\n width: traceWidth,\n height: traceHeight,\n colorAttachments: out,\n depthAttachment: null,\n ignoreDepthStencil: true\n });\n builder.setExecute((rg) => {\n const device = ctx.device;\n device.pushDeviceStates();\n try {\n device.setFramebuffer(rg.getFramebuffer(fb));\n this.trace(ctx, rg.getTexture<Texture2D>(s.input), getLinearDepth(rg));\n } finally {\n device.popDeviceStates();\n }\n });\n return out;\n });\n\n // 2. Temporal accumulation BEFORE the spatial blur: accumulating the raw\n // per-pixel estimate raises the effective sample count over time, and the\n // blur then only has to clean the residual noise. (Blurring first would\n // turn per-frame noise into large low-frequency blobs that flicker.)\n // The history stores the pre-blur accumulated signal.\n const wantTemporal = !!camera.ssgiTemporal;\n const motionVectorHandle = wantTemporal ? s.blackboard.get(FrameResources.MotionVector) : null;\n const historySize = { width: traceWidth, height: traceHeight };\n const prevRadianceHandle =\n wantTemporal && history && motionVectorHandle\n ? history.importPreviousIfCompatible(graph, RGHistoryResources.SSGI_RADIANCE, texDesc, historySize)\n : null;\n const prevMotionVectorHandle =\n wantTemporal && history && motionVectorHandle\n ? history.importPreviousIfCompatible(\n graph,\n RGHistoryResources.SSGI_MOTION_VECTOR,\n {\n format: 'rgba16f',\n sizeMode: 'absolute',\n width: s.width,\n height: s.height\n },\n { width: s.width, height: s.height }\n )\n : null;\n let radianceHandle = traceHandle;\n const canTemporal = !!(motionVectorHandle && prevRadianceHandle && prevMotionVectorHandle);\n if (canTemporal) {\n radianceHandle = graph.addPass('SSGI:Temporal', (builder) => {\n builder.read(traceHandle);\n builder.read(prevRadianceHandle!);\n builder.read(prevMotionVectorHandle!);\n builder.read(motionVectorHandle!);\n readCommon(builder);\n const out = builder.createTexture({ ...texDesc, label: 'SSGI:temporal' });\n const fb = builder.createFramebuffer({\n label: 'SSGI:temporalFB',\n width: traceWidth,\n height: traceHeight,\n colorAttachments: out,\n depthAttachment: null,\n ignoreDepthStencil: true\n });\n builder.setExecute((rg) => {\n const device = ctx.device;\n device.pushDeviceStates();\n try {\n this.temporal(\n ctx,\n rg.getTexture<Texture2D>(traceHandle),\n rg.getTexture<Texture2D>(prevRadianceHandle!),\n rg.getTexture<Texture2D>(prevMotionVectorHandle!),\n rg.getFramebuffer<FrameBuffer>(fb)\n );\n } finally {\n device.popDeviceStates();\n }\n });\n return out;\n });\n }\n // The accumulated (pre-blur) signal is what feeds next frame's history.\n const accumulatedHandle = radianceHandle;\n\n // 3. Bilateral blur (horizontal + vertical) guided by scene depth cleans\n // the residual noise left after accumulation.\n if (camera.ssgiBlurKernelSize > 0) {\n const blurInputHandle = radianceHandle;\n radianceHandle = graph.addPass('SSGI:Blur', (builder) => {\n builder.read(blurInputHandle);\n readCommon(builder);\n const middle = builder.createTexture({ ...texDesc, label: 'SSGI:blurH' });\n const out = builder.createTexture({ ...texDesc, label: 'SSGI:blur' });\n const middleFB = builder.createFramebuffer({\n label: 'SSGI:blurHFB',\n width: traceWidth,\n height: traceHeight,\n colorAttachments: middle,\n depthAttachment: null,\n ignoreDepthStencil: true\n });\n const outFB = builder.createFramebuffer({\n label: 'SSGI:blurFB',\n width: traceWidth,\n height: traceHeight,\n colorAttachments: out,\n depthAttachment: null,\n ignoreDepthStencil: true\n });\n builder.setExecute((rg) => {\n const device = ctx.device;\n device.pushDeviceStates();\n try {\n const depthTex = getLinearDepth(rg);\n const blitterH = (SSGI._blurBlitterH = SSGI._blurBlitterH ?? new BilateralBlurBlitter(false));\n this.blurPass(\n ctx,\n blitterH,\n depthTex,\n rg.getTexture<Texture2D>(blurInputHandle),\n rg.getFramebuffer<FrameBuffer>(middleFB)\n );\n const blitterV = (SSGI._blurBlitterV = SSGI._blurBlitterV ?? new BilateralBlurBlitter(true));\n this.blurPass(\n ctx,\n blitterV,\n depthTex,\n rg.getTexture<Texture2D>(middle),\n rg.getFramebuffer<FrameBuffer>(outFB)\n );\n } finally {\n device.popDeviceStates();\n }\n });\n return out;\n });\n }\n\n // 4. Upsample, modulate by the albedo approximation and add to the scene\n // color; queue history commits.\n const finalRadianceHandle = radianceHandle;\n return graph.addPass('PostEffect:SSGI', (builder) => {\n builder.read(s.input);\n builder.read(finalRadianceHandle);\n if (accumulatedHandle !== finalRadianceHandle) {\n builder.read(accumulatedHandle);\n }\n if (motionVectorHandle) {\n builder.read(motionVectorHandle);\n }\n readCommon(builder);\n const output = s.createOutput(builder, { needDepthAttachment: true });\n builder.setExecute((rg) => {\n const device = ctx.device;\n device.pushDeviceStates();\n try {\n device.setFramebuffer(output.framebuffer ? rg.getFramebuffer(output.framebuffer) : null);\n const inputTex = rg.getTexture<Texture2D>(s.input);\n const radianceTex = rg.getTexture<Texture2D>(finalRadianceHandle);\n copyTexture(\n inputTex,\n device.getFramebuffer()!,\n fetchSampler('clamp_nearest_nomip'),\n AbstractPostEffect.getDefaultRenderState(ctx, 'eq')\n );\n this.combine(ctx, inputTex, radianceTex, output.srgbOutput);\n // Commit history whenever temporal is wanted - even on frames where\n // the temporal pass could not run yet (no compatible history). This\n // seeds the very first frame; gating the commit on canTemporal\n // would deadlock: no history -> no temporal -> no commit -> no\n // history, forever.\n if (wantTemporal && history && motionVectorHandle) {\n // Commit the PRE-blur accumulated signal: feeding the blurred\n // result back would compound the blur every frame.\n const accumulatedTex = rg.getTexture<Texture2D>(accumulatedHandle);\n history.queueRetainedCommit(\n RGHistoryResources.SSGI_RADIANCE,\n {\n format: accumulatedTex.format,\n sizeMode: 'absolute',\n width: accumulatedTex.width,\n height: accumulatedTex.height\n },\n { width: accumulatedTex.width, height: accumulatedTex.height },\n accumulatedTex\n );\n if (ctx.motionVectorTexture) {\n history.queueRetainedCommit(\n RGHistoryResources.SSGI_MOTION_VECTOR,\n {\n format: ctx.motionVectorTexture.format,\n sizeMode: 'absolute',\n width: ctx.motionVectorTexture.width,\n height: ctx.motionVectorTexture.height\n },\n { width: ctx.motionVectorTexture.width, height: ctx.motionVectorTexture.height },\n ctx.motionVectorTexture\n );\n }\n }\n } finally {\n device.popDeviceStates();\n }\n });\n return output.color;\n });\n }\n /** @internal */\n blurPass(\n ctx: DrawContext,\n blitter: BilateralBlurBlitter,\n depthTex: Texture2D,\n srcTex: Texture2D,\n fbTo: FrameBuffer\n ) {\n const camera = ctx.camera;\n blitter.kernelRadius = (Math.max(1, camera.ssgiBlurKernelSize >> 0) - 1) >> 1;\n blitter.stdDev = camera.ssgiBlurStdDev;\n blitter.size = new Vector2(srcTex.width, srcTex.height);\n blitter.depthTex = depthTex;\n blitter.depthCutoff = camera.ssgiBlurDepthCutoff;\n blitter.blurSizeTex = null;\n blitter.sampler = fetchSampler('clamp_nearest_nomip');\n blitter.cameraNearFar.setXY(camera.getNearPlane(), camera.getFarPlane());\n blitter.srgbOut = false;\n blitter.blit(srcTex, fbTo, fetchSampler('clamp_linear_nomip'));\n }\n /** @internal */\n trace(ctx: DrawContext, inputColorTexture: Texture2D, sceneDepthTexture: Texture2D) {\n const device = ctx.device;\n const hash = `${!!ctx.HiZTexture}:${!!ctx.SSRCalcThickness}`;\n let program = SSGI._tracePrograms[hash];\n if (program === undefined) {\n const created = this._createTraceProgram(ctx);\n if (!created) {\n return;\n }\n program = created;\n SSGI._tracePrograms[hash] = program;\n }\n let bindGroup = this._traceBindGroups[hash];\n if (!bindGroup) {\n bindGroup = device.createBindGroup(program.bindGroupLayouts[0]);\n this._traceBindGroups[hash] = bindGroup;\n }\n const camera = ctx.camera;\n const nearestSampler = fetchSampler('clamp_nearest');\n const linearSampler = fetchSampler('clamp_linear');\n const fb = device.getFramebuffer()!;\n const traceWidth = fb.getWidth();\n const traceHeight = fb.getHeight();\n bindGroup.setTexture('colorTex', inputColorTexture, linearSampler);\n bindGroup.setTexture('normalTex', ctx.SSRNormalTexture!, nearestSampler);\n bindGroup.setTexture('depthTex', sceneDepthTexture, nearestSampler);\n bindGroup.setValue('cameraNearFar', new Vector2(camera.getNearPlane(), camera.getFarPlane()));\n bindGroup.setValue('projMatrix', camera.getProjectionMatrix());\n bindGroup.setValue('invProjMatrix', Matrix4x4.invert(camera.getProjectionMatrix()));\n bindGroup.setValue('viewMatrix', camera.viewMatrix);\n bindGroup.setValue(\n 'ssgiParams',\n new Vector4(camera.ssgiRadius, camera.ssgiMaxSteps, camera.ssgiThickness, camera.ssgiSamples)\n );\n // Advance the noise sequence only when the temporal resolve can converge\n // it; a static pattern is less objectionable than unaccumulated flicker.\n bindGroup.setValue('frameIndex', camera.ssgiTemporal ? device.frameInfo.frameCounter % 1024 : 0);\n if (ctx.HiZTexture) {\n bindGroup.setTexture('hizTex', ctx.HiZTexture, nearestSampler);\n bindGroup.setValue('depthMipLevels', ctx.HiZTexture.mipLevelCount);\n bindGroup.setValue(\n 'targetSize',\n new Vector4(traceWidth, traceHeight, ctx.HiZTexture.width, ctx.HiZTexture.height)\n );\n } else {\n bindGroup.setValue('ssgiStride', camera.ssgiStride);\n bindGroup.setValue(\n 'targetSize',\n new Vector4(traceWidth, traceHeight, sceneDepthTexture.width, sceneDepthTexture.height)\n );\n }\n bindGroup.setValue('flip', this.needFlip(device) ? 1 : 0);\n device.setProgram(program);\n device.setBindGroup(0, bindGroup);\n this.drawFullscreenQuad(AbstractPostEffect.getDefaultRenderState(ctx, 'always'));\n }\n /** @internal */\n temporal(\n ctx: DrawContext,\n currentRadianceTex: Texture2D,\n prevRadianceTex: Texture2D,\n prevMotionVectorTex: Texture2D,\n outFramebuffer: FrameBuffer\n ) {\n const device = ctx.device;\n let program = SSGI._temporalProgram;\n if (!program) {\n program = this._createTemporalProgram(ctx);\n SSGI._temporalProgram = program;\n }\n if (!this._temporalBindGroup) {\n this._temporalBindGroup = device.createBindGroup(program.bindGroupLayouts[0]);\n }\n this._temporalBindGroup.setTexture(\n 'historyColorTex',\n prevRadianceTex,\n fetchSampler('clamp_linear_nomip')\n );\n this._temporalBindGroup.setTexture(\n 'currentColorTex',\n currentRadianceTex,\n fetchSampler('clamp_nearest_nomip')\n );\n this._temporalBindGroup.setTexture(\n 'motionVector',\n ctx.motionVectorTexture!,\n fetchSampler('clamp_linear_nomip')\n );\n this._temporalBindGroup.setTexture(\n 'prevMotionVector',\n prevMotionVectorTex,\n fetchSampler('clamp_linear_nomip')\n );\n this._temporalBindGroup.setValue('flip', this.needFlip(device) ? 1 : 0);\n this._temporalBindGroup.setValue(\n 'texSize',\n new Vector2(currentRadianceTex.width, currentRadianceTex.height)\n );\n this._temporalBindGroup.setValue('temporalWeight', ctx.camera.ssgiTemporalWeight);\n device.setFramebuffer(outFramebuffer);\n device.setProgram(program);\n device.setBindGroup(0, this._temporalBindGroup);\n this.drawFullscreenQuad(AbstractPostEffect.getDefaultRenderState(ctx, 'always'));\n }\n /** @internal */\n combine(ctx: DrawContext, inputColorTexture: Texture2D, radianceTex: Texture2D, srgbOut: boolean) {\n const device = ctx.device;\n let program = SSGI._combineProgram;\n if (program === undefined) {\n program = this._createCombineProgram(ctx);\n SSGI._combineProgram = program;\n }\n if (!this._combineBindGroup) {\n this._combineBindGroup = device.createBindGroup(program!.bindGroupLayouts[0]);\n }\n this._combineBindGroup.setTexture('colorTex', inputColorTexture, fetchSampler('clamp_nearest'));\n this._combineBindGroup.setTexture('radianceTex', radianceTex, fetchSampler('clamp_linear'));\n this._combineBindGroup.setValue('ssgiIntensity', ctx.camera.ssgiIntensity);\n this._combineBindGroup.setValue(\n 'targetSize',\n new Vector2(inputColorTexture.width, inputColorTexture.height)\n );\n this._combineBindGroup.setValue('flip', this.needFlip(device) ? 1 : 0);\n this._combineBindGroup.setValue('srgbOut', srgbOut ? 1 : 0);\n device.setProgram(program);\n device.setBindGroup(0, this._combineBindGroup);\n this.drawFullscreenQuad(AbstractPostEffect.getDefaultRenderState(ctx, 'gt'));\n }\n /** @internal */\n private _createTraceProgram(ctx: DrawContext): Nullable<GPUProgram> {\n const program = ctx.device.buildRenderProgram({\n vertex(pb) {\n this.flip = pb.int().uniform(0);\n this.$inputs.pos = pb.vec2().attrib('position');\n this.$outputs.uv = pb.vec2();\n pb.main(function () {\n this.$builtins.position = pb.vec4(this.$inputs.pos, 1, 1);\n this.$outputs.uv = pb.add(pb.mul(this.$inputs.pos.xy, 0.5), pb.vec2(0.5));\n this.$if(pb.notEqual(this.flip, 0), function () {\n this.$builtins.position.y = pb.neg(this.$builtins.position.y);\n });\n });\n },\n fragment(pb) {\n this.colorTex = pb.tex2D().uniform(0);\n this.normalTex = pb.tex2D().uniform(0);\n this.depthTex = pb.tex2D().uniform(0);\n this.cameraNearFar = pb.vec2().uniform(0);\n this.projMatrix = pb.mat4().uniform(0);\n this.invProjMatrix = pb.mat4().uniform(0);\n this.viewMatrix = pb.mat4().uniform(0);\n // (radius, maxIterations, thickness, numRays)\n this.ssgiParams = pb.vec4().uniform(0);\n this.frameIndex = pb.float().uniform(0);\n this.targetSize = pb.vec4().uniform(0);\n if (ctx.HiZTexture) {\n this.hizTex = pb.tex2D().uniform(0);\n this.depthMipLevels = pb.int().uniform(0);\n } else {\n this.ssgiStride = pb.float().uniform(0);\n }\n this.$outputs.outColor = pb.vec4();\n pb.func('getPosition', [pb.vec2('uv'), pb.mat4('mat')], function () {\n this.$l.linearDepth = ShaderHelper.sampleLinearDepth(this, this.depthTex, this.uv, 0);\n this.$l.nonLinearDepth = pb.div(\n pb.sub(pb.div(this.cameraNearFar.x, this.linearDepth), this.cameraNearFar.y),\n pb.sub(this.cameraNearFar.x, this.cameraNearFar.y)\n );\n this.$l.clipSpacePos = pb.vec4(\n pb.sub(pb.mul(this.uv, 2), pb.vec2(1)),\n pb.sub(pb.mul(pb.clamp(this.nonLinearDepth, 0, 1), 2), 1),\n 1\n );\n this.$l.wPos = pb.mul(this.mat, this.clipSpacePos);\n this.$return(pb.vec4(pb.div(this.wPos.xyz, this.wPos.w), this.linearDepth));\n });\n pb.main(function () {\n this.$l.screenUV = pb.div(pb.vec2(this.$builtins.fragCoord.xy), this.targetSize.xy);\n this.$l.color = pb.vec3(0);\n this.$l.pos = this.getPosition(this.screenUV, this.invProjMatrix);\n this.$if(pb.lessThan(this.pos.w, 1), function () {\n this.$l.viewPos = this.pos.xyz;\n this.$l.worldNormal = pb.sub(\n pb.mul(pb.textureSampleLevel(this.normalTex, this.screenUV, 0).rgb, 2),\n pb.vec3(1)\n );\n this.$l.viewNormal = pb.normalize(pb.mul(this.viewMatrix, pb.vec4(this.worldNormal, 0)).xyz);\n this.$l.numRays = pb.max(this.ssgiParams.w, 1);\n this.$l.sum = pb.vec3(0);\n this.$for(pb.float('ray'), 0, this.numRays, function () {\n this.$l.rand = SSGI_rand2(\n this,\n pb.vec2(this.$builtins.fragCoord.xy),\n pb.add(pb.mul(this.frameIndex, this.numRays), this.ray)\n );\n this.$l.rayDir = SSGI_cosineSampleHemisphere(this, this.viewNormal, this.rand);\n this.$l.hitInfo = pb.vec4(0);\n if (ctx.HiZTexture) {\n this.hitInfo = screenSpaceRayTracing_HiZ(\n this,\n this.viewPos,\n this.rayDir,\n this.viewMatrix,\n this.projMatrix,\n this.invProjMatrix,\n this.cameraNearFar,\n this.depthMipLevels,\n this.ssgiParams.y,\n this.ssgiParams.x,\n this.ssgiParams.z,\n this.targetSize,\n this.hizTex,\n this.normalTex\n );\n } else {\n this.hitInfo = screenSpaceRayTracing_Linear2D(\n this,\n this.viewPos,\n this.rayDir,\n this.viewMatrix,\n this.projMatrix,\n this.invProjMatrix,\n this.cameraNearFar,\n this.ssgiParams.x,\n this.ssgiParams.y,\n this.ssgiParams.z,\n this.ssgiStride,\n this.targetSize,\n this.depthTex,\n this.normalTex,\n // Backface depth is only present when the depth prepass was\n // built with SSR thickness computation enabled.\n !!ctx.SSRCalcThickness\n );\n }\n this.$l.hitAlpha = pb.clamp(this.hitInfo.w, 0, 1);\n // Hemisphere rays frequently graze the screen plane; the\n // projective ray setup can then produce Inf/NaN which would be\n // smeared into large blocks by the bilateral blur. NaN fails\n // any comparison, so this test also rejects it.\n this.$l.hitValid = pb.and(\n pb.all(pb.lessThan(pb.abs(this.hitInfo), pb.vec4(1e30))),\n pb.greaterThan(this.hitAlpha, 0)\n );\n this.$if(this.hitValid, function () {\n this.$l.hitUV = pb.clamp(this.hitInfo.xy, pb.vec2(0), pb.vec2(1));\n // Firefly clamp: an HDR sun/sky sample can be orders of\n // magnitude brighter than the surroundings; unclamped it\n // dominates the low-spp estimate as isolated bright dots no\n // spatial filter can remove.\n this.$l.radiance = pb.min(\n pb.textureSampleLevel(this.colorTex, this.hitUV, 0).rgb,\n pb.vec3(4)\n );\n this.sum = pb.add(this.sum, pb.mul(this.radiance, this.hitAlpha));\n });\n });\n // Cosine-weighted sampling: the irradiance estimate over the\n // hemisphere reduces to the plain average of the hit radiances.\n this.color = pb.div(this.sum, this.numRays);\n });\n // Reinhard-compress into [0, 1) (mirrors the SSR intersect pass).\n // The bilateral blur weights neighbors by color distance; in linear\n // HDR a firefly is \"far\" from every neighbor and survives the blur\n // untouched. Compressed, bright outliers stay within blurring range\n // and the denoiser can actually converge them. combine() inverts\n // this mapping.\n this.color = pb.div(this.color, pb.add(this.color, pb.vec3(1)));\n this.$outputs.outColor = pb.vec4(this.color, 1);\n });\n }\n });\n if (!program) {\n return null;\n }\n program.name = '@SSGI_Trace';\n return program;\n }\n /** @internal */\n private _createTemporalProgram(ctx: DrawContext) {\n const program = ctx.device.buildRenderProgram({\n vertex(pb) {\n this.flip = pb.int().uniform(0);\n this.$inputs.pos = pb.vec2().attrib('position');\n this.$outputs.uv = pb.vec2();\n pb.main(function () {\n this.$builtins.position = pb.vec4(this.$inputs.pos, 1, 1);\n this.$outputs.uv = pb.add(pb.mul(this.$inputs.pos.xy, 0.5), pb.vec2(0.5));\n this.$if(pb.notEqual(this.flip, 0), function () {\n this.$builtins.position.y = pb.neg(this.$builtins.position.y);\n });\n });\n },\n fragment(pb) {\n this.historyColorTex = pb.tex2D().uniform(0);\n this.currentColorTex = pb.tex2D().uniform(0);\n this.motionVector = pb.tex2D().uniform(0);\n this.prevMotionVector = pb.tex2D().uniform(0);\n this.texSize = pb.vec2().uniform(0);\n this.temporalWeight = pb.float().uniform(0);\n this.$outputs.outColor = pb.vec4();\n pb.main(function () {\n // Sample-count adaptive accumulation with fixed-gamma variance\n // clipping. The accumulated frame count N rides in the alpha\n // channel of the radiance history: early frames blend with\n // 1/(N+1) (fast convergence), converged pixels blend at the\n // temporalWeight cap. A FIXED-weight EMA never settles - its\n // stationary state is a random walk inside the clip box, visible\n // as slowly rippling low-frequency noise after the blur. With\n // count-based weighting the estimator is a true running average,\n // so the converged value stops moving.\n // TAA-style box collapsing with velocity is deliberately avoided:\n // camera jitter alone would collapse the box and reject all\n // history, preventing convergence of the stochastic signal.\n this.$l.screenUV = pb.div(pb.vec2(this.$builtins.fragCoord.xy), this.texSize);\n this.$l.currentColor = pb.textureSampleLevel(this.currentColorTex, this.screenUV, 0).rgb;\n this.$l.velocitySample = pb.textureSampleLevel(this.motionVector, this.screenUV, 0);\n this.$l.velocity = this.velocitySample.xy;\n // Sky/unwritten motion vector sentinel: no history\n this.$if(\n pb.and(pb.greaterThanEqual(this.velocity.x, 5e4), pb.greaterThanEqual(this.velocity.y, 5e4)),\n function () {\n this.$outputs.outColor = pb.vec4(this.currentColor, 1);\n }\n ).$else(function () {\n this.$l.reprojectedUV = pb.sub(this.screenUV, this.velocity);\n this.$l.offscreen = pb.or(\n pb.any(pb.lessThan(this.reprojectedUV, pb.vec2(0))),\n pb.any(pb.greaterThan(this.reprojectedUV, pb.vec2(1)))\n );\n this.$if(this.offscreen, function () {\n this.$outputs.outColor = pb.vec4(this.currentColor, 1);\n }).$else(function () {\n this.$l.historySample = pb.textureSampleLevel(this.historyColorTex, this.reprojectedUV, 0);\n this.$l.historyColor = this.historySample.rgb;\n this.$l.historyCount = pb.max(this.historySample.a, 1);\n // 3x3 neighborhood statistics of the current stochastic estimate\n this.$l.m1 = pb.vec3(0);\n this.$l.m2 = pb.vec3(0);\n for (let i = -1; i <= 1; i++) {\n for (let j = -1; j <= 1; j++) {\n const c = `c${(i + 1) * 3 + j + 1}`;\n this.$l[c] = pb.textureSampleLevel(\n this.currentColorTex,\n pb.add(this.screenUV, pb.div(pb.vec2(i, j), this.texSize)),\n 0\n ).rgb;\n this.m1 = pb.add(this.m1, this[c]);\n this.m2 = pb.add(this.m2, pb.mul(this[c], this[c]));\n }\n }\n this.m1 = pb.div(this.m1, 9);\n this.m2 = pb.div(this.m2, 9);\n this.$l.sigma = pb.sqrt(pb.max(pb.sub(this.m2, pb.mul(this.m1, this.m1)), pb.vec3(0)));\n // gamma = 2 with a small absolute slack: tolerant to the noise a\n // converged history legitimately sits in (compressed-space values).\n this.$l.halfExtent = pb.add(pb.mul(this.sigma, 2), pb.vec3(0.03));\n this.$l.clampedHistory = pb.clamp(\n this.historyColor,\n pb.sub(this.m1, this.halfExtent),\n pb.add(this.m1, this.halfExtent)\n );\n // How much the clip moved the history signals stale data;\n // knock the effective count down so recovery is fast.\n this.$l.clipAmount = pb.length(pb.sub(this.clampedHistory, this.historyColor));\n this.$l.clipReset = pb.clamp(pb.mul(this.clipAmount, 8), 0, 1);\n // Disocclusion: previous frame's motion at the reprojected point\n // should agree with the current motion; a large mismatch means the\n // surface was not visible last frame.\n this.$l.prevVelocity = pb.textureSampleLevel(this.prevMotionVector, this.reprojectedUV, 0).xy;\n this.$l.velocityDiff = pb.length(\n pb.mul(pb.sub(this.velocity, this.prevVelocity), this.texSize)\n );\n this.$l.disocclusion = pb.clamp(pb.mul(pb.sub(this.velocityDiff, 2.5), 0.1), 0, 1);\n this.$l.confidence = pb.mul(pb.sub(1, this.disocclusion), pb.sub(1, this.clipReset));\n this.$l.effectiveCount = pb.max(pb.mul(this.historyCount, this.confidence), 0);\n // Count-based blend weight, capped by temporalWeight:\n // maxCount = w/(1-w) so the cap and the weight limit agree.\n this.$l.wMax = pb.clamp(this.temporalWeight, 0, 0.99);\n this.$l.maxCount = pb.div(this.wMax, pb.sub(1, this.wMax));\n this.$l.w = pb.min(this.wMax, pb.div(this.effectiveCount, pb.add(this.effectiveCount, 1)));\n this.$l.newCount = pb.min(pb.add(this.effectiveCount, 1), this.maxCount);\n this.$outputs.outColor = pb.vec4(\n pb.mix(this.currentColor, this.clampedHistory, this.w),\n this.newCount\n );\n });\n });\n });\n }\n })!;\n program.name = '@SSGI_Temporal';\n return program;\n }\n /** @internal */\n private _createCombineProgram(ctx: DrawContext) {\n const program = ctx.device.buildRenderProgram({\n vertex(pb) {\n this.flip = pb.int().uniform(0);\n this.$inputs.pos = pb.vec2().attrib('position');\n this.$outputs.uv = pb.vec2();\n pb.main(function () {\n this.$builtins.position = pb.vec4(this.$inputs.pos, 1, 1);\n this.$outputs.uv = pb.add(pb.mul(this.$inputs.pos.xy, 0.5), pb.vec2(0.5));\n this.$if(pb.notEqual(this.flip, 0), function () {\n this.$builtins.position.y = pb.neg(this.$builtins.position.y);\n });\n });\n },\n fragment(pb) {\n this.colorTex = pb.tex2D().uniform(0);\n this.radianceTex = pb.tex2D().uniform(0);\n this.targetSize = pb.vec2().uniform(0);\n this.ssgiIntensity = pb.float().uniform(0);\n this.srgbOut = pb.int().uniform(0);\n this.$outputs.outColor = pb.vec4();\n pb.main(function () {\n this.$l.screenUV = pb.div(pb.vec2(this.$builtins.fragCoord.xy), this.targetSize);\n this.$l.sceneColor = pb.textureSampleLevel(this.colorTex, this.screenUV, 0).rgb;\n // Invert the Reinhard compression applied by the trace pass\n // (x/(1+x) -> y/(1-y)); the clamp bounds the expansion so a fully\n // saturated texel cannot blow up to infinity.\n this.$l.compressed = pb.clamp(\n pb.textureSampleLevel(this.radianceTex, this.screenUV, 0).rgb,\n pb.vec3(0),\n pb.vec3(0.98)\n );\n this.$l.radiance = pb.div(this.compressed, pb.sub(pb.vec3(1), this.compressed));\n // The forward pipeline keeps no albedo GBuffer; approximate the\n // surface reflectance by the chromaticity of the lit scene color\n // (hue preserved, luminance normalized). Unlike scaling by the\n // scene color itself this keeps indirect light visible in shadowed\n // areas - exactly where GI matters.\n this.$l.luma = pb.dot(this.sceneColor, pb.vec3(0.2126, 0.7152, 0.0722));\n this.$l.albedoApprox = pb.clamp(\n pb.div(this.sceneColor, pb.vec3(pb.add(this.luma, 1e-3))),\n pb.vec3(0),\n pb.vec3(1)\n );\n this.$l.combined = pb.add(\n this.sceneColor,\n pb.mul(this.radiance, this.albedoApprox, this.ssgiIntensity)\n );\n this.$if(pb.equal(this.srgbOut, 0), function () {\n this.$outputs.outColor = pb.vec4(this.combined, 1);\n }).$else(function () {\n this.$outputs.outColor = pb.vec4(linearToGamma(this, this.combined), 1);\n });\n });\n }\n })!;\n program.name = '@SSGI_Combine';\n return program;\n }\n}\n"],"names":["SSGI","AbstractPostEffect","_tracePrograms","_combineProgram","_temporalProgram","_blurBlitterH","_blurBlitterV","_traceBindGroups","_combineBindGroup","_temporalBindGroup","_layer","PostEffectLayer","opaque","requireLinearDepthTexture","requireDepthAttachment","requireMotionVectorTexture","ctx","camera","ssgiTemporal","setup","s","graph","history","device","type","blackboard","get","FrameResources","SSRNormal","input","halfRes","ssgiHalfResolution","traceWidth","Math","max","width","traceHeight","height","linearDepthHandle","LinearDepth","texDesc","format","sizeMode","readCommon","builder","read","dep","dependencies","getLinearDepth","rg","getTexture","linearDepthTexture","traceHandle","addPass","out","createTexture","label","fb","createFramebuffer","colorAttachments","depthAttachment","ignoreDepthStencil","setExecute","pushDeviceStates","setFramebuffer","getFramebuffer","trace","popDeviceStates","wantTemporal","motionVectorHandle","MotionVector","historySize","prevRadianceHandle","importPreviousIfCompatible","RGHistoryResources","SSGI_RADIANCE","prevMotionVectorHandle","SSGI_MOTION_VECTOR","radianceHandle","canTemporal","temporal","accumulatedHandle","ssgiBlurKernelSize","blurInputHandle","middle","middleFB","outFB","depthTex","blitterH","BilateralBlurBlitter","blurPass","blitterV","finalRadianceHandle","output","createOutput","needDepthAttachment","framebuffer","inputTex","radianceTex","copyTexture","fetchSampler","getDefaultRenderState","combine","srgbOutput","accumulatedTex","queueRetainedCommit","motionVectorTexture","color","blitter","srcTex","fbTo","kernelRadius","stdDev","ssgiBlurStdDev","size","Vector2","depthCutoff","ssgiBlurDepthCutoff","blurSizeTex","sampler","cameraNearFar","setXY","getNearPlane","getFarPlane","srgbOut","blit","inputColorTexture","sceneDepthTexture","hash","HiZTexture","SSRCalcThickness","program","undefined","created","_createTraceProgram","bindGroup","createBindGroup","bindGroupLayouts","nearestSampler","linearSampler","getWidth","getHeight","setTexture","SSRNormalTexture","setValue","getProjectionMatrix","Matrix4x4","invert","viewMatrix","Vector4","ssgiRadius","ssgiMaxSteps","ssgiThickness","ssgiSamples","frameInfo","frameCounter","mipLevelCount","ssgiStride","needFlip","setProgram","setBindGroup","drawFullscreenQuad","currentRadianceTex","prevRadianceTex","prevMotionVectorTex","outFramebuffer","_createTemporalProgram","ssgiTemporalWeight","_createCombineProgram","ssgiIntensity","buildRenderProgram","vertex","pb","flip","int","uniform","$inputs","pos","vec2","attrib","$outputs","uv","main","$builtins","position","vec4","add","mul","xy","$if","notEqual","y","neg","fragment","colorTex","tex2D","normalTex","projMatrix","mat4","invProjMatrix","ssgiParams","frameIndex","float","targetSize","hizTex","depthMipLevels","outColor","func","$l","linearDepth","ShaderHelper","sampleLinearDepth","nonLinearDepth","div","sub","x","clipSpacePos","clamp","wPos","mat","$return","xyz","w","screenUV","fragCoord","vec3","getPosition","lessThan","viewPos","worldNormal","textureSampleLevel","rgb","viewNormal","normalize","numRays","sum","$for","rand","SSGI_rand2","ray","rayDir","SSGI_cosineSampleHemisphere","hitInfo","screenSpaceRayTracing_HiZ","z","screenSpaceRayTracing_Linear2D","hitAlpha","hitValid","and","all","abs","greaterThan","hitUV","radiance","min","name","historyColorTex","currentColorTex","motionVector","prevMotionVector","texSize","temporalWeight","currentColor","velocitySample","velocity","greaterThanEqual","$else","reprojectedUV","offscreen","or","any","historySample","historyColor","historyCount","a","m1","m2","i","j","c","sigma","sqrt","halfExtent","clampedHistory","clipAmount","length","clipReset","prevVelocity","velocityDiff","disocclusion","confidence","effectiveCount","wMax","maxCount","newCount","mix","sceneColor","compressed","luma","dot","albedoApprox","combined","equal","linearToGamma"],"mappings":"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"}
@@ -79,9 +79,32 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
79
79
  }
80
80
  return null;
81
81
  }
82
+ /**
83
+ * Whether the combine pass should read the screen-space shadow mask for the
84
+ * combine light instead of recomputing its shadow. Enabled when the camera
85
+ * renders the mask and the combine light was actually written into it: the
86
+ * mask already holds the identical shadow — same shadow impl (PCSS/VSM/…),
87
+ * distance fade and shadowStrength — so this skips a full redundant per-pixel
88
+ * shadow evaluation. Shadow mode is irrelevant: the mask is rendered with the
89
+ * light's own impl. Falls back to the inline path when the light is not in the
90
+ * mask (e.g. it overflows {@link MAX_SHADOW_MASK_LIGHTS}).
91
+ *
92
+ * Only valid at execute time, after the ShadowMaps and ShadowMask passes have
93
+ * populated shadowMapInfo / maskOrdinal.
94
+ */ useCombineShadowMask(ctx, shadowLight) {
95
+ if (!shadowLight || !ctx.screenSpaceShadowMask) {
96
+ return false;
97
+ }
98
+ const shadowMapParams = ctx.shadowMapInfo?.get(shadowLight);
99
+ return !!(shadowMapParams?.shadowMap && shadowMapParams.impl && shadowMapParams.maskOrdinal != null);
100
+ }
82
101
  getCombineProgramKey(ctx, shadowLight) {
83
102
  const shadowMapParams = shadowLight ? ctx.shadowMapInfo?.get(shadowLight) : null;
84
- return shadowMapParams?.shaderHash ? `shadow:${shadowMapParams.shaderHash}` : 'default';
103
+ if (!shadowMapParams?.shaderHash) {
104
+ return 'default';
105
+ }
106
+ // The mask-sampling shader is independent of the PCSS impl hash.
107
+ return this.useCombineShadowMask(ctx, shadowLight) ? 'shadowMask' : `shadow:${shadowMapParams.shaderHash}`;
85
108
  }
86
109
  requireLinearDepthTexture() {
87
110
  return true;
@@ -89,6 +112,14 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
89
112
  requireDepthAttachment() {
90
113
  return true;
91
114
  }
115
+ requireShadowMask(ctx) {
116
+ // Runs at graph-build time, before shadowMapInfo is populated (that happens
117
+ // during the ShadowMaps pass execute), so it cannot inspect the combine
118
+ // light. Keep the mask alive whenever the camera renders it; combine()
119
+ // decides at execute time whether to sample it, and _setupFromApply only
120
+ // reads the handle when the mask was actually produced this frame.
121
+ return !!ctx.screenSpaceShadowMask;
122
+ }
92
123
  apply(ctx, inputColorTexture, sceneDepthTexture, srgbOutput) {
93
124
  const device = ctx.device;
94
125
  const outputFramebuffer = device.getFramebuffer();
@@ -257,33 +288,52 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
257
288
  bindGroup.setValue('srgbOut', srgbOutput ? 1 : 0);
258
289
  if (shadowLight) {
259
290
  const shadowMapParams = ctx.shadowMapInfo.get(shadowLight);
260
- const cameraPos = ctx.camera.getWorldPosition();
261
- bindGroup.setValue('camera', {
262
- position: new Vector4(cameraPos.x, cameraPos.y, cameraPos.z, 0),
263
- params: new Vector4(ctx.camera.getNearPlane(), ctx.camera.getFarPlane(), 1, 1),
264
- shadowDebugCascades: ctx.camera.shadowDebugCascades ? 1 : 0
265
- });
266
- bindGroup.setValue('light', {
267
- sunDir: new Float32Array([
268
- sunDir.x,
269
- sunDir.y,
270
- sunDir.z
271
- ]),
272
- envLightStrength: ctx.env?.light.strength ?? 0,
273
- envLightSpecularStrength: ctx.env?.light.specularStrength ?? 1,
274
- shadowStrength: shadowLight.shadow.shadowStrength,
275
- shadowCascades: shadowMapParams.numShadowCascades,
276
- positionAndRange: shadowLight.positionAndRange,
277
- directionAndCutoff: shadowLight.directionAndCutoff,
278
- diffuseAndIntensity: shadowLight.diffuseAndIntensity,
279
- extraParams: shadowLight.extraParams,
280
- cascadeDistances: shadowMapParams.cascadeDistances,
281
- depthBiasValues: shadowMapParams.depthBiasValues[0],
282
- shadowCameraParams: shadowMapParams.cameraParams,
283
- depthBiasScales: shadowMapParams.depthBiasScales,
284
- shadowMatrices: new Float32Array(shadowMapParams.shadowMatrices)
285
- });
286
- bindGroup.setTexture('Z_UniformShadowMap', shadowMapParams.shadowMap, shadowMapParams.shadowMapSampler);
291
+ if (this.useCombineShadowMask(ctx, shadowLight)) {
292
+ // Screen-space shadow mask path: bind the mask array and select this
293
+ // light's layer/channel from its recorded ordinal (layer = s>>2,
294
+ // channel = s&3). A missing mask falls back to the fully-lit dummy.
295
+ const ordinal = shadowMapParams.maskOrdinal ?? 0;
296
+ const layer = ordinal >> 2;
297
+ const channel = ordinal & 3;
298
+ bindGroup.setValue('shadowMaskLayer', layer);
299
+ bindGroup.setValue('shadowMaskChannel', new Float32Array([
300
+ channel === 0 ? 1 : 0,
301
+ channel === 1 ? 1 : 0,
302
+ channel === 2 ? 1 : 0,
303
+ channel === 3 ? 1 : 0
304
+ ]));
305
+ bindGroup.setTexture('Z_UniformShadowMask', ctx.shadowMaskTexture ?? ShaderHelper.getDummyShadowMask(device), fetchSampler('clamp_nearest'));
306
+ } else {
307
+ const cameraPos = ctx.camera.getWorldPosition();
308
+ bindGroup.setValue('camera', {
309
+ position: new Vector4(cameraPos.x, cameraPos.y, cameraPos.z, 0),
310
+ params: new Vector4(ctx.camera.getNearPlane(), ctx.camera.getFarPlane(), 1, 1),
311
+ shadowDebugCascades: ctx.camera.shadowDebugCascades ? 1 : 0,
312
+ framestamp: ctx.device.frameInfo.frameCounter
313
+ });
314
+ bindGroup.setValue('light', {
315
+ sunDir: new Float32Array([
316
+ sunDir.x,
317
+ sunDir.y,
318
+ sunDir.z
319
+ ]),
320
+ envLightStrength: ctx.env?.light.strength ?? 0,
321
+ envLightSpecularStrength: ctx.env?.light.specularStrength ?? 1,
322
+ shadowStrength: shadowLight.shadow.shadowStrength,
323
+ shadowCascades: shadowMapParams.numShadowCascades,
324
+ positionAndRange: shadowLight.positionAndRange,
325
+ directionAndCutoff: shadowLight.directionAndCutoff,
326
+ diffuseAndIntensity: shadowLight.diffuseAndIntensity,
327
+ extraParams: shadowLight.extraParams,
328
+ implParams: shadowMapParams.impl.getParams(),
329
+ cascadeDistances: shadowMapParams.cascadeDistances,
330
+ depthBiasValues: shadowMapParams.depthBiasValues[0],
331
+ shadowCameraParams: shadowMapParams.cameraParams,
332
+ depthBiasScales: shadowMapParams.depthBiasScales,
333
+ shadowMatrices: new Float32Array(shadowMapParams.shadowMatrices)
334
+ });
335
+ bindGroup.setTexture('Z_UniformShadowMap', shadowMapParams.shadowMap, shadowMapParams.shadowMapSampler);
336
+ }
287
337
  }
288
338
  device.setProgram(program);
289
339
  device.setBindGroup(0, bindGroup);
@@ -490,6 +540,11 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
490
540
  createCombineProgram(ctx, shadowLight) {
491
541
  const shadowMapParams = shadowLight ? ctx.shadowMapInfo?.get(shadowLight) : null;
492
542
  const shadowEnabled = !!(shadowLight && shadowMapParams?.shadowMap && shadowMapParams.impl);
543
+ // When the screen-space shadow mask is available for the combine light,
544
+ // sample it instead of recomputing PCSS (which also avoids the dpdx-in-
545
+ // non-uniform-control-flow constraint entirely on this path).
546
+ const useShadowMask = this.useCombineShadowMask(ctx, shadowLight);
547
+ const pcssEnabled = shadowEnabled && !useShadowMask;
493
548
  const program = ctx.device.buildRenderProgram({
494
549
  vertex (pb) {
495
550
  this.flip = pb.int().uniform(0);
@@ -504,11 +559,12 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
504
559
  });
505
560
  },
506
561
  fragment (pb) {
507
- if (shadowEnabled) {
562
+ if (pcssEnabled) {
508
563
  const cameraStruct = pb.defineStruct([
509
564
  pb.vec4('position'),
510
565
  pb.vec4('params'),
511
- pb.float('shadowDebugCascades')
566
+ pb.float('shadowDebugCascades'),
567
+ pb.int('framestamp')
512
568
  ]);
513
569
  const lightStruct = pb.defineStruct([
514
570
  pb.vec3('sunDir'),
@@ -522,6 +578,7 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
522
578
  pb.vec4('extraParams'),
523
579
  pb.vec4('cascadeDistances'),
524
580
  pb.vec4('depthBiasValues'),
581
+ pb.vec4('implParams'),
525
582
  pb.vec4('shadowCameraParams'),
526
583
  pb.vec4('depthBiasScales'),
527
584
  pb.vec4[16]('shadowMatrices')
@@ -535,6 +592,14 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
535
592
  }
536
593
  this.Z_UniformShadowMap = shadowTex.uniform(0);
537
594
  }
595
+ if (useShadowMask) {
596
+ // Screen-space shadow mask: one RGBA8 array layer per 4 lights. The
597
+ // combine light's visibility is one channel of one layer, selected via
598
+ // the layer index and a one-hot channel selector bound at draw time.
599
+ this.Z_UniformShadowMask = pb.tex2DArray().uniform(0);
600
+ this.shadowMaskLayer = pb.int().uniform(0);
601
+ this.shadowMaskChannel = pb.vec4().uniform(0);
602
+ }
538
603
  this.colorTex = pb.tex2D().uniform(0);
539
604
  this.diffuseTex = pb.tex2D().uniform(0);
540
605
  this.blurTex = pb.tex2D().uniform(0);
@@ -708,7 +773,7 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
708
773
  this.spotFactor = pb.smoothStep(this.dirCutoff.w, pb.mix(this.dirCutoff.w, 1, 0.5), this.spotFactor);
709
774
  this.$return(pb.mul(this.spotFactor, this.falloff, this.falloff));
710
775
  });
711
- if (shadowEnabled) {
776
+ if (pcssEnabled) {
712
777
  pb.func('calculateTransmissionShadow', [
713
778
  pb.vec3('worldPos'),
714
779
  pb.float('depth01'),
@@ -776,6 +841,28 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
776
841
  this.$l.profilePreset = this.readProfilePreset(this.param);
777
842
  this.$l.depth01 = this.readDepth01(this.uv);
778
843
  this.$l.result = this.baseColor.rgb;
844
+ // Transmission shadow. On the PCSS path the shadow uses implicit
845
+ // derivatives (dpdx) inside the impl; WGSL requires those in uniform
846
+ // control flow, so it is computed here rather than inside the
847
+ // profile-active branch below (a per-pixel, non-uniform branch). On the
848
+ // shadow-mask path the value is a single texture fetch (no PCSS).
849
+ this.$l.transmissionShadowRaw = pb.float(1);
850
+ this.$l.transmissionShadow = pb.float(1);
851
+ if (pcssEnabled) {
852
+ this.$l.shadowNormalWS = this.decodeNormal(this.uv);
853
+ this.$l.shadowViewPos = this.reconstructViewPos(this.uv, this.depth01);
854
+ this.$l.shadowWorldPos = pb.mul(this.invViewMatrix, pb.vec4(this.shadowViewPos, 1)).xyz;
855
+ this.$l.shadowSunDirWS = this.calculateMainLightDirection(this.shadowWorldPos, this.mainLightType, this.mainLightPosRange, this.mainLightDirCutoff, this.sunDir);
856
+ this.transmissionShadowRaw = this.calculateTransmissionShadow(this.shadowWorldPos, this.depth01, pb.clamp(pb.abs(pb.dot(this.shadowNormalWS, this.shadowSunDirWS)), 0, 1));
857
+ this.transmissionShadow = this.transmissionShadowRaw;
858
+ } else if (useShadowMask) {
859
+ // The mask already holds the identical shadow (same PCSS + distance
860
+ // fade + shadowStrength) rendered by the ShadowMaskPass; read the
861
+ // combine light's channel. Sample by screen UV, matching how the
862
+ // other screen-space inputs (color/depth) are sampled above.
863
+ this.transmissionShadowRaw = pb.dot(pb.textureArraySampleLevel(this.Z_UniformShadowMask, this.uv, this.shadowMaskLayer, 0), this.shadowMaskChannel);
864
+ this.transmissionShadow = this.transmissionShadowRaw;
865
+ }
779
866
  this.$if(pb.and(pb.and(pb.and(pb.greaterThan(this.profileStrength, 1e-4), pb.greaterThan(this.profileSlot, 0)), this.profileActive), pb.lessThan(this.depth01, 1)), function() {
780
867
  this.$l.widthStrength = pb.clamp(this.param.g, 0, 0.999);
781
868
  this.$l.profileSettingsA = this.readProfileSettingsA(this.profileSlot);
@@ -819,11 +906,9 @@ import { AbstractPostEffect, PostEffectLayer } from './posteffect.js';
819
906
  this.$l.sunDirWS = this.calculateMainLightDirection(this.worldPos, this.mainLightType, this.mainLightPosRange, this.mainLightDirCutoff, this.sunDir);
820
907
  this.$l.mainLightAttenuation = this.calculateMainLightAttenuation(this.worldPos, this.mainLightType, this.mainLightPosRange, this.mainLightDirCutoff);
821
908
  this.$l.frontLit = pb.mul(pb.dot(this.normalWS, this.sunDirWS), this.mainLightAttenuation);
822
- this.$l.transmissionShadowRaw = pb.float(1);
823
- this.$l.transmissionShadow = pb.float(1);
824
- if (shadowEnabled) {
825
- this.transmissionShadowRaw = this.calculateTransmissionShadow(this.worldPos, this.depth01, pb.clamp(pb.abs(pb.dot(this.normalWS, this.sunDirWS)), 0, 1));
826
- }
909
+ // transmissionShadowRaw/transmissionShadow were computed in uniform
910
+ // control flow at the top of main (PCSS sampling uses dpdx, which
911
+ // WGSL forbids inside this non-uniform branch); reuse them here.
827
912
  this.transmissionShadow = this.transmissionShadowRaw;
828
913
  this.$l.transmissionLightAttenuation = pb.mul(this.mainLightAttenuation, this.transmissionShadow);
829
914
  this.$l.thinnessComponents = this.estimateScreenThinnessComponents(this.uv, this.depth01, this.normalWS, this.radiusResponse);