#javascript #reactjs #three.js #augmented-reality #webxr
Вопрос:
Кому-нибудь удалось успешно использовать WebXR в React? Я пытаюсь преобразовать код в следующем руководстве из vanilla.js чтобы react.js :
https://www.devbridge.com/articles/ar-app-development-tutorial/
Но я продолжаю видеть ошибку, говорящую:
Uncaught (in promise) DOMException: Failed to execute 'requestSession' on 'XRSystem': There is already an active, immersive XRSession.
У меня нет проблем с использованием кода в vanilla.js.
Моя версия кода React такова:
import React, {useState} from 'react'
const AR = () => {
const [xrButton, setXRButton] = useState('XR Not Found')
const [info, setInfo] = useState('')
//check if XR is supported or not
const [supported, setSupported] = useState(false)
const [check, setCheck] = useState(false)
const { XRWebGLLayer } = window
// to control the xr session
let xrSession = null
// reference space used within an application
let xrRefSpace = null
// Canvas OpenGL context used for rendering
let gl = null
//Check if there are any WebXR errors in Window
const checkXR = () => {
if(!check){
if (!window.isSecureContext) {
document.getElementById("warning").innerText = "WebXR unavailable. Please use secure context"
}
if (navigator.xr) { // check to see if WebXR is supported
navigator.xr.addEventListener('devicechange', checkSupportedState)
checkSupportedState()
} else {
document.getElementById("warning").innerText = "WebXR unavailable for this browser"
}
setCheck(true)
}
}
//check if webxr is supported
const checkSupportedState = () => {
if(navigator.xr){
navigator.xr.isSessionSupported('immersive-ar').then((isSupported) => {
setSupported(isSupported)
if (isSupported) {
setXRButton('View in AR')
console.log("supported:", isSupported)
} else {
setXRButton('AR not found')
console.log("WebXR doesn't support immersive-ar mode!")
}
})
}
else {
console.log("WebXR is not available!")
}
}
//if webxr is supported, allow onButtonClicked handler to be called
const onButtonClicked = () => {
if (!xrSession) {
navigator.xr.requestSession('immersive-ar', {
optionalFeatures: ['dom-overlay'],
requiredFeatures: ['local'],
domOverlay: {root: document.getElementById('overlay')}
}).then((session) => {
xrSession = session
setXRButton('Exit AR')
onSessionStarted(xrSession)
})
} else {
xrSession.end().then(() => xrSession = null)
}
}
//when immersive-ar session starts
const onSessionStarted = (session) =>{
// Show which type of DOM Overlay got enabled (if any)
if (session.domOverlayState) {
setInfo('DOM Overlay type: ' session.domOverlayState.type)
}
session.addEventListener('end', onSessionEnded);
// create a canvas element and WebGL context for rendering
let canvas = document.createElement('canvas');
gl = canvas.getContext('webgl', { xrCompatible: true });
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
session.requestReferenceSpace('local').then((refSpace) => {
xrRefSpace = refSpace;
// start WebXR rendering loop
session.requestAnimationFrame(onXRFrame);
});
}
//once immersive-ar session ends
const onSessionEnded = (event) => {
xrSession = null;
setXRButton( 'Enter AR')
setInfo('')
gl = null;
}
//on the frame once session starts
const onXRFrame = (t, frame) => {
let session = frame.session;
session.requestAnimationFrame(onXRFrame);
let pose = frame.getViewerPose(xrRefSpace);
if (!pose) {
return;
}
const pos = pose.transform.position;
setInfo(`x:${pos.x.toFixed(2)}m y:${pos.y.toFixed(2)}m z:${pos.z.toFixed(2)}m`)
}
//call checkXR function
checkXR()
return (
<div id="overlay">
<div className="info-area">
<div id="info">{info}</div>
{ supported ?
<button id="xr-button" onClick={onButtonClicked}>{xrButton}</button>
:
<button id="xr-button" disabled>{xrButton}</button>
}
</div>
</div>
)
}
export default AR
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Я не уверен, что делаю что-то не так. Я еще не реализовал ни одного из Three.js элементов на экране еще нет. Я пытаюсь проверить, начнется ли сеанс погружения в ar или нет, но у меня возникли проблемы с этим. Те же шаги последовали и в vanilla.js не столкнулся ни с какими проблемами.