javascript - 谁能解释一下 Three.js StereoEffect 的代码中发生了什么

标签 javascript three.js virtual-reality stereoscopy

了解立体渲染的人可以解释一下这些函数是如何创建 VR 立体效果的吗? Three.js 库中几乎没有关于 StereoCamera()、setScissor()、setViewPort() 等函数的文档。

我非常感谢任何类型的高级/低级解释。

另外,我遇​​到的一个错误是当我尝试更改 eyeSep 值时,它对最终渲染没有影响。

/**
 * @author alteredq / http://alteredqualia.com/
 * @authod mrdoob / http://mrdoob.com/
 * @authod arodic / http://aleksandarrodic.com/
 * @authod fonserbc / http://fonserbc.github.io/
*/

THREE.StereoEffect = function ( renderer ) {

    var _stereo = new THREE.StereoCamera();
    _stereo.aspect = 0.5;
    var size = new THREE.Vector2();

    this.setEyeSeparation = function ( eyeSep ) {

        _stereo.eyeSep = eyeSep;

    };

    this.setSize = function ( width, height ) {

        renderer.setSize( width, height );

    };

    this.render = function ( scene, camera ) {

        scene.updateMatrixWorld();

        if ( camera.parent === null ) camera.updateMatrixWorld();

        _stereo.update( camera );

        renderer.getSize( size );

        if ( renderer.autoClear ) renderer.clear();
        renderer.setScissorTest( true );

        renderer.setScissor( 0, 0, size.width / 2, size.height );
        renderer.setViewport( 0, 0, size.width / 2, size.height );
        renderer.render( scene, _stereo.cameraL );

        renderer.setScissor( size.width / 2, 0, size.width / 2, size.height );
        renderer.setViewport( size.width / 2, 0, size.width / 2, size.height );
        renderer.render( scene, _stereo.cameraR );

        renderer.setScissorTest( false );

    };

};

module.exports = THREE.StereoEffect;

最佳答案

setScissorsetViewport

设置要渲染的 Canvas 区域。更具体地说,setViewport 设置如何从着色器的剪辑空间转换为 Canvas 像素空间的某些部分,setScissor 设置一个矩形,在该矩形之外无法渲染任何内容。

参见this

否则,StereoCamera 仅提供 2 个相距 eyeSep 的摄像头,因此您只需操作一个摄像头,即 PerspectiveCamera,然后您更新 StereoCamera,它将自动更新您可用于渲染的 2 眼摄像机。

body { margin: 0; }
#c { width: 100vw; height: 100vh; display: block; }
#ui { position: absolute; left: 1em; top: 1em; }
<canvas id="c"></canvas>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js';
import {GUI} from 'https://threejsfundamentals.org/threejs/../3rdparty/dat.gui.module.js';

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 75;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 5;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 2;
  
  const stereo = new THREE.StereoCamera();

  const gui = new GUI();
  gui.add(stereo, 'eyeSep', 0, 2, 0.001);

  const scene = new THREE.Scene();

  {
    const color = 0xFFFFFF;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);
  }

  const geometry = new THREE.SphereBufferGeometry(0.5, 6, 3);

  function makeInstance(geometry, color, x) {
    const material = new THREE.MeshPhongMaterial({color, flatShading: true});

    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);

    cube.position.x = x;

    return cube;
  }

  const cubes = [
    makeInstance(geometry, 0x44aa88,  0),
    makeInstance(geometry, 0x8844aa, -1),
    makeInstance(geometry, 0xaa8844,  1),
  ];

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight / 2;  
      camera.updateProjectionMatrix();
    }

    cubes.forEach((cube, ndx) => {
      const speed = 1 + ndx * .1;
      const rot = time * speed;
      cube.rotation.x = rot;
      cube.rotation.y = rot;
    });

    {
        // we need to manually update camera matrix
        // because it will not be passed directly to
        // renderer.render were it would normally be
        // updated

        camera.updateWorldMatrix();
        stereo.update(camera);

        const size = new THREE.Vector2();
        renderer.getSize(size);

        renderer.setScissorTest(true);

        renderer.setScissor(0, 0, size.width / 2, size.height);
        renderer.setViewport(0, 0, size.width / 2, size.height);
        renderer.render(scene, stereo.cameraL);

        renderer.setScissor(size.width / 2, 0, size.width / 2, size.height);
        renderer.setViewport(size.width / 2, 0, size.width / 2, size.height);
        renderer.render(scene, stereo.cameraR);

        renderer.setScissorTest(false);
    }

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
</script>

关于javascript - 谁能解释一下 Three.js StereoEffect 的代码中发生了什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61052900/

相关文章:

javascript - 在 gridview 中使用 <a href>

javascript - computeVertexNormals 不适用于 JsonLoader 中的模型

c++ - Oculus Rift VR - 示例项目错​​误

javascript - A 型框架轨道 Controller 重置摄像机位置

Three.js - VRControls 集成 - 如何在场景中移动?

javascript - jstree 中只调用了 1 个文件夹

javascript - 为什么对 IDBObjectStore.get() 的调用会导致混淆行为?

asp.net - 单击后退按钮强制刷新页面

javascript - Three.js - 地面/地板上的反射

three.js - Threejs 着色器 - gl_FragColor 与 Alpha(不透明度不变)