Selective bloom not working

I followed a tutorial by anderson mancini - https://www.youtube.com/watch?v=er02gtD8asA&ab_channel=AndersonMancini-ThreejsJourney

I coded accordingly except for the part where he traverses the scene for the mesh, i search it with getObjectByName funtion. The whole scene is getting the bloom effect however i want just the blook object to get it.

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
import { BloomEffect, EffectComposer, EffectPass, RenderPass, SelectiveBloomEffect } from "postprocessing";
import { Selection } from 'postprocessing';



//Initialising a scene and camera 
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  50,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

//initialising the renderer and inserting it into DOM element
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.type = THREE.VSMShadowMap;
document.body.appendChild(renderer.domElement);

//declaring shadown maps and tone mapping of the scene
renderer.shadowMap.enabled = true;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.5;
renderer.setPixelRatio( window.devicePixelRatio );


/*const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
composer.addPass(new EffectPass(camera, new BloomEffect()));*/




let model; // Declare the model variable at a higher scope

//loading the HDRI to the scene
const hdriLoader = new RGBELoader();
hdriLoader.load('../env1.hdr', (texture) => {
  const envMap = texture;
  envMap.mapping = THREE.EquirectangularReflectionMapping;
  envMap.exposure = 0.25;
  scene.environment = envMap;
  scene.background = new THREE.Color(0.5, 0.5, 0.5);
});

/*
const renderScene = new RenderPass(scene,camera);
const composer = new EffectComposer(renderer);
composer.addPass(renderScene);

const bloomPass = new UnrealBloomPass(
  new THREE.Vector2(window.innerWidth,window.innerHeight),
  1.6,
  0.1,
  0.1
);

composer.addPass(bloomPass);
*/


//loading the model using the GLTF loader 
const loader1 = new GLTFLoader();

const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
loader1.setDRACOLoader(dracoLoader);

let selectedobjectforbloom = new Selection();
const composer = new EffectComposer(renderer);
const renderpass = new RenderPass(scene,camera);

loader1.load(
  'interior_threejs.glb',
  function (gltf) {
    model = gltf.scene;
    model.position.set(0, 0.01, 0);
    model.traverse((child) => {
        if (child.isObject3D) child.castShadow = true;
      });
    // Assuming you've loaded the GLTF model into the scene and named the light in Blender as 'pointLight'

      // Traverse through the scene to find the light
      model.traverse((child) => {
       if (child.name === 'Spot') {
        // Access the punctual light
          const pointLight = child;8

           // Now you can access properties of the light
          console.log('Punctual light intensity:', pointLight.children[0].intensity);
          console.log('Punctual light color:', pointLight.children[0].color);
          console.log('Punctual light position:', pointLight.position);
    
    // You can also manipulate the light properties if needed
    // For example:
        pointLight.children[0].intensity = 25;
         //pointLight.color.set(0xff0000);
  }
  const scene1 = model.getObjectByName("Scene", true);
  scene1.receiveShadow = true;

  const object = model.getObjectByName( "Cube", true );
  object.receiveShadow = true;
  object.castShadow = true;

  const object1 = model.getObjectByName("Cube002",true)
  object1.receiveShadow = true;
  object1.castShadow = true;

  const object2 = model.getObjectByName( "Cube001_2", true );
  object2.receiveShadow = true;
  object2.castShadow = true;



  const selectiveBloom = new SelectiveBloomEffect(scene,camera, {
    intensity : 1.5,
    luminanceThreshold : 0.0001,
    mipmapblur : true,
    radius : .35,
  })
  
  selectiveBloom.selection =  selectedobjectforbloom;
  
  const obj = model.getObjectByName("bloom", true);
  selectedobjectforbloom.add(obj);

 
  composer.addPass(renderpass);
  composer.addPass(new EffectPass(camera, new BloomEffect(), selectiveBloom));


});

      scene.add(model);
      console.log(model);
      
    },
    undefined,
    function (error) {
      console.error('Error loading GLTF model:', error);
    }
  );
    /*
  let selectedobjectforbloom = new Selection();

  const selectiveBloom = new SelectiveBloomEffect(scene,camera, {
    intensity : 1.5,
    luminanceThreshold : 0.0001,
    mipmapblur : true,
    radius : .35,
  })
  
  selectiveBloom.selection =  selectedobjectforbloom;
  
  const obj = model.getObjectByName("bloom", true);
  selectedobjectforbloom.add(obj);

  const composer = new EffectComposer(renderer);
  const renderpass = new RenderPass(scene,camera);
  composer.addPass(renderpass);
  composer.addPass(new EffectPass(camera, bloom, selectiveBloom));*/

// Initialize ambient light
const ambientLight = new THREE.AmbientLight(0xffffff, 1); // Color: white, Intensity: 1
scene.add(ambientLight);


const directionalLight = new THREE.DirectionalLight(0xffffff,8);
directionalLight.position.set(-6.5,2.5,-1.5);
directionalLight.castShadow = true;
scene.add(directionalLight);

directionalLight.shadow.mapSize.width = 1024; // Shadow map width
directionalLight.shadow.mapSize.height = 1024; // Shadow map height
directionalLight.shadow.camera.near = 0.5; // Near plane of shadow camera
directionalLight.shadow.camera.far = 500; // Far plane of shadow camera
directionalLight.shadow.camera.left = -10; // Left boundary of shadow camera's frustum
directionalLight.shadow.camera.right = 10; // Right boundary of shadow camera's frustum
directionalLight.shadow.camera.top = 10; // Top boundary of shadow camera's frustum
directionalLight.shadow.camera.bottom = -10;
directionalLight.shadow.bias = 0; // Shadow bias
directionalLight.shadow.normalBias = 1; // Shadow normal bias
directionalLight.shadow.radius = 4; 
   
  //orbit controls for the chair
const orbit = new OrbitControls(camera, renderer.domElement);
camera.position.set(0, 2, 3);
/*
// Set limits for rotation
orbit.minPolarAngle = 0; // radians
orbit.maxPolarAngle = 1.309; // radians

// Set limits for zoom
orbit.minDistance = 1;
orbit.maxDistance = 3;
*/
orbit.update();

//animate to render it realtime
function animate() {
    requestAnimationFrame(animate);
   // renderer.render(scene, camera);
    composer.render();
  }
  animate();

the above is my code and the output is shown below

Please format the code properly, it’s not really readable in the current form.

i have done by best, please take a look. Thanks!

This is a different approach, but also see:

My feeling is that getting your “emissive” objects and bloom threshold above the 0–1 range is generally a better approach, and avoids the need for manual selectivity.

thanks for the suggestion.

I did set the color to be bright yellow as i wanted it to emulate LED strip lighting and set the emission strength above 1 (5). however I am still facing the same issues

I am sure that I am not understanding something very important here, so below are my questions

  1. what is the best material type to set for the emissive objects (LED strips or lamps)? so i can use bloom on them
    is it lambert or other type?

  2. i set the color of the light mesh to be brightest yellow, is that what you mean or do I have to do something different?

  3. will i have issues of using bloom when i have spot lights lighting my scene?

  4. when you mention threshhold of 0, do you mean this threshold mentioned below?

  5. if at all i want to create led strip lighting or a lamp lighting in a well lit interior scene what approach is the best?

I would suggest either a PBR material (Standard or Physical) with “.emissive” or a Basic material with just “.color”. Either should be fine.

i set the color of the light mesh to be brightest yellow, is that what you mean or do I have to do something different?

In Blender you’ll want: to use the Emissive option, and crank the strength up >>> 1…

Screenshot 2024-03-28 at 2.19.53 PM

Then open the model in https://gltf.report/ and open the metadata tab. You should see KHR_materials_emissive_strength listed as an extension – if not then your version of Blender is too old.

will i have issues of using bloom when i have spot lights lighting my scene?

Only if your spotlights are so bright that they cause a surface to reflect more light than the luminance threshold. That is “as intended”, as you might very well want to see bloom off of the strongest reflections, or not, you can choose the threshold and emissive values accordingly.

when you mention threshhold of 0, do you mean this threshold mentioned below?

Yes, that’s the one.

Keep in mind that the threshold is not compared directly to the RGB values, but to a luminance computed from them with sRGB / Rec. 709 luminance weights…

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

… related to perceived brightness of different colors. So, for example, an emissive blue at strength 2 will have a lower luminosity than white at strength 1, choose your emissive strengths accordingly.

Physically based lighting could easily have intensities in the thousands of nits (and would require adjustments to .toneMappingExposure to create a well-exposed image), there is nothing magical about “1” as an emissive strength value.

Let me propose an alternative – if there are just a few meshes that must bloom, it might be feasible to use fake selective bloom, like the golden ring in this example. Fake bloom does not use any post-processing passes, instead it adds a few additional meshes.

https://codepen.io/boytchev/full/ExdmvxE

image

(you may also add a halo object, which is yet another variant of fake selective bloom)

2 Likes

I have set the color to brightest yellow with the emission strength as 50 as you directed
Then open the model in https://gltf.report/ and open the metadata tab.

You should see KHR_materials_emissive_strength listed as an extension – if not then your version of Blender is too old.

I did check it in the website and it does have that extenstion

Only if your spotlights are so bright that they cause a surface to reflect more light than the luminance threshold. That is “as intended”, as you might very well want to see bloom off of the strongest reflections, or not, you can choose the threshold and emissive values accordingly.

I halved the brightness of all my spotlight for such case so as to avoid the entire issue of creating strong reflections, it did improve a bit as i can see some of the white marble texture.

I did try to tinker with the threshold and intensity, I dont see any expected difference

is there a blog post or something i can read to get better at this ??

thanks for an alternative approach. its just that it ain’t very aesthetic for my client. he is very particular about having natural looking lights in the scene

If a non-emissive white floor under normal lighting is causing bloom, then your bloom luminance threshold should be set much higher. Also make sure the floor’s material is not emissive. Sorry I don’t know of a blog post on this subject.

use the normal Bloom, not SelectiveBloom. bloom is selective out of the box without you having to do anything. set luminianceThreshold to 1 or 2 so that nothing glows. the prop is called mipmapBlur, not mipmapblur, it is important for it to be true because without it’s using the terrible looking implementation, mipmap uses unreal bloom which is beautiful and natural. i would remove the radius prop because your mipmap was off.

now emission will allow you to pick the materials that are supposed to bloom. the floor won’t if it isn’t emissive.