You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js Bloom生效异常问题:请求修改示例并讲解场景遍历与材质释放

Got it, let's fix that bloom effect issue in your Three.js code, and also break down how to properly use scene.traverse and obj.material.dispose along the way.

First, let's diagnose why your current setup isn't producing the expected bloom (like bloomYes.png instead of bloomNot.png):

  • The RenderPass in your composer wasn't restricted to only render layer 1 (the bloom-specific objects), so it was applying bloom to the entire scene instead of just the glowing elements.
  • Your layering render order was reversed, causing the bloom effect to be covered up by the main scene in some cases.
  • Repeated variable names (like using obj for every mesh) made the code hard to debug and maintain.

Modified Working Code

<!DOCTYPE html>
<html>
<head>
    <style>
        body {
            overflow: hidden;
            margin: 0;
        }
    </style>
</head>
<body>
    <script src="https://threejs.org/build/three.min.js"></script>
    <script src='https://threejs.org/examples/js/postprocessing/EffectComposer.js'></script>
    <script src='https://threejs.org/examples/js/postprocessing/RenderPass.js'></script>
    <script src='https://threejs.org/examples/js/postprocessing/ShaderPass.js'></script>
    <script src='https://threejs.org/examples/js/shaders/CopyShader.js'></script>
    <script src="https://threejs.org/examples/js/shaders/FXAAShader.js"></script>
    <script src="https://threejs.org/examples/js/shaders/LuminosityHighPassShader.js"></script>
    <script src="https://threejs.org/examples/js/postprocessing/UnrealBloomPass.js"></script>
    <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
    <script>
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(60, window.innerWidth/ window.innerHeight, 1, 1000);
        camera.position.set(20, 0, -20);
        camera.layers.enable(1);
        var renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.autoClear = false;
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x000000);
        document.body.appendChild(renderer.domElement);
        var controls = new THREE.OrbitControls(camera, renderer.domElement);
        var light = new THREE.DirectionalLight(0xffffff, 0.75);
        light.position.setScalar(100);
        scene.add(light);
        scene.add(new THREE.AmbientLight(0xffffff, 0.25));

        // Non-bloom objects (layer 0)
        var obj1 = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 4), new THREE.MeshLambertMaterial({color: 0xf0f0f0}));
        obj1.layers.set(0);
        obj1.position.z = 0;
        scene.add(obj1);

        var obj2 = new THREE.Mesh(new THREE.BoxGeometry(12, 12, 1), new THREE.MeshLambertMaterial({color: 0x0000ff}));
        obj2.position.z = 2.5;
        obj2.layers.set(0);
        scene.add(obj2);

        var obj3 = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 4), new THREE.MeshLambertMaterial({color: 0xf0f0f0}));
        obj3.layers.set(0);
        obj3.position.z = 5;
        scene.add(obj3);

        var objRed = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 1), new THREE.MeshBasicMaterial({color: 0xff0000}));
        objRed.position.z = -2.5;
        objRed.layers.set(0);
        scene.add(objRed);

        var objGreen = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 1), new THREE.MeshBasicMaterial({color: 0x00ff00}));
        objGreen.position.z = 7.5;
        objGreen.layers.set(0);
        scene.add(objGreen);

        // Bloom objects (layer 1)
        var objBloomRed = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 1), new THREE.MeshBasicMaterial({color: 0xff0000}));
        objBloomRed.position.z = -2.25;
        objBloomRed.layers.set(1);
        scene.add(objBloomRed);

        var objBloomGreen = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 1), new THREE.MeshBasicMaterial({color: 0x00ff00}));
        objBloomGreen.position.z = 7.5;
        objBloomGreen.layers.set(1);
        scene.add(objBloomGreen);

        /** COMPOSER CONFIGURATION - FIXED */
        // Create a render pass restricted to bloom layer (layer 1)
        const bloomRenderPass = new THREE.RenderPass(scene, camera);
        bloomRenderPass.camera.layers.set(1); // Only render bloom objects here

        const effectFXAA = new THREE.ShaderPass(THREE.FXAAShader);
        effectFXAA.uniforms.resolution.value.set(1 / window.innerWidth, 1 / window.innerHeight);

        const bloomPass = new THREE.UnrealBloomPass(
            new THREE.Vector2(window.innerWidth, window.innerHeight),
            1.5, 0.4, 0.85
        );
        bloomPass.threshold = 0.21;
        bloomPass.strength = 1.2;
        bloomPass.radius = 0.55;
        bloomPass.renderToScreen = false; // Don't render bloom directly to screen yet

        // Final pass to copy bloom effect over the main scene
        const copyPass = new THREE.ShaderPass(THREE.CopyShader);
        copyPass.renderToScreen = true;

        const composer = new THREE.EffectComposer(renderer);
        composer.setSize(window.innerWidth, window.innerHeight);
        composer.addPass(bloomRenderPass);
        composer.addPass(effectFXAA);
        composer.addPass(bloomPass);
        composer.addPass(copyPass);

        var delta = 0;

        function render(){
            requestAnimationFrame(render);
            delta += 0.05;

            // Sync color updates for bloom and matching non-bloom object
            const greenVal = Math.sin(delta);
            const blueVal = Math.cos(delta);
            objBloomRed.material.color.g = greenVal;
            objBloomRed.material.color.b = blueVal;
            objRed.material.color.g = greenVal;
            objRed.material.color.b = blueVal;

            renderer.clear();

            // First render main scene (layer 0)
            camera.layers.set(0);
            renderer.render(scene, camera);

            // Then overlay the bloom effect
            renderer.clearDepth();
            composer.render();
        }

        render();

        // Example: Proper resource cleanup with scene.traverse and material.dispose
        function cleanupScene() {
            // Traverse every object in the scene to clean up resources
            scene.traverse((obj) => {
                if (obj.isMesh) {
                    // Dispose material to free GPU memory
                    obj.material.dispose();
                    // Dispose geometry if it's not reused elsewhere
                    obj.geometry.dispose();
                }
            });
            // Clean up composer resources too
            composer.dispose();
        }

        // Optional: Attach cleanup to window unload to prevent memory leaks
        window.addEventListener('unload', cleanupScene);
    </script>
</body>
</html>

Key Fixes & Explanations

  1. Restricted Bloom Rendering

    • We added a dedicated RenderPass that only renders layer 1 (bloom objects) by setting bloomRenderPass.camera.layers.set(1). This ensures bloom is only applied to the intended glowing elements, not the entire scene.
    • Reversed the render order: first draw the main scene (layer 0), then overlay the bloom effect—this fixes the layering issue where bloom was being covered up.
  2. Using scene.traverse for Batch Operations

    • The cleanupScene function shows how scene.traverse lets you iterate over every object in the scene. This is perfect for batch tasks like resource cleanup, updating materials, or adjusting properties across multiple meshes.
  3. Proper Material Disposal

    • Calling obj.material.dispose() tells WebGL to release GPU resources tied to that material. This is critical for preventing memory leaks, especially in long-running apps or single-page applications where scenes are swapped out.
    • Always pair material disposal with geometry disposal (obj.geometry.dispose()) unless the geometry is reused across multiple meshes.
  4. Code Clarity

    • Renamed duplicate obj variables to descriptive names, making the code easier to read and debug.
    • Ensured bloom and non-bloom objects are positioned correctly to avoid unintended visual overlap.

内容的提问来源于stack exchange,提问作者Vladimir Fedorov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 08:32:33