Three.js:无法将背景通道与轮廓通道相结合

Posted

技术标签:

【中文标题】Three.js:无法将背景通道与轮廓通道相结合【英文标题】:Three.js: Not able to combine background pass with outline pass 【发布时间】:2020-07-06 21:31:49 【问题描述】:

我想将网格渲染到背景场景中,这样我就可以使用更强大的着色器(渐变、特殊效果……)自定义背景。当用户将鼠标悬停在主场景网格上时,我还想使用outlinePass 效果。

我不确定它是否不可行,或者我尝试清除渲染器的方式是否有问题。

这是目前的代码 (jsfiddle demo):

var container, stats;
var camera, scene, renderer, controls, backgroundScene, backgroundCamera;
var raycaster = new THREE.Raycaster();

var mouse = new THREE.Vector2();
var selectedObjects = [];

var composer, effectFXAA, outlinePass;

function init() 

  backgroundCamera = new THREE.OrthographicCamera(
    -1, 1, 1, -1, -1, 0);

  backgroundScene = new THREE.Scene()

  const fragmentShader = `
    void main() 
      gl_FragColor = vec4(0.7, 0, 0, 1.);
    
  `

  backgroundScene.add(new THREE.Mesh(
    new THREE.PlaneBufferGeometry(2, 2), 
    new THREE.ShaderMaterial(
    fragmentShader
  )));

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

    var width = window.innerWidth;
    var height = window.innerHeight;

    renderer = new THREE.WebGLRenderer();
    renderer.shadowMap.enabled = true;

    renderer.setSize( width, height );
  renderer.autoClear = false

    document.body.appendChild( renderer.domElement );

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera( 45, width / height, 0.1, 100 );
    camera.position.set( 0, 0, 8 );

    controls = new THREE.OrbitControls( camera, renderer.domElement );
    scene.add( new THREE.AmbientLight( 0xaaaaaa, 0.2 ) );

    var light = new THREE.DirectionalLight( 0xddffdd, 0.6 );
    light.position.set( 1, 1, 1 );
    scene.add( light );

    var geometry = new THREE.TorusBufferGeometry( 1, 0.3, 16, 100 );
    var material = new THREE.MeshPhongMaterial(  color: 0xffaaff  );
    var torus = new THREE.Mesh( geometry, material );
    torus.position.z = - 4;
    scene.add( torus );

    composer = new THREE.EffectComposer( renderer );

  var backgroundPass = new THREE.RenderPass(
    backgroundScene, 
    backgroundCamera);

    composer.addPass( backgroundPass );

  backgroundPass.clear = false

    var renderPass = new THREE.RenderPass( scene, camera );
    composer.addPass( renderPass );

  renderPass.clear = false

    outlinePass = new THREE.OutlinePass( 
    new THREE.Vector2( 
        window.innerWidth, window.innerHeight ), scene, camera );

  outlinePass.clear = false

    composer.addPass( outlinePass );

    window.addEventListener( 'resize', onWindowResize, false );
    window.addEventListener( 'mousemove', onTouchMove );


    var outputPass = new THREE.ShaderPass( THREE.CopyShader );
    outputPass.renderToScreen = true;
  outputPass.clear = true

  composer.addPass( outputPass );

    function onTouchMove( event ) 

        var x, y;

        if ( event.changedTouches ) 
            x = event.changedTouches[ 0 ].pageX;
            y = event.changedTouches[ 0 ].pageY;
         else 
            x = event.clientX;
            y = event.clientY;
        

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

        checkIntersection();
    

    function checkIntersection() 
        raycaster.setFromCamera(mouse, camera);
        var intersects = raycaster.intersectObjects([scene], true);
    outlinePass.selectedObjects = intersects.length
        ? [intersects[ 0 ].object]
      : []
    


function onWindowResize() 
    var width = window.innerWidth;
    var height = window.innerHeight;
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
    renderer.setSize( width, height );
    composer.setSize( width, height );


function renderLoop() 
    requestAnimationFrame(renderLoop);
    controls.update();
    renderer.clear()
    composer.render();


init()
renderLoop() 

结果看起来像是一个缓冲区清除问题,但不知道我应该如何解决它。

【问题讨论】:

【参考方案1】:

你在正确的轨道上。您唯一需要更改的是:

    摆脱renderer.autoClear = false; 摆脱所有xxPass.clear = false;。您唯一需要保留的是renderPass.clear = false,这样它就不会覆盖红色着色器输出。

以下是修改后的结果:

https://jsfiddle.net/marquizzo/mwazr0yd/

(我注意到还有一点,您的outputPass 没有向渲染结果添加任何内容。您可以摆脱这个额外的步骤,只需使用outlinePass.renderToScreen = true; 将outlinePass 渲染到屏幕上)

【讨论】:

感谢这解决了演示中的问题,不幸的是我的应用程序仍然有问题。正如我最初在那个问题中提到的那样:discourse.threejs.org/t/…。添加轮廓通道将完全遮蔽场景。任何见解可能有什么问题?

以上是关于Three.js:无法将背景通道与轮廓通道相结合的主要内容,如果未能解决你的问题,请参考以下文章

使用vue学习three.js之渲染后期处理-简单的后期处理通道FilmPass(类似电视效果)DotScreenPass(将场景输出成点集)GlitchPass(电磁风暴效果)

使用vue学习three.js之渲染后期处理-使用UnrealBloomPass通道在场景中添加泛光效果,三维物体表面发光效果

PS简易通道抠图的方法

广播与P2P通道(下) -- 方案实现

将 SwiftUI 中的文本与背景属性相结合会产生错误,因为无法将“某些视图”类型的值转换为预期的参数类型“文本”?

OpenCV 错误:通道数错误(源图像必须有 1、3 或 4 个通道)