Skip to content
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

Unreal Bloom Scene Brightness Issue #14899

Closed
10 tasks
maximcapra opened this issue Sep 12, 2018 · 22 comments
Closed
10 tasks

Unreal Bloom Scene Brightness Issue #14899

maximcapra opened this issue Sep 12, 2018 · 22 comments

Comments

@maximcapra
Copy link

Description of the problem

I am using Unreal Bloom in my current project, but I am having problems finding the right parameters. As soon as I add the effect to the EffectComposer, the scene brightens due to the additive behaviour of the effect. Even when I turn the .strength variable to zero, the scene doubles in brightness. Icould not find a way to modify UnrealBloomPass.js so that it behaves more correct.

Bloom Off, Strength: 0
bloom_off

Bloom On, Strength: 0

bloom_on

I am not able to get a nice result in my scene, the scene is always too bright and doesn't look linear anymore as soon as I turn on the bloom effect. There must be a way to preserve the linear luminance values in the scene with an additional bloom effect on top, like I am used to from other packages like Unreal, After Effects, ....

  • Dev
  • [x ] r96
  • ...
Browser
  • All of them
  • [x ] Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • [x ] Windows
  • macOS
  • Linux
  • Android
  • iOS
@maximcapra
Copy link
Author

I should add, also when using the threshold parameter to restrict the bloom effect to higher luminance values, the scene brightens up in the other areas, too .....

@maximcapra
Copy link
Author

To illustrate it further:

Scene without bloom
scene

Scene with bloom. I have set
this.highPassUniforms[ "smoothWidth" ].value = 0.2;
and
blending: THREE.NormalBlending,
just to have a nicer falloff and to have a look at the bloom layer itself
scene_normal

As soon as I reset blending back to THREE.AdditiveBlending this happens:
scene_additive

@WestLangley
Copy link
Collaborator

Even when I turn the .strength variable to zero, the scene doubles in brightness.

If the scene brightness increases when the bloom strength is zero, that would seem to indicate that the algorithm is not implemented correctly.

@maximcapra
Copy link
Author

I somehow managed to alter UnrealBloomPass.js so that it works for my needs. I am sure there is more to it, as I don't fully understand what is going on in this file, but I figured, there is something wrong with the texture on the quad.material, where the blurred texture gets added. So I added the following line at line 205 in the if( this.renderToScreen ) section:

this.basic.map.encoding = THREE.sRGBEncoding;

Now the basic texture looks right again and the bloom is added on top. See the difference compared to the result at my previous post:

scene_corrected

Someone with more insight should jump in and fix the code the right way ...

@WestLangley
Copy link
Collaborator

Can you please provide a live link to your demo so we can see what you are doing at the application level?

Is the output of your render pass in linear space?

@maximcapra
Copy link
Author

maximcapra commented Sep 12, 2018

Sure:
http://maximcapra.com/threejs_testbed - deleted from server
This is already with the fixed UnrealBloom.js

EDIT:
Here is the same version with the original UnrealBloom.js
http://maximcapra.com/threejs_testbed_bkp - deleted from server

Actually the same problem is in the example file:
https://threejs.org/examples/webgl_postprocessing_unreal_bloom.html

If you turn off the bloom in the example file the brightness (gamma) of the rendering is different compared to the rendering with the effect (even with strength 0). (You need to make a copy, there is no option to turn of the effect in the example, so nobody really noticed the problem I think) There is definitely a problem with linear/sRGB gamma hidden somewhere in the renderchain.

@WestLangley
Copy link
Collaborator

As I hypothesized, in your demo the output from the render pass is not in linear space, since you have set

renderer.gammaOutput = true;

Hacking the bloom pass by setting

this.basic.map.encoding = THREE.GammaEncoding;

should invert that.

Without investigating this further, I am not sure of the best place to apply gamma-correction in this particular case: before or after post-processing.

@maximcapra
Copy link
Author

I see, thanks for having a look!

I thought I tried turning gamma correction off before applying the effect ... o.0 but it works as expected with a linear render.

Usually I would try to stay linear as long as possible and just apply a gamma or lut right before viewing on screen, so after post processing and everything else. How would you apply this after post processing? Is there a way without impacting performance too much?

@maximcapra
Copy link
Author

Also I think the effect should work with a gamma corrected render as well, what comes in, should come out, so the effect should always do it's thing in a linear manner without applying additional stuff ... just my 2 cents ...

@WestLangley
Copy link
Collaborator

/ping @spidersharma03

I think the following are reasonable expectations:

  1. This effect should support the addition of GammaCorrectionPass for linear input, if it doesn't already.
  2. This effect should also support gamma-corrected input without over-brightening.

@mrdoob mrdoob added this to the rXX milestone Oct 22, 2018
@looeee
Copy link
Collaborator

looeee commented Apr 15, 2020

This issue can be fixed by adding a linear to sRGB pass after the Bloom pass.

Here's the example with no gamma pass. Left is Bloom disabled, right is bloom with strength 0. Clearly there's a difference in brightness:

no_gam

Here's the example with a gamma pass. Left is Bloom disabled, right is bloom with strength 0. No difference in brightness:

yes_gam

Probably every post-processing example should have a GammaCorrectionPass.

@mrdoob
Copy link
Owner

mrdoob commented Apr 20, 2020

@looeee Is that comment still valid after what was discussed in #19139?

@looeee
Copy link
Collaborator

looeee commented Apr 20, 2020

Probably every post-processing example should have a GammaCorrectionPass.

This comment? I believe so, probably for every example that renders using the EffectComposer.

However, before proceeding with this, we need to figure out what causes the color banding discussed in the other thread. As you can see in this forum post, other people have encountered this too.

@mrdoob
Copy link
Owner

mrdoob commented Apr 20, 2020

The banding is probably because the render targets are not floating point?

@looeee
Copy link
Collaborator

looeee commented Apr 20, 2020

Unfortunately, that does not reduce banding in this case. Not even when I use FloatType for both EffectComposer and BloomPass UnrealBloomPass render targets 😕

There's some discussion of bloom, tone mapping, and banding here:

https://www.gamedev.net/forums/topic/588388-glarebloom-effect-what-you-use/

One person suggested to do the tone mapping only after bloom, which I had also tried yesterday:

renderer.toneMapping = NoToneMapping;

composer.addPass( bloomPass );
composer.addPass( acesFilmicPass );
composer.addPass( gammaCorrectionPass ); 

However, this just reduces banding. It's not completely gone.

@looeee looeee closed this as completed Apr 20, 2020
@looeee looeee reopened this Apr 20, 2020
@KoltesDigital
Copy link
Contributor

KoltesDigital commented May 5, 2020

I also had ugly color banding using UnrealBloomPass followed by a ShaderPass(GammaCorrectionShader). It disappeared when I set both EffectComposer's and UnrealBloomPass's render targets to FloatType or even HalfFloatType. Setting FloatType only on EffectComposer's render targets does not change anything. Setting FloatType only on UnrealBloomPass's render targets makes the bands clean and rounded (but they are still clearly present).

@looeee you're mentionning BloomPass and not UnrealBloomPass. Did you confuse both by mistake?

@looeee
Copy link
Collaborator

looeee commented May 5, 2020

@looeee you're mentionning BloomPass and not UnrealBloomPass. Did you confuse both by mistake?

Yes, my apologies. I'm referring to UnrealBloomPass exclusively.

@KoltesDigital
Copy link
Contributor

KoltesDigital commented May 5, 2020

Ok then another diff with you is acesFilmicPass, can you please show its declaration? I've added a tone mapping, here is my post process stack:

const bloomPass = new UnrealBloomPass(new THREE.Vector2(128, 128), 1.5, 0.4, 0);
composer.addPass(bloomPass);

const hdrToneMappingPass = new AdaptiveToneMappingPass(false, 256);
composer.addPass(hdrToneMappingPass);

composer.addPass(new ShaderPass(GammaCorrectionShader));

And I see no color bands neither (when using the patched render targets).

@looeee
Copy link
Collaborator

looeee commented May 5, 2020

I wrote my own ACESFilmicPass using the approximation here:

vec3 ACESFilmicToneMapping( vec3 color ) {
color *= toneMappingExposure;
return saturate( ( color * ( 2.51 * color + 0.03 ) ) / ( color * ( 2.43 * color + 0.59 ) + 0.14 ) );
}
`;

Since then @WestLangley added an ACESFilmicPass using a different approximation in #19196. I haven't tested that one.

@KoltesDigital
Copy link
Contributor

Hm hard to tell then.

In my case, it's solved by setting the renderers' type to float. While EffectComposer let us use a custom renderer, UnrealBloomPass does not, i.e. there's currently no way to fix the banding, the file has to be edited.

I suggest to add a new optional parameter to the UnrealBloomPass in order to customize the inner renderers' parameters. However, I believe this would benefit most passes as well: users will want to customize based on their needs, maybe someone is doing a mobile site and would prefer to tweak most passes.

Another issue is the number and order of parameters in the pass constructors. Some time ago, in this typical case of functions taking multiple parameters without any logical order because these parameters are actually to become the object's inner state, I started to use a single object parameter instead: it allows parameters to be unordered, any of them can be optional, and their name has to be explicited. I believe this increases the code quality overall. For instance, compare

new UnrealBloomPass(new THREE.Vector2(128, 128), 1.5, 0.4, 0)

with

new UnrealBloomPass({
  resolution: new THREE.Vector2(128, 128),
  strength: 1.5,
  radius: 0.4,
  threshold: 0,
})

which I think is clearer. But my main point is not code quality, but extensibility. With an object, we can add new parameters at any time, without breaking any code. We could then add a parameter for the renderer type:

new UnrealBloomPass({
  resolution: new THREE.Vector2(128, 128),
  strength: 1.5,
  radius: 0.4,
  threshold: 0,
  rendererType: THREE.FloatType,  // <--
})

or even a full parameter object:

new UnrealBloomPass({
  resolution: new THREE.Vector2(128, 128),
  strength: 1.5,
  radius: 0.4,
  threshold: 0,
  rendererParameters: {
    type: THREE.FloatType,
  },
})

which would be merged to default parameters in the constructor:

const parameters = Object.assign({ ... }, options.rendererParameters);

In order to do the transition, we may sadly use ugly tricks like if (arguments.length === 1 && typeof arguments[0] === 'object' && arguments[0]) ... so that the current syntax and the proposed syntax both work.

To summarize, I suggest:

  1. to change all pass constructors to a unified way to set their initial values using a single object parameter instead of multiple ordered parameters,
  2. to add an optional rendererParameters field in this object parameter to customize how pass renderers are created.

Can you please comment?

@looeee
Copy link
Collaborator

looeee commented May 10, 2020

In my case, it's solved by setting the renderers' type to float.

I suggest to add a new optional parameter to the UnrealBloomPass in order to customize the inner renderers' parameters.

I guess by renderer you mean render target?

Yes, I edited the UnrealBloomPass when testing this. In total, I think there were three places I set the type - the effect composer, then two targets in UnrealBloomPass.

to add an optional rendererParameters field

Should be rendererTargetParameters . But rather than adding this, we could read the type from the effect composer and use that? I assume that in most cases you'll want the same type throughout post, at least up until tone mapping.

Do you want to create a new PR based on #19139? I still think that my approach was correct except for the banding issue. It would be good to have a working demo of using float type to fix banding.

Repository owner deleted a comment from 8562056816031 Feb 28, 2021
Repository owner deleted a comment from 8562056816031 Feb 28, 2021
Repository owner deleted a comment from 8562056816031 Feb 28, 2021
@Mugen87
Copy link
Collaborator

Mugen87 commented Jun 9, 2023

This issue should be fixed in the latest release. The FX pipeline is using half-float render targets by default and all post-processing examples output to sRGB now. The unreal bloom demo specifically uses the new OutputPass class which does tone mapping + sRGB color space conversion in one step.

So the topic color space, tone mapping and banding in context of post processing should be solved now.

Latest unreal bloom demo: https://threejs.org/examples/webgl_postprocessing_unreal_bloom

If someone ever experiences a blending issue with unreal bloom pass, this might be related to premultiplied alpha (see #26185).

@Mugen87 Mugen87 closed this as completed Jun 9, 2023
@Mugen87 Mugen87 removed this from the r??? milestone Jun 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants