Search code examples
three.jsbackgroundscenepost-processingbloom

How to change my scene background by creating a post-processing BLOOM?


I am new to THREE.js and i want the object to light up when the mouse rolls over.

But when I change the scene.background color to white by Bloom, I find that Bloom affects the appearance of the background color. how do I solve this problem?

it's before

enter image description here

and it's after

enter image description here

here is the complete code

<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="importmap">
    {
        "imports": {
            "three": "./build/three.module.js"
        }
    }
</script>

<script type="module">
    import * as THREE from 'three';
    import { OrbitControls } from './jsm/controls/OrbitControls.js';
    import Stats from './jsm/libs/stats.module.js';
    import { GUI } from './jsm/libs/lil-gui.module.min.js';
    import { EffectComposer } from './jsm/postprocessing/EffectComposer.js';
    import { RenderPass } from './jsm/postprocessing/RenderPass.js';
    import { UnrealBloomPass } from './jsm/postprocessing/UnrealBloomPass.js';
    import { FBXLoader } from './Loader/FBXLoader/FBXLoader.js';
    import { OBJLoader } from './Loader/OBJLoader.js';
    import { MTLLoader } from './Loader/MTLLoader.js'
    import { GLTFLoader } from "./Loader/GLTFLoader.js";
    import { ShaderPass } from './jsm/postprocessing/ShaderPass.js';

    const ENTIRE_SCENE = 0, BLOOM_SCENE = 1;

    const bloomLayer = new THREE.Layers();
    bloomLayer.set(BLOOM_SCENE);

    let params = {
        exposure: 1,
        bloomThreshold: 0.41,
        bloomStrength: 0.66,
        bloomRadius: 0.05,
        scene: 'Scene with Glow'
    };

    //set MeshBasicMaterial
    const darkMaterial = new THREE.MeshBasicMaterial({ color: 'black' });
    const materials = {};

    /*--------renderer--------*/
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;

    //add scene
    const scene = new THREE.Scene();

    /*--------camera--------*/
    const camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 100000000);
    camera.position.set(0, 10, 0);
    camera.lookAt(0, 0, 0);





    /*--------OrbitControls--------*/
    let controls = new OrbitControls(camera, renderer.domElement);
    controls.target.set(0, 0, 0);
    controls.enablePan = false;
    controls.maxPolarAngle = Math.PI / 2;
    controls.enableDamping = true;

    //Render
    const renderScene = new RenderPass(scene, camera);

    const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
    bloomPass.threshold = params.bloomThreshold;
    bloomPass.strength = params.bloomStrength;
    bloomPass.radius = params.bloomRadius;

    const bloomComposer = new EffectComposer(renderer);
    bloomComposer.renderToScreen = false;
    bloomComposer.addPass(renderScene);
    bloomComposer.addPass(bloomPass);

    const finalPass = new ShaderPass(
        new THREE.ShaderMaterial({
            uniforms: {
                baseTexture: { value: null },
                bloomTexture: { value: bloomComposer.renderTarget2.texture }
            },
            vertexShader: document.getElementById('vertexshader').textContent,
            fragmentShader: document.getElementById('fragmentshader').textContent,
            defines: {}
        }), 'baseTexture'
    );
    finalPass.needsSwap = true;

    const finalComposer = new EffectComposer(renderer);
    finalComposer.addPass(renderScene);
    finalComposer.addPass(finalPass);

    /*--------Stats--------*/
    const stats = Stats();
    stats.showPanel(0);
    document.body.appendChild(stats.dom);

    /*--------AmbientLight-1--------*/
    scene.add(new THREE.AmbientLight(0xffffff, 1));

    //light1
    const light1 = new THREE.PointLight(0xddffdd, 1);
    light1.position.z = 0;
    light1.position.y = 300;
    light1.position.x = 200;
    scene.add(light1);

    //GUI
    const gui = new GUI();

    gui.add(params, 'scene', ['Scene with Glow', 'Scene only']).onChange(function (value) {
        switch (value) {
            case 'Scene with Glow':
                bloomComposer.renderToScreen = false;
                break;
            case 'Scene only':
                // nothing to do
                break;
        }
    });

    const folder = gui.addFolder('Bloom Parameters');

    folder.add(params, 'exposure', 0.1, 2).onChange(function (value) {

        renderer.toneMappingExposure = Math.pow(value, 4.0);

    });

    folder.add(params, 'bloomThreshold', 0.0, 1.0).onChange(function (value) {

        bloomPass.threshold = Number(value);

    });

    folder.add(params, 'bloomStrength', 0.0, 10.0).onChange(function (value) {

        bloomPass.strength = Number(value);

    });

    folder.add(params, 'bloomRadius', 0.0, 1.0).step(0.01).onChange(function (value) {

        bloomPass.radius = Number(value);

    });
    /*--------scene.background--------*/
    scene.background = new THREE.Color(0xffffff);

    /*--------cube--------*/

    const geometry = new THREE.BoxGeometry(4, 4, 4);
    const material = new THREE.MeshBasicMaterial({ color: 0x000050 });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);

    /*--------raycaster--------*/
    const raycaster = new THREE.Raycaster();

    const mouse = new THREE.Vector2();

    window.addEventListener('mousemove', onMouseMove);
    console.log(scene);
    function onMouseMove(event) {

        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

        raycaster.setFromCamera(mouse, camera);

        const intersects = raycaster.intersectObjects(scene.children);
        scene.children[2].layers.set(ENTIRE_SCENE);
        if (intersects[0]) {
            const intersects_object_name = intersects[0].object.name;
            intersects[0].object.layers.enableAll(BLOOM_SCENE);
        }
    }
    //window.onresize
    window.onresize = function () {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    };

    function disposeMaterial(obj) {
        if (obj.material) {
            obj.material.dispose();
        }
    }

    //render
    function render() {
        switch (params.scene) {

            case 'Scene only':
                renderer.render(scene, camera);
                break;

            case 'Scene with Glow':

            default:
                // render scene with bloom
                renderBloom(true);

                // render the entire scene, then render bloom scene on top
                finalComposer.render();
                break;

        }

    }
    function renderBloom(mask) {

        if (mask === true) {
            scene.traverse(darkenNonBloomed);
            bloomComposer.render();
            scene.traverse(restoreMaterial);
        } else {
            camera.layers.set(BLOOM_SCENE);
            bloomComposer.render();
            camera.layers.set(ENTIRE_SCENE);
        }
    }
    function darkenNonBloomed(obj) {
        if (obj.isMesh && bloomLayer.test(obj.layers) === false) {
            materials[obj.uuid] = obj.material;
            obj.material = darkMaterial;
        }
    }
    function restoreMaterial(obj) {
        if (materials[obj.uuid]) {
            obj.material = materials[obj.uuid];
            delete materials[obj.uuid];
        }
    }
    function animate() {
        stats.update();
        render();
        requestAnimationFrame(animate);
    };
    animate();

</script>

Here are examples if needed https://smile881225.github.io/AskQuestions/


Solution

  • Try to change this part:

            if (mask === true) {
                scene.traverse(darkenNonBloomed);
                bloomComposer.render();
                scene.traverse(restoreMaterial);
            } else {
    

    to this:

            if (mask === true) {
                renderer.setClearColor(0x000000); // all must be black, including background
                scene.traverse(darkenNonBloomed);
                bloomComposer.render();
                renderer.setClearColor(0x006432); // set the color you want
                scene.traverse(restoreMaterial);
            } else {