任何人都可以解释 Three.js StereoEffect 的代码中发生了什么
Can anyone explain what is going on in this code for Three.js StereoEffect
懂立体渲染的大神能不能解释一下这几个函数是做什么用的来创建VR立体效果的。 three.js 库中几乎没有关于 StereoCamera(), setScissor(), setViewPort()
等函数的文档。
如果有任何形式的 high/low-level 解释,我将不胜感激。
此外,我遇到的一个错误是,当我尝试更改 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;
setScissor
和 setViewport
设置 canvas 的渲染区域。更具体地说,setViewport
设置如何从着色器的剪辑 space 转换为 canvas 像素的某些部分 space 和 setScissor
设置一个矩形,在该矩形之外无法呈现任何内容。
参见 this。
否则 StereoCamera
只提供 2 个相距 eyeSep
的摄像头,因此您只需操作一个摄像头,PerspectiveCamera
然后 update
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>
懂立体渲染的大神能不能解释一下这几个函数是做什么用的来创建VR立体效果的。 three.js 库中几乎没有关于 StereoCamera(), setScissor(), setViewPort()
等函数的文档。
如果有任何形式的 high/low-level 解释,我将不胜感激。
此外,我遇到的一个错误是,当我尝试更改 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;
setScissor
和 setViewport
设置 canvas 的渲染区域。更具体地说,setViewport
设置如何从着色器的剪辑 space 转换为 canvas 像素的某些部分 space 和 setScissor
设置一个矩形,在该矩形之外无法呈现任何内容。
参见 this。
否则 StereoCamera
只提供 2 个相距 eyeSep
的摄像头,因此您只需操作一个摄像头,PerspectiveCamera
然后 update
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>