Fix volumetric fog missing for one frame after a canvas resize - #9283
Merged
Conversation
The fog combine pass renders into rtSceneColor, an alias of the scene render target wrapping the same color texture without the scene depth attachment it samples. That alias has no pass of its own to resize it, so the camera frame pass resized it from the scene render target's dimensions - but FrameGraph.addRenderPass updates a frame pass before the passes it owns, and the scene render target is resized by the scene pass, one of them. On the frame the canvas resized, the alias was therefore resized to the previous size, and the following this.rt.resize() replaced the shared texture's GPU object while the alias kept a framebuffer attached to the one it replaced. The combine pass drew the fog into an orphaned surface nothing samples, with a stale viewport. Evaluate the size the same way the scene pass evaluates it instead of reading it back a frame stale.
Build size reportThis PR changes the size of the minified bundles.
|
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The change is small, localized, and aligns the alias sizing logic with the existing render-pass resize evaluation to eliminate the observed one-frame resize hazard.
Pull request overview
This PR fixes a one-frame loss of volumetric fog immediately after a canvas resize by ensuring the “scene color only” alias render target (used when sampling scene depth) is resized based on the same resize inputs as the scene pass, rather than reading stale dimensions from the scene render target.
Changes:
- Compute
rtSceneColorresize dimensions from the scene pass’resizeSourceandscaleX/scaleY(matchingRenderPass.frameUpdatesizing logic). - Avoid a stale-size resize that could orphan the fog combine pass’ framebuffer attachment for the resize frame.
File summaries
| File | Description |
|---|---|
| src/extras/render-passes/frame-pass-camera-frame.js | Resizes the scene-color alias using the scene pass’ resize inputs to prevent a one-frame mismatch after canvas resize. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The volumetric fog examples lose the fog for exactly one frame right after the window is resized.
With the volumetric fog enabled,
CameraFramerenders the scene depth as an additional attachment of the scene render target. The fog combine pass samples that depth, so it cannot render into the render target it is attached to, and renders intortSceneColorinstead - an alias wrapping the same color texture without the depth. That alias has no pass of its own to resize it, soFramePassCameraFrame.frameUpdateresized it from the scene render target's dimensions.FrameGraph.addRenderPassupdates a frame pass before the passes it owns, though, and the scene render target is resized by the scene pass - one of them. On the frame the canvas resizes the alias was therefore resized to the previous size, and thethis.rt.resize()which followed replaced the shared texture's GPU object while the alias kept a framebuffer attached to the one it replaced. The combine pass drew the fog into an orphaned surface nothing samples, with a stale viewport. This failed silently, ascheckFramebufferStatusstill reports the framebuffer as complete - WebGL keeps a deleted but attached texture alive.Changes:
Verified on WebGL2 by stepping the frame graph one frame at a time across a resize, growing and shrinking: the alias' framebuffer now keeps the live texture and its viewport matches, and a canvas readback on the resize frame matches the frame which follows it rather than a fog-disabled reference.