diff --git a/examples/js/vr/WebVR.js b/examples/js/vr/WebVR.js index 087c453cff63ce5bcebbdc2f82430ec4ed6e2b58..a814623fd73015d25af7ce52dbcd63c7bea37a5a 100644 --- a/examples/js/vr/WebVR.js +++ b/examples/js/vr/WebVR.js @@ -9,7 +9,7 @@ var WEBVR = { createButton: function ( renderer ) { - function showEnterVR( display ) { + function showEnterVR( device ) { button.style.display = ''; @@ -24,11 +24,29 @@ var WEBVR = { button.onclick = function () { - display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: renderer.domElement } ] ); + if ( 'xr' in navigator ) { + + device.requestSession( { exclusive: true } ).then( function ( session ) { + + renderer.vr.setSession( session ); + + session.addEventListener( 'end', function ( event ) { + + renderer.vr.setSession( null ); + + } ); + + } ); + + } else { + + device.isPresenting ? device.exitPresent() : device.requestPresent( [ { source: renderer.domElement } ] ); + + } }; - renderer.vr.setDevice( display ); + renderer.vr.setDevice( device ); } @@ -68,7 +86,31 @@ var WEBVR = { } - if ( 'getVRDisplays' in navigator ) { + var isWebXR = false; + + if ( 'xr' in navigator ) { + + isWebXR = true; + + var button = document.createElement( 'button' ); + button.style.display = 'none'; + + stylizeElement( button ); + + navigator.xr.requestDevice().then( function ( device ) { + + device.supportsSession( { exclusive: true } ).then( function () { + + showEnterVR( device ); + button.textContent = 'ENTER XR'; // TODO + + } ).catch( showVRNotFound ); + + } ).catch( showVRNotFound ); + + return button; + + } else if ( 'getVRDisplays' in navigator ) { var button = document.createElement( 'button' ); button.style.display = 'none'; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 516a231334b8150323f075d2a8db6dc785add981..1bbee9d54ec0b1dc22e668f9cfcfaffe73ed1046 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -42,6 +42,7 @@ import { WebGLTextures } from './webgl/WebGLTextures.js'; import { WebGLUniforms } from './webgl/WebGLUniforms.js'; import { WebGLUtils } from './webgl/WebGLUtils.js'; import { WebVRManager } from './webvr/WebVRManager.js'; +import { WebXRManager } from './webvr/WebXRManager.js'; /** * @author supereggbert / http://www.paulbrunt.co.uk/ @@ -288,7 +289,7 @@ function WebGLRenderer( parameters ) { // vr - var vr = new WebVRManager( _this ); + var vr = ( 'xr' in navigator ) ? new WebXRManager( _gl ) : new WebVRManager( _this ); this.vr = vr; @@ -353,9 +354,7 @@ function WebGLRenderer( parameters ) { this.setSize = function ( width, height, updateStyle ) { - var device = vr.getDevice(); - - if ( device && device.isPresenting ) { + if ( vr.isPresenting() ) { console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); return; @@ -1037,11 +1036,9 @@ function WebGLRenderer( parameters ) { function requestAnimationLoopFrame() { - var device = vr.getDevice(); - - if ( device && device.isPresenting ) { + if ( vr.isPresenting() ) { - device.requestAnimationFrame( animationLoop ); + vr.requestAnimationFrame( animationLoop ); } else { @@ -1388,14 +1385,22 @@ function WebGLRenderer( parameters ) { if ( object.layers.test( camera2.layers ) ) { - var bounds = camera2.bounds; + if ( 'viewport' in camera2 ) { // XR + + state.viewport( _currentViewport.copy( camera2.viewport ) ); + + } else { + + var bounds = camera2.bounds; - var x = bounds.x * _width; - var y = bounds.y * _height; - var width = bounds.z * _width; - var height = bounds.w * _height; + var x = bounds.x * _width; + var y = bounds.y * _height; + var width = bounds.z * _width; + var height = bounds.w * _height; - state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) ); + state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) ); + + } renderObject( object, scene, camera2, geometry, material, group ); diff --git a/src/renderers/webvr/WebVRManager.js b/src/renderers/webvr/WebVRManager.js index 70e59146972a63804d93b2d727d82ac23f47a15d..f07f6c93a957616cebe9745a4345437a29aea6de 100644 --- a/src/renderers/webvr/WebVRManager.js +++ b/src/renderers/webvr/WebVRManager.js @@ -3,8 +3,8 @@ */ import { Matrix4 } from '../../math/Matrix4.js'; -import { Vector4 } from '../../math/Vector4.js'; import { Vector3 } from '../../math/Vector3.js'; +import { Vector4 } from '../../math/Vector4.js'; import { Quaternion } from '../../math/Quaternion.js'; import { ArrayCamera } from '../../cameras/ArrayCamera.js'; import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js'; @@ -226,6 +226,14 @@ function WebVRManager( renderer ) { }; + this.isPresenting = isPresenting; + + this.requestAnimationFrame = function ( callback ) { + + device.requestAnimationFrame( callback ); + + }; + this.submitFrame = function () { if ( isPresenting() ) device.submitFrame(); diff --git a/src/renderers/webvr/WebXRManager.js b/src/renderers/webvr/WebXRManager.js new file mode 100644 index 0000000000000000000000000000000000000000..08865b22a1c6cd04a4ad98738b9a7bdb0b3fa5e1 --- /dev/null +++ b/src/renderers/webvr/WebXRManager.js @@ -0,0 +1,145 @@ +/** + * @author mrdoob / http://mrdoob.com/ + */ + +import { Matrix4 } from '../../math/Matrix4.js'; +import { Vector4 } from '../../math/Vector4.js'; +import { Vector3 } from '../../math/Vector3.js'; +import { Quaternion } from '../../math/Quaternion.js'; +import { ArrayCamera } from '../../cameras/ArrayCamera.js'; +import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js'; + +function WebXRManager( gl ) { + + var scope = this; + + var device = null; + var session = null; + + var frameOfRef = null; + var isExclusive = false; + + var pose = null; + + function isPresenting() { + + return session !== null && frameOfRef !== 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.getDevice = function () { + + return device; + + }; + + this.setDevice = function ( value ) { + + if ( value !== undefined ) device = value; + + gl.setCompatibleXRDevice( value ); + + }; + + this.setSession = function ( value ) { + + session = value; + + if ( session !== null ) { + + session.baseLayer = new XRWebGLLayer( session, gl ); + session.requestFrameOfReference( 'stage' ).then( function ( value ) { + + frameOfRef = value; + isExclusive = session.exclusive; + + console.log( 0 ); + + } ); + + } + + }; + + this.getCamera = function ( camera ) { + + return isPresenting() ? cameraVR : camera; + + }; + + this.isPresenting = isPresenting; + + this.requestAnimationFrame = function ( callback ) { + + console.log( 1 ); + + function onFrame( time, frame ) { + + pose = frame.getDevicePose( frameOfRef ); + + 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.projectionMatrix.fromArray( view.projectionMatrix ); + camera.matrixWorldInverse.fromArray( viewMatrix ); + camera.matrixWorld.getInverse( camera.matrixWorldInverse ); + camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); + + if ( i === 0 ) { + + cameraVR.matrixWorld.copy( camera.matrixWorld ); + cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse ); + + // HACK (mrdoob) + // https://github.com/w3c/webvr/issues/203 + + cameraVR.projectionMatrix.copy( camera.projectionMatrix ); + + } + + } + + gl.bindFramebuffer( gl.FRAMEBUFFER, session.baseLayer.framebuffer ); + + callback(); + + } + + session.requestAnimationFrame( onFrame ); + + }; + + this.submitFrame = function () { + + // if ( device && device.isPresenting ) device.submitFrame(); + + }; + +} + +export { WebXRManager }; diff --git a/utils/build/externs.js b/utils/build/externs.js index 94d700596f9f8d90cac86ece1f5f7fdb62fba6ec..b6ac18dfaf7a0aa9adb40cb18ed166e04bb5bc30 100644 --- a/utils/build/externs.js +++ b/utils/build/externs.js @@ -5,3 +5,4 @@ var exports; var performance; var createImageBitmap; var WebGL2RenderingContext; +var XRWebGLLayer;