-
-
Notifications
You must be signed in to change notification settings - Fork 36.1k
WebGLRenderer: Improve HDR handling for additive blending #32433
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
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
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
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
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.
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.
Why is this approach just used for additive blending and not for all use cases?
Uh oh!
There was an error while loading. Please reload this page.
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.
@WestLangley Does this change interfere when
premultipliedAlphais set totrue?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.
There is something wrong with the model. Additive blending seems to have been added to the example after-the-fact. We have techniques to render glass correctly using normal blending.
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 tried using
transmissionbut the render is not as crisp (compare ROLEX and the text under):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.
@Mugen87
Here you go:
Additive Blending & Pre-multiplication
Three approaches, same blend result, different tone mapping:
(rgb, 0.4)src * srcAlpha + dstrgb * 0.4 + dsttoneMap(rgb)then* 0.4in blendpremultipliedAlpha: true(rgb, 0.4)src * 1 + dstrgb + dsttoneMap(rgb)— alpha ignored!BLENDING_ADDITIVEshader(rgb * 0.4, 1.0)src * srcAlpha + dstrgb * 0.4 + dsttoneMap(rgb * 0.4)Why only additive blending?
For normal alpha blending (
src * a + dst * (1-a)), pre-multiplying in the shader would square the alpha — breaking the math. Additive blending only uses alpha as a source multiplier, so moving the multiplication into the shader works.The core problem:
WebGL blending happens after the fragment shader. So tone mapping (in shader) always happens before blending. There's no way to blend in HDR space without post-processing.
The
BLENDING_ADDITIVEchange moved the* alphabefore tone mapping, which changes the visual result becausetoneMap(x) * a ≠ toneMap(x * a).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.
Hm... the words sound plausible, but I'm having a difficult time anchoring them to fundamentals I understand. Does this make sense to others, and/or do we have a reference beyond the LLM? Notably, if I put "premultiply alpha before tonemapping" or "why not premultiply alpha before tonemapping" into one, it is very happy to respond with well-written words arguing that the opposite choices are correct, preferred, and conventional.
The change is similar enough to tone mapping in a later pass, so that's encouraging, but turning it on globally for additive blending, and without reference to
material.premultipliedAlpha, is confusing me.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.
This is what I'm trying to solve:
BLENDING_ADDITIVEpremultiplies the light contribution andmaterial.premultiplyAlphais about the asset itself:Uh oh!
There was an error while loading. Please reload this page.
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.
This isn't correct. "Additive blending" is additive color and alpha - the alpha cannot just be set to 1.0 because the opacity has already been applied to the rgb channels. This change will break any additive blending on a transparent background. From the "webgl materials blending" demo with "alpha:true" setting passed to WebGLRenderer and a clear background color:
The AI response doesn't make sense to me, either. The only reason you'd only apply this to additive blending is because it would be more obviously wrong in all other blending conditions. If you want to premultiply the alpha before applying tone mapping then we should use premultiplied alpha. And move the tone mapping stage after the "premultiplied alpha" operation (it's currently before). This change is really just adding in premultiplied alpha only for additive blending (with incorrect blend states set) even when the setting is false.
Fundamentally this is an issue of mapping a color to [0, 1] and then multiplying alpha into the color before blending. This will happen with non-tonemapped materials if premultiplied alpha is set to false, as well, since the graphics API will clamp the color before blending. You can see the effect in this fiddle with 25% opacity transparent spheres:
left: toneMapped=false, premultipliedAlpha=false, middle: toneMapped=false, premultipliedAlpha=true, right: toneMapped=true, premultipliedAlpha=true
You'll see that the "tone mapped" sphere has the same dull highlight as the non-premultiplied alpha sphere because it tonemaps the color to [0, 1] before applying alpha, as the graphics API does when blending.
Regarding whether it's "correct" to perform tonemapping before or after applying alpha - I don't have any strong opinions. But I believe it's the only way to avoid this problem in a forward rendering shader (unless our tone mapping functions will map to a range outside of [0, 1] which is a different discussion). Really you want to tone map the color after it's been blended to a final color on the screen (eg a postprocessing effect) so either way I think we're dealing with a compromise.
If this is something we want to improve I think we should look at rearranging the order of these shader fragments, though I know these have been arranged in this way for reason:
edit
I'm generally seeing this kind of thing, as well, with other topics 😅 it can sound very convincing if a topic is unfamiliar and this premultiplied alpha topic is fairly complicated, I think.
Uh oh!
There was an error while loading. Please reload this page.
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.
Just did another PR that moves premultiplied_alpha before tonemapping: #32449
Seems like the right solution indeed.
Although it's definitely not great that the developer needs to know and set
premultiplyAlpha: trueif they want aopacity: 0.5material to not get clamped IBL.Edit:
Oh good. Was just working on just that before I saw your post.