Skip to content

Commit bd63a6c

Browse files
authored
Merge pull request #13978 from mrdoob/webxr
Added basic WebXR support
2 parents bbfbe98 + 8f2c2fa commit bd63a6c

File tree

5 files changed

+220
-19
lines changed

5 files changed

+220
-19
lines changed

examples/js/vr/WebVR.js

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ var WEBVR = {
99

1010
createButton: function ( renderer ) {
1111

12-
function showEnterVR( display ) {
12+
function showEnterVR( device ) {
1313

1414
button.style.display = '';
1515

@@ -24,11 +24,29 @@ var WEBVR = {
2424

2525
button.onclick = function () {
2626

27-
display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: renderer.domElement } ] );
27+
if ( 'xr' in navigator ) {
28+
29+
device.requestSession( { exclusive: true } ).then( function ( session ) {
30+
31+
renderer.vr.setSession( session );
32+
33+
session.addEventListener( 'end', function ( event ) {
34+
35+
renderer.vr.setSession( null );
36+
37+
} );
38+
39+
} );
40+
41+
} else {
42+
43+
device.isPresenting ? device.exitPresent() : device.requestPresent( [ { source: renderer.domElement } ] );
44+
45+
}
2846

2947
};
3048

31-
renderer.vr.setDevice( display );
49+
renderer.vr.setDevice( device );
3250

3351
}
3452

@@ -68,7 +86,31 @@ var WEBVR = {
6886

6987
}
7088

71-
if ( 'getVRDisplays' in navigator ) {
89+
var isWebXR = false;
90+
91+
if ( 'xr' in navigator ) {
92+
93+
isWebXR = true;
94+
95+
var button = document.createElement( 'button' );
96+
button.style.display = 'none';
97+
98+
stylizeElement( button );
99+
100+
navigator.xr.requestDevice().then( function ( device ) {
101+
102+
device.supportsSession( { exclusive: true } ).then( function () {
103+
104+
showEnterVR( device );
105+
button.textContent = 'ENTER XR'; // TODO
106+
107+
} ).catch( showVRNotFound );
108+
109+
} ).catch( showVRNotFound );
110+
111+
return button;
112+
113+
} else if ( 'getVRDisplays' in navigator ) {
72114

73115
var button = document.createElement( 'button' );
74116
button.style.display = 'none';

src/renderers/WebGLRenderer.js

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import { WebGLTextures } from './webgl/WebGLTextures.js';
4242
import { WebGLUniforms } from './webgl/WebGLUniforms.js';
4343
import { WebGLUtils } from './webgl/WebGLUtils.js';
4444
import { WebVRManager } from './webvr/WebVRManager.js';
45+
import { WebXRManager } from './webvr/WebXRManager.js';
4546

4647
/**
4748
* @author supereggbert / http://www.paulbrunt.co.uk/
@@ -288,7 +289,7 @@ function WebGLRenderer( parameters ) {
288289

289290
// vr
290291

291-
var vr = new WebVRManager( _this );
292+
var vr = ( 'xr' in navigator ) ? new WebXRManager( _gl ) : new WebVRManager( _this );
292293

293294
this.vr = vr;
294295

@@ -353,9 +354,7 @@ function WebGLRenderer( parameters ) {
353354

354355
this.setSize = function ( width, height, updateStyle ) {
355356

356-
var device = vr.getDevice();
357-
358-
if ( device && device.isPresenting ) {
357+
if ( vr.isPresenting() ) {
359358

360359
console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
361360
return;
@@ -1037,11 +1036,9 @@ function WebGLRenderer( parameters ) {
10371036

10381037
function requestAnimationLoopFrame() {
10391038

1040-
var device = vr.getDevice();
1041-
1042-
if ( device && device.isPresenting ) {
1039+
if ( vr.isPresenting() ) {
10431040

1044-
device.requestAnimationFrame( animationLoop );
1041+
vr.requestAnimationFrame( animationLoop );
10451042

10461043
} else {
10471044

@@ -1388,14 +1385,22 @@ function WebGLRenderer( parameters ) {
13881385

13891386
if ( object.layers.test( camera2.layers ) ) {
13901387

1391-
var bounds = camera2.bounds;
1388+
if ( 'viewport' in camera2 ) { // XR
1389+
1390+
state.viewport( _currentViewport.copy( camera2.viewport ) );
1391+
1392+
} else {
1393+
1394+
var bounds = camera2.bounds;
13921395

1393-
var x = bounds.x * _width;
1394-
var y = bounds.y * _height;
1395-
var width = bounds.z * _width;
1396-
var height = bounds.w * _height;
1396+
var x = bounds.x * _width;
1397+
var y = bounds.y * _height;
1398+
var width = bounds.z * _width;
1399+
var height = bounds.w * _height;
13971400

1398-
state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) );
1401+
state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) );
1402+
1403+
}
13991404

14001405
renderObject( object, scene, camera2, geometry, material, group );
14011406

src/renderers/webvr/WebVRManager.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
*/
44

55
import { Matrix4 } from '../../math/Matrix4.js';
6-
import { Vector4 } from '../../math/Vector4.js';
76
import { Vector3 } from '../../math/Vector3.js';
7+
import { Vector4 } from '../../math/Vector4.js';
88
import { Quaternion } from '../../math/Quaternion.js';
99
import { ArrayCamera } from '../../cameras/ArrayCamera.js';
1010
import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js';
@@ -226,6 +226,14 @@ function WebVRManager( renderer ) {
226226

227227
};
228228

229+
this.isPresenting = isPresenting;
230+
231+
this.requestAnimationFrame = function ( callback ) {
232+
233+
device.requestAnimationFrame( callback );
234+
235+
};
236+
229237
this.submitFrame = function () {
230238

231239
if ( isPresenting() ) device.submitFrame();
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* @author mrdoob / http://mrdoob.com/
3+
*/
4+
5+
import { Matrix4 } from '../../math/Matrix4.js';
6+
import { Vector4 } from '../../math/Vector4.js';
7+
import { Vector3 } from '../../math/Vector3.js';
8+
import { Quaternion } from '../../math/Quaternion.js';
9+
import { ArrayCamera } from '../../cameras/ArrayCamera.js';
10+
import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js';
11+
12+
function WebXRManager( gl ) {
13+
14+
var scope = this;
15+
16+
var device = null;
17+
var session = null;
18+
19+
var frameOfRef = null;
20+
var isExclusive = false;
21+
22+
var pose = null;
23+
24+
function isPresenting() {
25+
26+
return session !== null && frameOfRef !== null;
27+
28+
}
29+
30+
//
31+
32+
var cameraL = new PerspectiveCamera();
33+
cameraL.layers.enable( 1 );
34+
cameraL.viewport = new Vector4();
35+
36+
var cameraR = new PerspectiveCamera();
37+
cameraR.layers.enable( 2 );
38+
cameraR.viewport = new Vector4();
39+
40+
var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
41+
cameraVR.layers.enable( 1 );
42+
cameraVR.layers.enable( 2 );
43+
44+
//
45+
46+
this.enabled = false;
47+
48+
this.getDevice = function () {
49+
50+
return device;
51+
52+
};
53+
54+
this.setDevice = function ( value ) {
55+
56+
if ( value !== undefined ) device = value;
57+
58+
gl.setCompatibleXRDevice( value );
59+
60+
};
61+
62+
this.setSession = function ( value ) {
63+
64+
session = value;
65+
66+
if ( session !== null ) {
67+
68+
session.baseLayer = new XRWebGLLayer( session, gl );
69+
session.requestFrameOfReference( 'stage' ).then( function ( value ) {
70+
71+
frameOfRef = value;
72+
isExclusive = session.exclusive;
73+
74+
console.log( 0 );
75+
76+
} );
77+
78+
}
79+
80+
};
81+
82+
this.getCamera = function ( camera ) {
83+
84+
return isPresenting() ? cameraVR : camera;
85+
86+
};
87+
88+
this.isPresenting = isPresenting;
89+
90+
this.requestAnimationFrame = function ( callback ) {
91+
92+
console.log( 1 );
93+
94+
function onFrame( time, frame ) {
95+
96+
pose = frame.getDevicePose( frameOfRef );
97+
98+
var layer = session.baseLayer;
99+
var views = frame.views;
100+
101+
for ( var i = 0; i < views.length; i ++ ) {
102+
103+
var view = views[ i ];
104+
var viewport = layer.getViewport( view );
105+
var viewMatrix = pose.getViewMatrix( view );
106+
107+
var camera = cameraVR.cameras[ i ];
108+
camera.projectionMatrix.fromArray( view.projectionMatrix );
109+
camera.matrixWorldInverse.fromArray( viewMatrix );
110+
camera.matrixWorld.getInverse( camera.matrixWorldInverse );
111+
camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
112+
113+
if ( i === 0 ) {
114+
115+
cameraVR.matrixWorld.copy( camera.matrixWorld );
116+
cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );
117+
118+
// HACK (mrdoob)
119+
// https://github.com/w3c/webvr/issues/203
120+
121+
cameraVR.projectionMatrix.copy( camera.projectionMatrix );
122+
123+
}
124+
125+
}
126+
127+
gl.bindFramebuffer( gl.FRAMEBUFFER, session.baseLayer.framebuffer );
128+
129+
callback();
130+
131+
}
132+
133+
session.requestAnimationFrame( onFrame );
134+
135+
};
136+
137+
this.submitFrame = function () {
138+
139+
// if ( device && device.isPresenting ) device.submitFrame();
140+
141+
};
142+
143+
}
144+
145+
export { WebXRManager };

utils/build/externs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ var exports;
55
var performance;
66
var createImageBitmap;
77
var WebGL2RenderingContext;
8+
var XRWebGLLayer;

0 commit comments

Comments
 (0)