-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WebGPURenderer: Add
XRManager
. (#30346)
* WebGPURenderer: Add `XRManager`. * Renderer: Fix projection matrix computation in XR. * WebGLBackend: Use `gl.STATIC_DRAW` for camera index buffers. * Renderer: Clean up. * WebGLBackend: Don't cache `cameraIndex`. * XRManager: Add documentation. * E2E: Update screenshot. * Renderer: Fix `xr` usage.
- Loading branch information
Showing
9 changed files
with
1,684 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
// temporary version of XRButton until WebGPURenderer fully support layers | ||
|
||
class XRButton { | ||
|
||
static createButton( renderer, sessionInit = {} ) { | ||
|
||
const button = document.createElement( 'button' ); | ||
|
||
function showStartXR( mode ) { | ||
|
||
let currentSession = null; | ||
|
||
async function onSessionStarted( session ) { | ||
|
||
session.addEventListener( 'end', onSessionEnded ); | ||
|
||
await renderer.xr.setSession( session ); | ||
|
||
button.textContent = 'STOP XR'; | ||
|
||
currentSession = session; | ||
|
||
} | ||
|
||
function onSessionEnded( /*event*/ ) { | ||
|
||
currentSession.removeEventListener( 'end', onSessionEnded ); | ||
|
||
button.textContent = 'START XR'; | ||
|
||
currentSession = null; | ||
|
||
} | ||
|
||
// | ||
|
||
button.style.display = ''; | ||
|
||
button.style.cursor = 'pointer'; | ||
button.style.left = 'calc(50% - 50px)'; | ||
button.style.width = '100px'; | ||
|
||
button.textContent = 'START XR'; | ||
|
||
const sessionOptions = { | ||
...sessionInit, | ||
optionalFeatures: [ | ||
'local-floor', | ||
'bounded-floor', | ||
...( sessionInit.optionalFeatures || [] ) | ||
], | ||
}; | ||
|
||
button.onmouseenter = function () { | ||
|
||
button.style.opacity = '1.0'; | ||
|
||
}; | ||
|
||
button.onmouseleave = function () { | ||
|
||
button.style.opacity = '0.5'; | ||
|
||
}; | ||
|
||
button.onclick = function () { | ||
|
||
if ( currentSession === null ) { | ||
|
||
navigator.xr.requestSession( mode, sessionOptions ) | ||
.then( onSessionStarted ); | ||
|
||
} else { | ||
|
||
currentSession.end(); | ||
|
||
if ( navigator.xr.offerSession !== undefined ) { | ||
|
||
navigator.xr.offerSession( mode, sessionOptions ) | ||
.then( onSessionStarted ) | ||
.catch( ( err ) => { | ||
|
||
console.warn( err ); | ||
|
||
} ); | ||
|
||
} | ||
|
||
} | ||
|
||
}; | ||
|
||
if ( navigator.xr.offerSession !== undefined ) { | ||
|
||
navigator.xr.offerSession( mode, sessionOptions ) | ||
.then( onSessionStarted ) | ||
.catch( ( err ) => { | ||
|
||
console.warn( err ); | ||
|
||
} ); | ||
|
||
} | ||
|
||
} | ||
|
||
function disableButton() { | ||
|
||
button.style.display = ''; | ||
|
||
button.style.cursor = 'auto'; | ||
button.style.left = 'calc(50% - 75px)'; | ||
button.style.width = '150px'; | ||
|
||
button.onmouseenter = null; | ||
button.onmouseleave = null; | ||
|
||
button.onclick = null; | ||
|
||
} | ||
|
||
function showXRNotSupported() { | ||
|
||
disableButton(); | ||
|
||
button.textContent = 'XR NOT SUPPORTED'; | ||
|
||
} | ||
|
||
function showXRNotAllowed( exception ) { | ||
|
||
disableButton(); | ||
|
||
console.warn( 'Exception when trying to call xr.isSessionSupported', exception ); | ||
|
||
button.textContent = 'XR NOT ALLOWED'; | ||
|
||
} | ||
|
||
function stylizeElement( element ) { | ||
|
||
element.style.position = 'absolute'; | ||
element.style.bottom = '20px'; | ||
element.style.padding = '12px 6px'; | ||
element.style.border = '1px solid #fff'; | ||
element.style.borderRadius = '4px'; | ||
element.style.background = 'rgba(0,0,0,0.1)'; | ||
element.style.color = '#fff'; | ||
element.style.font = 'normal 13px sans-serif'; | ||
element.style.textAlign = 'center'; | ||
element.style.opacity = '0.5'; | ||
element.style.outline = 'none'; | ||
element.style.zIndex = '999'; | ||
|
||
} | ||
|
||
if ( 'xr' in navigator ) { | ||
|
||
button.id = 'XRButton'; | ||
button.style.display = 'none'; | ||
|
||
stylizeElement( button ); | ||
|
||
navigator.xr.isSessionSupported( 'immersive-ar' ) | ||
.then( function ( supported ) { | ||
|
||
if ( supported ) { | ||
|
||
showStartXR( 'immersive-ar' ); | ||
|
||
} else { | ||
|
||
navigator.xr.isSessionSupported( 'immersive-vr' ) | ||
.then( function ( supported ) { | ||
|
||
if ( supported ) { | ||
|
||
showStartXR( 'immersive-vr' ); | ||
|
||
} else { | ||
|
||
showXRNotSupported(); | ||
|
||
} | ||
|
||
} ).catch( showXRNotAllowed ); | ||
|
||
} | ||
|
||
} ).catch( showXRNotAllowed ); | ||
|
||
return button; | ||
|
||
} else { | ||
|
||
const message = document.createElement( 'a' ); | ||
|
||
if ( window.isSecureContext === false ) { | ||
|
||
message.href = document.location.href.replace( /^http:/, 'https:' ); | ||
message.innerHTML = 'WEBXR NEEDS HTTPS'; // TODO Improve message | ||
|
||
} else { | ||
|
||
message.href = 'https://immersiveweb.dev/'; | ||
message.innerHTML = 'WEBXR NOT AVAILABLE'; | ||
|
||
} | ||
|
||
message.style.left = 'calc(50% - 90px)'; | ||
message.style.width = '180px'; | ||
message.style.textDecoration = 'none'; | ||
|
||
stylizeElement( message ); | ||
|
||
return message; | ||
|
||
} | ||
|
||
} | ||
|
||
} | ||
|
||
export { XRButton }; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.