'ThreeJS Selective Bloom For Specific Parts Of One Object Using Emission Map

In my project I want to display 3d objects which sometimes have small LED lights. The idea is, that these small lights need to be emitting some kind of bloom to make it look like they are glowing.

I've tried to apply the UnrealBloom however it is considered for the entire scene and not just for the parts that have the actual emission value (using an emission texture map).. the scene gets very blurry as well.

enter image description here

This is obviously not what I wanted. I only need the little red LED light bulp to glow not the entire object. However I have not yet found a way to tell the engine to only apply the bloom to where the emission map is pointing at.

I'm using a very simple code setup which is almost the same as the UnrealBloom Example:

How can I setup the emission texture correctly and make only the emissive parts of the object glow and prevent the unrealistically shiny surfaces and very blurry visuals?

UPDATE: Editable example of my setup is now available on JSFiddle!

<body style="margin:0px; overflow:hidden;">
<div id="bloom-solution">   
    <div id="body">
    
        <h2 id="info" style="
          color: rgb(255,255,255);
          position: fixed;
          top: 45%;
          left: 50%;
          transform: translate(-50%, -50%);
        ">loading scene, this might take a few seconds..</h2>
    
        <script type="x-shader/x-vertex" id="vertexshader">

            varying vec2 vUv;

            void main() {

                vUv = uv;

                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

            }

        </script>

        <script type="x-shader/x-fragment" id="fragmentshader">

            uniform sampler2D baseTexture;
            uniform sampler2D bloomTexture;

            varying vec2 vUv;

            void main() {

                gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );

            }

        </script>
    
        <script type="module">
        
        import * as THREE from 'https://threejs.org/build/three.module.js'

        import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js'
        import { GLTFLoader } from 'https://threejs.org/examples/jsm/loaders/GLTFLoader.js'
        import { RGBELoader } from 'https://threejs.org/examples/jsm/loaders/RGBELoader.js'
        import { EffectComposer } from 'https://threejs.org/examples/jsm/postprocessing/EffectComposer.js';
        import { RenderPass } from 'https://threejs.org/examples/jsm/postprocessing/RenderPass.js';
        import { UnrealBloomPass } from 'https://threejs.org/examples/jsm/postprocessing/UnrealBloomPass.js';

        // RESOURCES ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

        const COLOR_TEXTURE =       "https://cdn.jsdelivr.net/gh/MigerRepo/bloom-solution/RecordPlayer_Color.jpeg"
        const METALNESS_TEXTURE =   "https://cdn.jsdelivr.net/gh/MigerRepo/bloom-solution/RecordPlayer_Metalness.jpeg"
        const EMISSION_TEXTURE =    "https://cdn.jsdelivr.net/gh/MigerRepo/bloom-solution/RecordPlayer_Emission.jpeg"
        const ALPHA_TEXTURE =       "https://cdn.jsdelivr.net/gh/MigerRepo/bloom-solution/RecordPlayer_Alpha.jpeg"
        
        const TURNTABLE_MODEL =     "https://cdn.jsdelivr.net/gh/MigerRepo/bloom-solution/turntable_a111.glb"
        const HDRI_MAP =            "https://cdn.jsdelivr.net/gh/MigerRepo/bloom-solution/forest.hdr"

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        function $(e){return document.getElementById(e)}

        const container = document.createElement( 'div' )
        document.body.appendChild( container )

        const scene = new THREE.Scene()
        scene.background = new THREE.Color( new THREE.Color("rgb(250,244,227)") )
        scene.fog = new THREE.Fog( new THREE.Color("rgb(100, 100, 100)"), 10, 50 )

        const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 )
        camera.position.set( 7, 3, 7 )

        const renderer = new THREE.WebGLRenderer( { antialias: true } )
        renderer.setPixelRatio( window.devicePixelRatio )
        renderer.setSize( window.innerWidth, window.innerHeight )
        renderer.toneMapping = THREE.ACESFilmicToneMapping
        renderer.outputEncoding = THREE.sRGBEncoding
        renderer.shadowMap.enabled = true
        renderer.shadowMap.type = THREE.PCFSoftShadowMap
        container.appendChild( renderer.domElement )
        
        const controls = new OrbitControls( camera, renderer.domElement )
        controls.minDistance = 1
        controls.enablePan = true
        controls.enableZoom = true;
        controls.enableDamping = true
        controls.dampingFactor = 0.1
        controls.rotateSpeed = 0.5
        
        const directionalLight = new THREE.DirectionalLight( new THREE.Color("rgb(255, 255, 255)"), 1 )
        directionalLight.castShadow = true
        directionalLight.shadow.camera.top = 4
        directionalLight.shadow.camera.bottom = - 4
        directionalLight.shadow.camera.left = - 4
        directionalLight.shadow.camera.right = 4
        directionalLight.shadow.camera.near = 0.1
        directionalLight.shadow.camera.far = 40
        directionalLight.shadow.camera.far = 40
        directionalLight.shadow.bias = - 0.002
        directionalLight.position.set( 0, 20, 20 )
        directionalLight.shadow.mapSize.width = 1024*4
        directionalLight.shadow.mapSize.height = 1024*4
        scene.add( directionalLight )

        scene.add( new THREE.CameraHelper( directionalLight.shadow.camera ) )

        var gltfLoader
        var model
        var mesh
        
        const pmremGenerator = new THREE.PMREMGenerator( renderer )
        pmremGenerator.compileEquirectangularShader()

        new RGBELoader().setDataType( THREE.UnsignedByteType ).load( HDRI_MAP, function ( texture ) {           
            const envMap = pmremGenerator.fromEquirectangular( texture ).texture
            scene.environment = envMap
            texture.dispose()
            pmremGenerator.dispose()
                
            gltfLoader = new GLTFLoader()
            gltfLoader.load( TURNTABLE_MODEL, function ( gltf ) {   
                model = gltf.scene
                model.position.y = 1
                model.traverse( function ( child ) {
                    if ( child.isMesh ) {
                        mesh = child
                        child.castShadow = true
                        child.receiveShadow = true
                        child.material.transparent = true           
                        child.material.envMapIntensity = 1
                        
                        $("info").style.display = "none";
                    }
                } );

                model.scale.set(15,15,15)

                scene.add( model )
                animate()
            } )
        });
        
        const animate = function () {

            requestAnimationFrame( animate )

            controls.update()

            renderer.render( scene, camera )

        };
        
        window.addEventListener( 'resize', function () {
            const width = window.innerWidth
            const height = window.innerHeight
            renderer.setSize( width, height )
            camera.aspect = width / height
            camera.updateProjectionMatrix()
        } )
        </script>
    </div>
</div>
</body>


Solution 1:[1]

there is a way, way easier method than going through all these complicated steps and passes. just push colors out of their normal 0-1 range and that is literally it: https://twitter.com/0xca0a/status/1525083552672632833

  1. set up bloom with a threshold of 1 (nothing gets bloomed)
  2. push material colors into hd range
  3. disable tonemapping

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 hpalu