/** * @author mrdoob / http://mrdoob.com/ */ import { Group } from '../../objects/Group.js'; import { Vector4 } from '../../math/Vector4.js'; import { ArrayCamera } from '../../cameras/ArrayCamera.js'; import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js'; import { WebGLAnimation } from '../webgl/WebGLAnimation.js'; import { setProjectionFromUnion } from './WebVRUtils.js'; function WebXRManager( renderer ) { var gl = renderer.context; var device = null; var session = null; var framebufferScaleFactor = 1.0; var frameOfReference = null; var frameOfReferenceType = 'stage'; var pose = null; var controllers = []; var inputSources = []; function isPresenting() { return session !== null && frameOfReference !== null; } // var cameraL = new PerspectiveCamera(); cameraL.layers.enable( 1 ); cameraL.viewport = new Vector4(); var cameraR = new PerspectiveCamera(); cameraR.layers.enable( 2 ); cameraR.viewport = new Vector4(); var cameraVR = new ArrayCamera( [ cameraL, cameraR ] ); cameraVR.layers.enable( 1 ); cameraVR.layers.enable( 2 ); // this.enabled = false; this.getController = function ( id ) { var controller = controllers[ id ]; if ( controller === undefined ) { controller = new Group(); controller.matrixAutoUpdate = false; controller.visible = false; controllers[ id ] = controller; } return controller; }; this.getDevice = function () { return device; }; this.setDevice = function ( value ) { if ( value !== undefined ) device = value; if ( value instanceof XRDevice ) gl.setCompatibleXRDevice( value ); }; // function onSessionEvent( event ) { var controller = controllers[ inputSources.indexOf( event.inputSource ) ]; if ( controller ) controller.dispatchEvent( { type: event.type } ); } function onSessionEnd() { renderer.setFramebuffer( null ); animation.stop(); } this.setFramebufferScaleFactor = function ( value ) { framebufferScaleFactor = value; }; this.setFrameOfReferenceType = function ( value ) { frameOfReferenceType = value; }; this.setSession = function ( value ) { session = value; if ( session !== null ) { session.addEventListener( 'select', onSessionEvent ); session.addEventListener( 'selectstart', onSessionEvent ); session.addEventListener( 'selectend', onSessionEvent ); session.addEventListener( 'end', onSessionEnd ); session.baseLayer = new XRWebGLLayer( session, gl, { framebufferScaleFactor: framebufferScaleFactor } ); session.requestFrameOfReference( frameOfReferenceType ).then( function ( value ) { frameOfReference = value; renderer.setFramebuffer( session.baseLayer.framebuffer ); animation.setContext( session ); animation.start(); } ); // inputSources = session.getInputSources(); session.addEventListener( 'inputsourceschange', function () { inputSources = session.getInputSources(); console.log( inputSources ); for ( var i = 0; i < controllers.length; i ++ ) { var controller = controllers[ i ]; controller.userData.inputSource = inputSources[ i ]; } } ); } }; function updateCamera( camera, parent ) { if ( parent === null ) { camera.matrixWorld.copy( camera.matrix ); } else { camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); } camera.matrixWorldInverse.getInverse( camera.matrixWorld ); } this.getCamera = function ( camera ) { if ( isPresenting() ) { var parent = camera.parent; var cameras = cameraVR.cameras; updateCamera( cameraVR, parent ); for ( var i = 0; i < cameras.length; i ++ ) { updateCamera( cameras[ i ], parent ); } // update camera and its children camera.matrixWorld.copy( cameraVR.matrixWorld ); var children = camera.children; for ( var i = 0, l = children.length; i < l; i ++ ) { children[ i ].updateMatrixWorld( true ); } setProjectionFromUnion( cameraVR, cameraL, cameraR ); return cameraVR; } return camera; }; this.isPresenting = isPresenting; // Animation Loop var onAnimationFrameCallback = null; function onAnimationFrame( time, frame ) { pose = frame.getDevicePose( frameOfReference ); if ( pose !== null ) { var layer = session.baseLayer; var views = frame.views; for ( var i = 0; i < views.length; i ++ ) { var view = views[ i ]; var viewport = layer.getViewport( view ); var viewMatrix = pose.getViewMatrix( view ); var camera = cameraVR.cameras[ i ]; camera.matrix.fromArray( viewMatrix ).getInverse( camera.matrix ); camera.projectionMatrix.fromArray( view.projectionMatrix ); camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); if ( i === 0 ) { cameraVR.matrix.copy( camera.matrix ); } } } // for ( var i = 0; i < controllers.length; i ++ ) { var controller = controllers[ i ]; var inputSource = inputSources[ i ]; if ( inputSource ) { var inputPose = frame.getInputPose( inputSource, frameOfReference ); if ( inputPose !== null ) { if ( 'targetRay' in inputPose ) { controller.matrix.elements = inputPose.targetRay.transformMatrix; } else if ( 'pointerMatrix' in inputPose ) { // DEPRECATED controller.matrix.elements = inputPose.pointerMatrix; } controller.matrix.decompose( controller.position, controller.rotation, controller.scale ); controller.visible = true; continue; } } controller.visible = false; } if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); } var animation = new WebGLAnimation(); animation.setAnimationLoop( onAnimationFrame ); this.setAnimationLoop = function ( callback ) { onAnimationFrameCallback = callback; }; this.dispose = function () {}; // DEPRECATED this.getStandingMatrix = function () { console.warn( 'THREE.WebXRManager: getStandingMatrix() is no longer needed.' ); return new THREE.Matrix4(); }; this.submitFrame = function () {}; } export { WebXRManager };