cx20 / gltf-test

Testing the glTF Loader and WebGL Library
https://cx20.github.io/gltf-test/
348 stars 43 forks source link

Make three.js bloom effect similar to Babylon.js #621

Open cx20 opened 2 years ago

cx20 commented 2 years ago

I added a bloom effect to the three.js sample. However, the display result is slightly different from Babylon.js. If possible, I would like to make adjustments so that the display results are the same.

Library result
Babylon.js + EmissiveStrengthTest image
three.js + EmissiveStrengthTest.gltf image

Edit 2022-09-23 I fixed it because the link destination was localhost.

emackey commented 2 years ago

@elalish Any thoughts here? It looks like ThreeJS is blooming the clamped white color, not the original emission color. Is there a way to do otherwise?

elalish commented 2 years ago

Interesting; I haven't played with three's bloom shader yet, but I would hazard a guess that perhaps tone mapping is being applied before the bloom pass instead of after? That might also explain why the right two cubes look almost the same. Perhaps it just isn't using a floating-point framebuffer for the intermediate draw, so all the values are getting clamped? @mrdoob in case he has any pointers.

cx20 commented 2 years ago

I used the following example as a reference for Bloom's implementation.

https://threejs.org/examples/webgl_postprocessing_unreal_bloom.html https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing_unreal_bloom.html

However, I didn't know how to use toneMapping correctly, so now I use THREE.NoToneMapping. https://github.com/cx20/gltf-test/blob/a171346766c8cd168e62bb53f7101ebf9fa592f7/examples/threejs/index.js#L101-L106

cx20 commented 2 years ago

I tried changing the toneMapping to use THREE.ReinhardToneMapping.

const params = {
    exposure: 1,
    bloomStrength: 1.0,
    bloomThreshold: 0.6,
    bloomRadius: 0.5
};

renderer.toneMapping = THREE.ReinhardToneMapping; 
Library result
before image
after image
elalish commented 2 years ago

Ah, that makes sense; without tone mapping you lose all this HDR info to clamping. One note: ACESFilmicToneMapping has become a bit of an industry standard, so you might want to go with that.

Using tone mapping is quite important for PBR rendering generally, not just for bloom. Take a look at my article.

cx20 commented 2 years ago

@elalish Thanks for all the advice. I'm experimenting with ACESFilmicToneMapping now. I am trying different parameters but Bloom's emission color seems to be white. Any advice?

ToneMapping result
NoToneMapping
bloomStrength: 0.5,
bloomThreshold: 0.9,
bloomRadius: 0.5
image
ReinhardToneMapping
bloomStrength: 1.0,
bloomThreshold: 0.6,
bloomRadius: 0.5
image
ACESFilmicToneMapping
bloomStrength: 0.6,
bloomThreshold: 0.9,
bloomRadius: 0.0
image
cx20 commented 1 year ago

I have created the following sample to facilitate comparison of the effects of Tonemapping and Bloom. three.js Bloom Test https://jsfiddle.net/cx20/x1g2j07y/ image

ToneMapping Bloom Off Bloom On
No image image
Reinhard image image
ACES Filmic image image
cx20 commented 1 year ago

I have tried the same combination of tone mapping and Bloom in Babylon.js as well. Babylon.js Bloom Test https://jsfiddle.net/cx20/ky0tcgr6/ image

ToneMapping Bloom Off Bloom On
None image image
Standard image image
ACES image image
elalish commented 1 year ago

I'd say Babylon looks more like I'd expect here; this looks like enough info to file a bug on three.js, especially if you include a link to your code. ACES pulls bright colors toward white, but the fact that the whole bloom looks white makes me think it doesn't have the right shape of exponential fall-off in intensity.

cx20 commented 1 year ago

When I upgraded three.js from r152 to r153, the effect of Bloom became dazzling. It might be a usage issue, but I haven't found a solution yet.

model three.js r152 three.js r153
EmissiveStrengthTest image image