Три. js: Невозможно объединить фоновый проход с контурным проходом. - PullRequest
1 голос
/ 26 марта 2020

Я хочу сделать меня sh в фоновой сцене, чтобы я мог настроить фон с помощью более мощных шейдеров (градиент, спецэффекты, ...). Я также хотел бы использовать эффект 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() 

результат выглядит как ошибка очистки буфера, но нет Идея, как мне это исправить.

enter image description here

1 Ответ

0 голосов
/ 31 марта 2020

Вы на правильном пути. Единственное, что вам нужно изменить:

  1. Избавиться от renderer.autoClear = false;
  2. Избавиться от всего xxPass.clear = false;. Единственное, что вам нужно сохранить - это renderPass.clear = false, поэтому он не перезаписывает вывод красного шейдера.

Вот результат с этими изменениями:

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

(Что-то еще, что я заметил, ваш outputPass ничего не добавляет к результату рендеринга. Вы можете избавиться от этого дополнительного шага и просто сделать outlinePass рендеринга на экран с помощью outlinePass.renderToScreen = true;)

...