Skip to content

Render the scene depth from the scene pass, replacing the depth prepass where possible - #9174

Merged
mvaligursky merged 2 commits into
mainfrom
mv-scene-texture-producer
Aug 14, 2026
Merged

Render the scene depth from the scene pass, replacing the depth prepass where possible#9174
mvaligursky merged 2 commits into
mainfrom
mv-scene-texture-producer

Conversation

@mvaligursky

Copy link
Copy Markdown
Contributor

CameraFrame can now render the scene depth as an additional attachment of the scene render target, alongside the scene color, instead of by a depth prepass. This is both cheaper and more capable.

Cheaper, because the depth prepass is a second geometry pass over every opaque mesh the camera renders, and for the common configurations it disappears entirely - volumetric fog, depth of field, TAA and SSAO all consume the depth only after the scene has been rendered, so the scene pass can produce it as a by-product for the cost of one attachment write. On the examples this removes the prepass from volumetric fog, TAA, the shadow catcher and SSAO in combine mode.

More capable, because the blended geometry contributes to it. Gaussian splats accumulate a transmittance weighted depth as they render, which a prepass cannot produce at all, so the effects using the depth become bounded by the splats instead of drawing through them. That is opt-in per scene, as it costs the attachment for the whole scene pass.

Changes:

  • CameraFrame derives which producer to use rather than exposing a setting. The depth is rendered by the scene pass when only the post-processing passes consume it. When something needs it earlier - the materials, via rendering.sceneDepthMap, or SSAO applied during shading - the prepass is kept, and the scene pass additionally renders it only when the splats are set to contribute.
  • GSplatParams.sceneDepthWrite turns the splat contribution on, defaulting to false. CameraFrame.isSplatSceneDepthSupported reports whether a device can do it, so an application can disable those effects on the ones which cannot.
  • SSAO in combine mode now runs after the scene pass rather than before it. Only SSAO applied during shading has to be generated first, as the lit shaders sample its texture; applied by the compose pass it is free to run later, where its depth can come from the scene pass and no prepass is needed. Lighting mode is unchanged.
  • The scene passes publish the depth they rendered from their after, mirroring how the depth prepass publishes its own, so the passes consuming it sample whichever producer ran later in the frame. Only the last pass rendering to the scene render target publishes, as exposing an attachment which the remaining passes still render into would let the materials they render sample it.
  • The depth is rendered as R32F, or as R16F where 32 bit float blending is unavailable. Half float is only used when the splats are contributing, since otherwise the prepass stores the depth more precisely - as R32F, or losslessly packed into RGBA8 - and the effects consuming it are sensitive to that.
  • The scene pass is not used where it cannot render the depth correctly, in which case the prepass serves as before: with multi-sampling, without independent blending, without a blendable floating point format, when the camera does not clear the whole of its render target, and when a prepass which packs the depth would run alongside. A debug build warns, naming the reason, when gaussian splats end up not contributing.
  • examples/graphics/depth-of-field disables multi-sampling when TAA is enabled, matching the ambient occlusion example. It was paying for both.

API Changes:

  • GSplatParams#sceneDepthWrite - new, whether the gaussian splats contribute to the scene depth. Defaults to false.
  • CameraFrame.isSplatSceneDepthSupported(device) - new static, whether a device can render the scene depth the splats contribute to.

Nothing changes for a camera whose configuration consumes no depth. Verified on both backends across the examples using CameraFrame, including the two-scene-pass case with a color grab pass, partial viewport cameras, and a device emulated as having no float blending to exercise the half float path and the packed prepass coexistence.

@github-actions

Copy link
Copy Markdown

Public API report

This PR changes the public API surface (+2 / −0), per the docs' rules (@ignore / @Private / undocumented are excluded).

Show API diff
+CameraFrame.static isSplatSceneDepthSupported(device: GraphicsDevice): boolean
+GSplatParams.sceneDepthWrite: boolean

Informational only — this never fails the build.

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2364.1 KB (+3.3 KB, +0.14%) 607.2 KB (+1.0 KB, +0.16%) 471.6 KB (+0.9 KB, +0.18%)
playcanvas.min.mjs 2361.5 KB (+3.3 KB, +0.14%) 606.2 KB (+1.0 KB, +0.16%) 471.0 KB (+0.8 KB, +0.17%)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Moves post-process depth generation into the scene pass where supported, avoiding redundant geometry prepasses.

Changes:

  • Adds scene-depth attachments and publication.
  • Adds optional Gaussian splat depth contribution.
  • Reorders combined SSAO and adjusts the DOF example’s MSAA/TAA settings.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/scene/renderer/render-pass-forward.js Publishes generated scene textures.
src/scene/gsplat-unified/gsplat-params.js Adds the splat depth-write option.
src/scene/constants.js Maps scene textures to uniforms.
src/extras/render-passes/frame-pass-camera-frame.js Selects and configures depth producers.
src/extras/render-passes/camera-frame.js Exposes device support detection.
examples/src/examples/graphics/depth-of-field.example.mjs Avoids combining TAA with MSAA.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/scene/gsplat-unified/gsplat-params.js
Comment thread src/extras/render-passes/frame-pass-camera-frame.js
Comment thread src/extras/render-passes/frame-pass-camera-frame.js Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/extras/render-passes/frame-pass-camera-frame.js:299

  • This warning also fires when TAA or combine-mode SSAO is the only depth consumer, but it specifically says volumetric fog and depth of field are affected even when both are disabled. Please describe the active consumers dynamically, or use a generic message such as “effects using scene depth cannot account for the splats,” so the remediation is not misleading.
                Debug.warnOnce(`CameraFrame: the gaussian splats this camera renders do not contribute to the scene depth, and so the effects using it (the volumetric fog and the depth of field) are not bound by them: ${reason}.`);

@mvaligursky
mvaligursky merged commit 85765ba into main Aug 14, 2026
11 checks passed
@mvaligursky
mvaligursky deleted the mv-scene-texture-producer branch August 14, 2026 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants