diff --git a/examples/files.json b/examples/files.json index 1f99ba5930ce4..2e136d4c9dc12 100644 --- a/examples/files.json +++ b/examples/files.json @@ -357,14 +357,9 @@ ], "webxr": [ "webxr_ar_cones", - "webxr_ar_dragging", "webxr_ar_hittest", "webxr_ar_lighting", - "webxr_ar_paint", "webxr_ar_plane_detection", - "webxr_vr_ballshooter", - "webxr_vr_cubes", - "webxr_vr_dragging", "webxr_vr_handinput", "webxr_vr_handinput_cubes", "webxr_vr_handinput_profiles", @@ -375,12 +370,15 @@ "webxr_vr_layers", "webxr_vr_panorama", "webxr_vr_panorama_depth", - "webxr_vr_paint", "webxr_vr_rollercoaster", "webxr_vr_sandbox", - "webxr_vr_sculpt", "webxr_vr_teleport", - "webxr_vr_video" + "webxr_vr_video", + "webxr_xr_ballshooter", + "webxr_xr_cubes", + "webxr_xr_dragging", + "webxr_xr_paint", + "webxr_xr_sculpt" ], "games": [ "games_fps" diff --git a/examples/jsm/webxr/XRButton.js b/examples/jsm/webxr/XRButton.js new file mode 100644 index 0000000000000..f33cbbea25111 --- /dev/null +++ b/examples/jsm/webxr/XRButton.js @@ -0,0 +1,198 @@ +class XRButton { + + static createButton( renderer ) { + + 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'; + + button.onmouseenter = function () { + + button.style.opacity = '1.0'; + + }; + + button.onmouseleave = function () { + + button.style.opacity = '0.5'; + + }; + + button.onclick = function () { + + if ( currentSession === null ) { + + const sessionInit = { + optionalFeatures: [ + 'local-floor', + 'bounded-floor', + 'hand-tracking', + 'layers' + ] + }; + + navigator.xr.requestSession( mode, sessionInit ) + .then( onSessionStarted ); + + } else { + + currentSession.end(); + + } + + }; + + } + + 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 }; diff --git a/examples/screenshots/webxr_ar_dragging.jpg b/examples/screenshots/webxr_ar_dragging.jpg deleted file mode 100644 index 4714c68168456..0000000000000 Binary files a/examples/screenshots/webxr_ar_dragging.jpg and /dev/null differ diff --git a/examples/screenshots/webxr_ar_paint.jpg b/examples/screenshots/webxr_ar_paint.jpg deleted file mode 100644 index 001fe203e0b94..0000000000000 Binary files a/examples/screenshots/webxr_ar_paint.jpg and /dev/null differ diff --git a/examples/screenshots/webxr_vr_ballshooter.jpg b/examples/screenshots/webxr_xr_ballshooter.jpg similarity index 100% rename from examples/screenshots/webxr_vr_ballshooter.jpg rename to examples/screenshots/webxr_xr_ballshooter.jpg diff --git a/examples/screenshots/webxr_vr_cubes.jpg b/examples/screenshots/webxr_xr_cubes.jpg similarity index 100% rename from examples/screenshots/webxr_vr_cubes.jpg rename to examples/screenshots/webxr_xr_cubes.jpg diff --git a/examples/screenshots/webxr_vr_dragging.jpg b/examples/screenshots/webxr_xr_dragging.jpg similarity index 100% rename from examples/screenshots/webxr_vr_dragging.jpg rename to examples/screenshots/webxr_xr_dragging.jpg diff --git a/examples/screenshots/webxr_vr_paint.jpg b/examples/screenshots/webxr_xr_paint.jpg similarity index 100% rename from examples/screenshots/webxr_vr_paint.jpg rename to examples/screenshots/webxr_xr_paint.jpg diff --git a/examples/screenshots/webxr_vr_sculpt.jpg b/examples/screenshots/webxr_xr_sculpt.jpg similarity index 100% rename from examples/screenshots/webxr_vr_sculpt.jpg rename to examples/screenshots/webxr_xr_sculpt.jpg diff --git a/examples/webxr_ar_dragging.html b/examples/webxr_ar_dragging.html deleted file mode 100644 index 0805df407d1aa..0000000000000 --- a/examples/webxr_ar_dragging.html +++ /dev/null @@ -1,244 +0,0 @@ - - - - three.js ar - dragging - - - - - - -
- three.js ar - dragging -
- - - - - - - - - - diff --git a/examples/webxr_ar_paint.html b/examples/webxr_ar_paint.html deleted file mode 100644 index 6a26076f5b755..0000000000000 --- a/examples/webxr_ar_paint.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - three.js ar - paint - - - - - - -
- three.js ar - paint
(Chrome Android 81+) -
- - - - - - - - - - diff --git a/examples/webxr_vr_ballshooter.html b/examples/webxr_xr_ballshooter.html similarity index 98% rename from examples/webxr_vr_ballshooter.html rename to examples/webxr_xr_ballshooter.html index 15f8ea178362f..0e0b006efef01 100644 --- a/examples/webxr_vr_ballshooter.html +++ b/examples/webxr_xr_ballshooter.html @@ -1,7 +1,7 @@ - three.js vr - ball shooter + three.js xr - ball shooter @@ -30,7 +30,7 @@ import * as THREE from 'three'; import { BoxLineGeometry } from 'three/addons/geometries/BoxLineGeometry.js'; - import { VRButton } from 'three/addons/webxr/VRButton.js'; + import { XRButton } from 'three/addons/webxr/XRButton.js'; import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js'; let camera, scene, renderer; @@ -100,7 +100,7 @@ // - document.body.appendChild( VRButton.createButton( renderer ) ); + document.body.appendChild( XRButton.createButton( renderer ) ); // controllers diff --git a/examples/webxr_vr_cubes.html b/examples/webxr_xr_cubes.html similarity index 97% rename from examples/webxr_vr_cubes.html rename to examples/webxr_xr_cubes.html index 2672bffcfcea8..0040bd6fb4d1e 100644 --- a/examples/webxr_vr_cubes.html +++ b/examples/webxr_xr_cubes.html @@ -1,7 +1,7 @@ - three.js vr - cubes + three.js xr - cubes @@ -30,7 +30,7 @@ import * as THREE from 'three'; import { BoxLineGeometry } from 'three/addons/geometries/BoxLineGeometry.js'; - import { VRButton } from 'three/addons/webxr/VRButton.js'; + import { XRButton } from 'three/addons/webxr/XRButton.js'; import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js'; const clock = new THREE.Clock(); @@ -146,7 +146,7 @@ // - document.body.appendChild( VRButton.createButton( renderer ) ); + document.body.appendChild( XRButton.createButton( renderer ) ); } diff --git a/examples/webxr_vr_dragging.html b/examples/webxr_xr_dragging.html similarity index 97% rename from examples/webxr_vr_dragging.html rename to examples/webxr_xr_dragging.html index d52e246395306..601d160be8030 100644 --- a/examples/webxr_vr_dragging.html +++ b/examples/webxr_xr_dragging.html @@ -1,7 +1,7 @@ - three.js vr - dragging + three.js xr - dragging @@ -29,7 +29,7 @@ import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; - import { VRButton } from 'three/addons/webxr/VRButton.js'; + import { XRButton } from 'three/addons/webxr/XRButton.js'; import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js'; let container; @@ -134,7 +134,7 @@ renderer.xr.enabled = true; container.appendChild( renderer.domElement ); - document.body.appendChild( VRButton.createButton( renderer ) ); + document.body.appendChild( XRButton.createButton( renderer ) ); // controllers diff --git a/examples/webxr_vr_paint.html b/examples/webxr_xr_paint.html similarity index 97% rename from examples/webxr_vr_paint.html rename to examples/webxr_xr_paint.html index 5ff2ee8546889..ad07b9ccb35a2 100644 --- a/examples/webxr_vr_paint.html +++ b/examples/webxr_xr_paint.html @@ -1,7 +1,7 @@ - three.js vr - paint + three.js xr - paint @@ -30,7 +30,7 @@ import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { TubePainter } from 'three/addons/misc/TubePainter.js'; - import { VRButton } from 'three/addons/webxr/VRButton.js'; + import { XRButton } from 'three/addons/webxr/XRButton.js'; let camera, scene, renderer; let controller1, controller2; @@ -105,7 +105,7 @@ renderer.xr.enabled = true; container.appendChild( renderer.domElement ); - document.body.appendChild( VRButton.createButton( renderer ) ); + document.body.appendChild( XRButton.createButton( renderer ) ); // controllers diff --git a/examples/webxr_vr_sculpt.html b/examples/webxr_xr_sculpt.html similarity index 97% rename from examples/webxr_vr_sculpt.html rename to examples/webxr_xr_sculpt.html index ccff83a8aa0a1..83ddf7526fbdf 100644 --- a/examples/webxr_vr_sculpt.html +++ b/examples/webxr_xr_sculpt.html @@ -1,7 +1,7 @@ - three.js vr - sculpt + three.js xr - sculpt @@ -30,7 +30,7 @@ import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { MarchingCubes } from 'three/addons/objects/MarchingCubes.js'; - import { VRButton } from 'three/addons/webxr/VRButton.js'; + import { XRButton } from 'three/addons/webxr/XRButton.js'; let container; let camera, scene, renderer; @@ -99,7 +99,7 @@ renderer.xr.enabled = true; container.appendChild( renderer.domElement ); - document.body.appendChild( VRButton.createButton( renderer ) ); + document.body.appendChild( XRButton.createButton( renderer ) ); // controllers diff --git a/src/renderers/webgl/WebGLBackground.js b/src/renderers/webgl/WebGLBackground.js index 70cbf8fd0fa4a..6d0ff5b8334c1 100644 --- a/src/renderers/webgl/WebGLBackground.js +++ b/src/renderers/webgl/WebGLBackground.js @@ -33,25 +33,38 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, } - // Ignore background in AR - // TODO: Reconsider this. + if ( background === null ) { - const xr = renderer.xr; - const session = xr.getSession && xr.getSession(); + setClear( clearColor, clearAlpha ); - if ( session && session.environmentBlendMode === 'additive' ) { + } else if ( background && background.isColor ) { - background = null; + setClear( background, 1 ); + forceClear = true; } - if ( background === null ) { + const xr = renderer.xr; + const session = xr.getSession(); - setClear( clearColor, clearAlpha ); + if ( session !== null ) { - } else if ( background && background.isColor ) { + switch ( session.environmentBlendMode ) { + + case 'additive': + + state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha ); + + break; + + case 'alpha-blend': + + state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha ); + + break; + + } - setClear( background, 1 ); forceClear = true; } diff --git a/src/renderers/webxr/WebXRManager.js b/src/renderers/webxr/WebXRManager.js index 3fddddf1e888c..5193987a20a76 100644 --- a/src/renderers/webxr/WebXRManager.js +++ b/src/renderers/webxr/WebXRManager.js @@ -19,6 +19,7 @@ class WebXRManager extends EventDispatcher { const scope = this; let session = null; + let framebufferScaleFactor = 1.0; let referenceSpace = null; @@ -268,7 +269,7 @@ class WebXRManager extends EventDispatcher { const layerInit = { antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, - alpha: attributes.alpha, + alpha: true, depth: attributes.depth, stencil: attributes.stencil, framebufferScaleFactor: framebufferScaleFactor