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

Three.js中EffectComposer混合场景闪烁问题求助

Three.js双场景混合频闪问题解决方案

嘿,我看了你的代码,发现问题出在多个EffectComposer共用了同一个WebGLRenderTarget上!当你用同一个renderTarget给不同的composer时,每次渲染都会覆盖这个目标的内容,导致第二个场景的纹理数据被后续的渲染操作冲掉,就出现了频闪的现象。

修复步骤:

  1. 为每个Composer创建独立的RenderTarget
    不要只创建一个renderTarget,而是给每个composer单独生成自己的WebGLRenderTarget。修改initProcessingPasses函数里的代码:

    function initProcessingPasses () {
        // 定义RenderTarget参数
        var parameters = {
            minFilter: THREE.LinearFilter,
            magFilter: THREE.LinearFilter,
            format: THREE.RGBAFormat,
            stencilBuffer: true
        };
    
        // 为每个Composer创建独立的RenderTarget
        var renderTargetScene1 = new THREE.WebGLRenderTarget( canvasWidth, canvasHeight, parameters );
        var renderTargetScene2 = new THREE.WebGLRenderTarget( canvasWidth, canvasHeight, parameters );
        var renderTargetBlending = new THREE.WebGLRenderTarget( canvasWidth, canvasHeight, parameters );
        var renderTargetFinal = new THREE.WebGLRenderTarget( canvasWidth, canvasHeight, parameters );
        var renderTargetDebug1 = new THREE.WebGLRenderTarget( canvasWidth, canvasHeight, parameters );
        var renderTargetDebug2 = new THREE.WebGLRenderTarget( canvasWidth, canvasHeight, parameters );
    
        processing = { pass: {}, texture: {} };
    
        processing.pass.clear = new THREE.ClearPass();
    
        processing.pass.renderScene1 = new THREE.RenderPass( scene1, camera );
        processing.pass.renderScene1.clear = true;
        processing.pass.renderScene1.renderToScreen = false;
        processing.pass.renderScene1.clearDepth = true;
    
        processing.pass.renderScene2 = new THREE.RenderPass( scene2, camera );
        processing.pass.renderScene2.clear = true;
        processing.pass.renderScene2.renderToScreen = false;
        processing.pass.renderScene2.clearDepth = true;
    
        processing.pass.blending = new THREE.ShaderPass( THREE.Custom.AdditiveShader );
        processing.pass.blending.clear = true;
        processing.pass.blending.renderToScreen = false;
    
        processing.pass.output = new THREE.ShaderPass( THREE.CopyShader );
        processing.pass.output.renderToScreen = true;
    
        setPostProcessingPasses(renderTargetScene1, renderTargetScene2, renderTargetBlending, renderTargetFinal, renderTargetDebug1, renderTargetDebug2);
    }
    
  2. 修改setPostProcessingPasses函数,接收独立的RenderTarget
    更新这个函数,让每个composer使用专属的renderTarget:

    function setPostProcessingPasses(rtScene1, rtScene2, rtBlending, rtFinal, rtDebug1, rtDebug2) {
        console.log('setPostProcessingPasses');
    
        composerScene1 = new THREE.EffectComposer( renderer, rtScene1 );
        composerScene1.addPass( processing.pass.clear );
        composerScene1.addPass( processing.pass.renderScene1 );
        processing.texture.renderedScene1 = new THREE.TexturePass(composerScene1.renderTarget2.texture);
    
        composerScene2 = new THREE.EffectComposer( renderer, rtScene2 );
        composerScene2.addPass( processing.pass.clear );
        composerScene2.addPass( processing.pass.renderScene2 );
        processing.texture.renderedScene2 = new THREE.TexturePass(composerScene2.renderTarget2.texture);
    
        composerBlending = new THREE.EffectComposer( renderer, rtBlending );
        composerBlending.addPass( processing.pass.clear );
        composerBlending.addPass( processing.texture.renderedScene1 );
        processing.pass.blending.uniforms[ 'tAdd' ].value = composerScene2.renderTarget2.texture;
        composerBlending.addPass( processing.pass.blending );
        processing.texture.renderedBlending = new THREE.TexturePass(composerBlending.renderTarget2.texture);
    
        composerFinal = new THREE.EffectComposer( renderer, rtFinal );
        composerFinal.addPass( processing.pass.clear );
        composerFinal.addPass( processing.texture.renderedBlending );
        composerFinal.addPass( processing.pass.output );
    
        composerDebugScene1 = new THREE.EffectComposer( renderer, rtDebug1 );
        composerDebugScene1.addPass( processing.pass.clear );
        composerDebugScene1.addPass( processing.texture.renderedScene1 );
        composerDebugScene1.addPass( processing.pass.output );
    
        composerDebugScene2 = new THREE.EffectComposer( renderer, rtDebug2 );
        composerDebugScene2.addPass( processing.pass.clear );
        composerDebugScene2.addPass( processing.texture.renderedScene2 );
        composerDebugScene2.addPass( processing.pass.output );
    }
    
  3. 修复着色器的语法错误
    你的AdditiveShader片段着色器里有个小错误:gl_FragColor = texel + add * fCoeff, 1.0; 这行的逗号是错的,应该改成:

    gl_FragColor = vec4(texel.rgb + add.rgb * fCoeff, 1.0);
    

    这样才能正确输出RGBA颜色,避免可能的渲染异常。

额外优化建议:

  • 窗口 resize 时,记得也要更新所有renderTarget的尺寸:在onWindowResize函数里添加每个renderTarget的setSize调用,比如renderTargetScene1.setSize(canvasWidth, canvasHeight);,确保渲染结果适配窗口大小。

这样修改后,两个场景的渲染结果会被保存到各自独立的renderTarget里,混合着色器就能正确读取两个纹理,不会再出现频闪的问题啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:31:17