-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WebGLRenderer: Fix incorrect background color space when setting scene.background to color #28434
Conversation
…e background color
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
@@ -1430,7 +1430,8 @@ class WebGLRenderer { | |||
samples: 4, | |||
stencilBuffer: stencil, | |||
resolveDepthBuffer: false, | |||
resolveStencilBuffer: false | |||
resolveStencilBuffer: false, | |||
colorSpace: ColorManagement.workingColorSpace, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, it hadn't occurred to me that the default color space of a render target is THREE.NoColorSpace
! Good catch, and I expect that there my be some other places we may need to fix similar issues.
src/renderers/WebGLRenderer.js
Outdated
const renderBackground = xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false; | ||
if ( renderBackground ) background.render( scene ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand the motivation for this part of the change, why would XR presentation and depth sensing affect whether the background is drawn?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know the history of some of these decisions, unfortunately - just that it's already done elsewhere in WebGLRenderer to determine whether to draw the background. There's probably some clean up that should happen in the render function in this respect.
See https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L1156
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok! I don't know much about that part but will approve the PR in any case, thanks again!
src/renderers/WebGLRenderer.js
Outdated
@@ -1461,6 +1462,9 @@ class WebGLRenderer { | |||
|
|||
_this.clear(); | |||
|
|||
const renderBackground = xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind passing the existing renderBackground
flag from the render()
method into renderTransmissionPass()
. In this way, it's not necessary to make the same evaluation twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also consider to rename it to _renderBackground
and store it in the same scope like _clippingEnabled
. Then it is not necessary to change the signature of renderTransmissionPass()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
I think it didn't at all. Before #28118, the background was renderer to the default framebuffer (or current bound render target) before any render pass were executed. This approach introduces performance issue though as explain in #28118. Now, the background is rendered after the transmission pass. However, before and after #28118 the background was never rendered with the transmission render target bound. This should be corrected with this PR. |
Sounds good - as I mentioned previously I'm a bit confused by some of the logic relating to the transmission pass and I don't know enough about the reasoning to make changes to it. This code block, for example, is really odd to me: _this.getClearColor( _currentClearColor );
_currentClearAlpha = _this.getClearAlpha();
if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );
_this.clear(); Why are we forcing a 50% transparent white background if the background is at all partially transparent of any color, for example? |
The reasoning behind this is explained in #25819. |
Clean up.
@@ -1461,6 +1464,8 @@ class WebGLRenderer { | |||
|
|||
_this.clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reading the code again I think _this.clear();
can be removed now. Otherwise clear()
is effectively called twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous approach only honored the clear color set via setClearColor()
. But if you trigger the clear indirectly via background.render( scene )
, then both clear color and Scene.background = new Color()
are honored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's necessarily the case? Again the rationale behind the current transmission clearing logic isn't super clear to me and may deserve some more comments (especially for the white clear color, for example). If renderBackground
is set to false then this call to "clear" will still be run, for example. I guess it can at least go in an "else" branch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If renderBackground is set to false then this call to "clear" will still be run, for example. I guess it can at least go in an "else" branch?
That makes sense. This particular clear should be retained in XR.
Related issue: #28423
Description
Previously the transmission buffer was rendering the background with an incorrect color space causing it to be lighter. I'm not entirely clear where the background color was being rendered for the transmission pass previously. Here's a demo showing the incorrect colors through a transmissive object.
background.render
when rendering the transmission pass which converts the color apropriately.Edit: Possibly related to #28118, as well?