Postprocessing selective bloom

Hi,

I’ve been trying to figure out how to use postprocessing for selective bloom. Now I’ve created two cubes where the red cube is supposed to bloom and the green cube should’nt bloom. When I have set the renderer background color to black, it works perfectly (the red cube has bloom and the green cube doesn’t). But when I change the renderer background color to white, both cubes have some kind of bloom even though I use selective bloom on just the red cube. Does anyone know why this happens and how I could fix this?

https://codesandbox.io/p/sandbox/wandering-morning-sv4jd2

Thanks in advance!

you don’t need selectivebloom, bloom is selective out of the box, this is what luminianceThreshold is for. if you set it to 1 that means nothing glows because RGB is between 0-1. if any color now goes beyond the threshold it glows.

ps keep in mind that threejs does not support tonemapping for rendertargets any longer. you’re not running acis. tonemapping should be “THREE.NoToneMapping” and you would render ToneMappingEffect last.

Then when is selective blooming used? The sandbox I added was as an example since we use different glb files with multiple meshes where we want to bloom for example one mesh. The meshes have base color materials where the color is always #ffffff. That’s why we wanted to use selective blooming to bloom only part of the model. We want to achieve something like the following:
https://codesandbox.io/p/sandbox/diamond-refraction-forked-5l97d6?file=%2Fsrc%2FApp.js

The shader and all we got, but now we’re looking at blooming. So for example we have a ring with multiple meshes (one mesh for the diamond and one for the ring itself) where we want the diamond to bloom but not the rest of the ring.

Here is mine (updated with the diamond glb):
https://codesandbox.io/p/sandbox/new-selectivebloom-sv4jd2?file=%2Fsrc%2FApp.js%3A37%2C31

selecticebloom doesn’t change how bloom works. bloom can make any mesh you want glow, just push the color outside RGB or use material.emissive + material.emissiveIntensity which is the true purpose of these properties. if you use glow in blender and export as glb it gets stored as emissive. this is what bloom is built for and that is why it has a threshold. all that selectivebloom does is limiting this to specific meshes but since bloom is selective ootb it doesn’t really have a purpose.

if you want the diamond to glow, either give it emissive intensity in blender and export, or make it emissive afterwards by setting it on the material by code. the beauty of this is that everything can easily be controlled by these properties without any extra effort.

diamondMaterial.emissive = new THREE.Color("red")
diamondMaterial.emissiveIntensity = 10

ps read this https://twitter.com/0xca0a/status/1623725819997704193

and here’s an example of a glb with emissive materials (emissiveMap in this case, another property which allows you to affect not the whole material but portions of it)

I’ve been trying different things, but I still can’t figure it out completely.
When I have a diamond shader as material I can add the emissive, but you need to set a color to the emissive which means my diamond shader gets a color which isn’t supposed to happen. How do I combine these two?

a diamond shader shouldn’t be emissive, it’s supposed to refract and reflect. why use what is possibly the most expensive shader ever and just make it glow.

https://codesandbox.io/p/sandbox/diamond-refraction-zqrreo

https://codesandbox.io/p/sandbox/diamond-ring-3ywzzx?file=%2Fsrc%2Findex.js

The thing is, we want the diamond to bloom. The diamond shader doesn’t have that included (as far as I know) so that’s why we’re looking for ways to do this in vanilla js. Right now we have a ring where we try to bloom the diamond but not the rest of the ring, but unfortunately it blooms the whole ring with BloomEffect.

bloom has little to do with vanilla or even the shader material. it blooms if the color of the material goes over the specified threshold. if you have threshold 1 (nothing glows) and the diamond material goes over RGB 1, say: material.color.set(100, 100, 100) then it will glow.

You are right.

So we have this (without bloom):

But we want it to be like this (with bloom):

but we can’t figure out how to do this
(https://codesandbox.io/p/sandbox/diamond-refraction-forked-cggr6l?file=%2Fsrc%2FApp.js%3A62%2C51)

threejs had some breaking changes i guess that’s what you’re up against. i refreshed all the dependencies and added the migration steps of the diamond sandbox i posted above.

When I look at this example you gave: https://codesandbox.io/p/sandbox/diamond-ring-3ywzzx?file=%2Fsrc%2FApp.js%3A20%2C93-20%2C96 I see that when the frame is for example white, it blooms. So that means that threshold 1 means that if the color is rgb(1,1,1) it will bloom AND everything that goes over 1 will also bloom?

We also have a ring and other assets like that where we have a frame and a diamond. Our frame has a roughness which makes the frame always bloom, doesn’t matter what the color is (except black ofc). So somewhere the roughness and metalness are connected to bloom. But we want to avoid the frame from blooming while having a light color. So how can we have a white frame, keep the roughness but not have it bloom?

I’m looking into this as well, and I’m getting some seemingly unexpected results.
It is my understanding that any value above the threshold should trigger the bloom effect, but using the basic cube example you posted the r value is set to 5.
After some experimentation, it seems it needs a value of ~4.8 when threshold is set to 1.

Forked it here, you can use the slider to change the r value and find where bloom activates.
https://codesandbox.io/p/sandbox/brave-hoover-w6rrzf

If you change the base color to say RGB(1,05,0.3), the triggering value is 3.
This seems very magic numberish.

Sidenote, pushing the r value (or any for that matter) higher will intensify the bloom effect. This might be intended behaviour, but that means that setting a color to 100,100,100 as suggested in the Diamond post will positively blind the user?

Sidenote2. In the Diamond sandbox, the hotpink sphere also blooms if you set the material color to white (1,1,1). Logically it shouldn’t because it’s a) tonemapped (so clamped to 0-1) and b) not going over the threshold.
This can be fixed by upping the bloom threshold to way beyond 1 but I’m sure that will have other unexpected results.

Either I’m woefully misunderstanding how the postprocessing works, or bloom is not as selective as we thought it to be.

it has something to do with color theory i believe. it’s big numbers.

as for 1 1 1 bloom, environment light amplifies the base color. the eventual color is over rgb 1 that’s why it blooms. you can set the threshold to > 1.

Right. So lighting, material properties, camera based fresnel etc all contribute to the final base colour value, which is then checked against the threshold. Makes sense.

In practical terms that means we can never have true selective bloom, as all those factors could inadvertently push any material over the set threshold.

Would the deprecated SelectiveBloom postproc still be a viable option, in your opinion?

The key word here is luminance. Red / green / blue are perceived as different brightnesses by human observers, and bloom pass uses luminance weights to compare to the luminance threshold, aiming to approximate perceived brightness. For the sRGB / Rec. 709 color primaries, luminance weights are:

L = 0.2126 * R + 0.7152 * G + 0.0722 * B

That’s why you’re seeing .7152 x 5 = 3.5 as the triggering value.

2 Likes

Thanks for that explanation, at least now I understand why it behaves this way :+1:

i don’t think it does anything special. selection by luminance as @donmccurdy explained (thank you btw, i had no idea) seems quite comfortable and easy. having to hold references and injecting them, not so easy imo and it gives you less control. for instance maybe you want subtle bloom over a base threshold of 0.9, but some elements need to glow intensely — i wouldn’t know how to do that with selective bloom unless you have two bloom passes.

1 Like

I was thinking something similar. Separating the bloompass to only work on bloomable materials would be a matter of adding those object3d to a different three layer, probably.
While this gives us the ability to really have bloomed and nonbloomed objects, it would only be feasible if all bloomed objects adhere to the same threshold. If we wanted to control that on a per object basis you’re probably looking at multiple bloom passes which is way too expensive, probably.

Still, binary separation of nonbloomed and bloomed could still be worth investigating :thinking:

While this gives us the ability to really have bloomed and nonbloomed objects, it would only be feasible if all bloomed objects adhere to the same threshold. If we wanted to control that on a per object basis

since this is what you get out of the box with bloom effect, in a single pass, i wouldn’t stress it. select per object via luminance/material.emissiveIntensity, it couldn’t be easier.