XR/desktop href-navigation works!

This commit is contained in:
Leon van Kammen 2023-05-22 17:18:15 +02:00
parent cdadc0f9f1
commit 154350897f
9 changed files with 191 additions and 36 deletions

View file

@ -614,6 +614,10 @@ xrfragment.InteractiveGroup = function(THREE,renderer,camera){
super(); super();
if( !renderer || !camera ) return if( !renderer || !camera ) return
// extract camera when camera-rig is passed
camera.traverse( (n) => String(n.type).match(/Camera/) ? camera = n : null )
const scope = this; const scope = this;
const raycaster = new Raycaster(); const raycaster = new Raycaster();
@ -877,7 +881,7 @@ xrf.navigator.to = (url,event) => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
console.log("xrfragment: navigating to "+url) console.log("xrfragment: navigating to "+url)
if( !file || xrf.model.file == file ){ // we're already loaded if( !file || xrf.model.file == file ){ // we're already loaded
document.location.hash = `#${hash}` // just update the hash document.location.hash = `#${hash}` // just update the hash
xrf.eval( url, xrf.model ) // and eval URI XR fragments xrf.eval( url, xrf.model ) // and eval URI XR fragments
return resolve(xrf.model) return resolve(xrf.model)
@ -968,8 +972,6 @@ xrf.frag.env = function(v, opts){
xrf.frag.href = function(v, opts){ xrf.frag.href = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts let { mesh, model, camera, scene, renderer, THREE} = opts
console.log("INIT HREF "+mesh.name)
const world = { const world = {
pos: new THREE.Vector3(), pos: new THREE.Vector3(),
scale: new THREE.Vector3(), scale: new THREE.Vector3(),
@ -1088,9 +1090,48 @@ xrf.frag.pos = function(v, opts){
//if( renderer.xr.isPresenting ) return // too far away //if( renderer.xr.isPresenting ) return // too far away
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ setting camera position to "+v.string) console.log(" └ setting camera position to "+v.string)
camera.position.x = v.x
camera.position.y = v.y if( !frag.q ){
camera.position.z = v.z
if( true ){//!renderer.xr.isPresenting ){
console.dir(camera)
camera.position.x = v.x
camera.position.y = v.y
camera.position.z = v.z
}
/*
else{ // XR
let cameraWorldPosition = new THREE.Vector3()
camera.object3D.getWorldPosition(this.cameraWorldPosition)
let newRigWorldPosition = new THREE.Vector3(v.x,v.y,x.z)
// Finally update the cameras position
let newRigLocalPosition.copy(this.newRigWorldPosition)
if (camera.object3D.parent) {
camera.object3D.parent.worldToLocal(newRigLocalPosition)
}
camera.setAttribute('position', newRigLocalPosition)
// Also take the headset/camera rotation itself into account
if (this.data.rotateOnTeleport) {
this.teleportOcamerainQuaternion
.setFromEuler(new THREE.Euler(0, this.teleportOcamerain.object3D.rotation.y, 0))
this.teleportOcamerainQuaternion.invert()
this.teleportOcamerainQuaternion.multiply(this.hitEntityQuaternion)
// Rotate the camera based on calculated teleport ocamerain rotation
this.cameraRig.object3D.setRotationFromQuaternion(this.teleportOcamerainQuaternion)
}
console.log("XR")
const offsetPosition = { x: - v.x, y: - v.y, z: - v.z, w: 1 };
const offsetRotation = new THREE.Quaternion();
const transform = new XRRigidTransform( offsetPosition, offsetRotation );
const teleportSpaceOffset = xrf.baseReferenceSpace.getOffsetReferenceSpace( transform );
renderer.xr.setReferenceSpace( teleportSpaceOffset );
}
*/
}
} }
xrf.frag.q = function(v, opts){ xrf.frag.q = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts
@ -1187,6 +1228,7 @@ window.AFRAME.registerComponent('xrf', {
// override the camera-related XR Fragments so the camera-rig is affected // override the camera-related XR Fragments so the camera-rig is affected
let camOverride = (xrf,v,opts) => { let camOverride = (xrf,v,opts) => {
opts.camera = $('[camera]').object3D.parent opts.camera = $('[camera]').object3D.parent
console.dir(opts.camera)
xrf(v,opts) xrf(v,opts)
} }
@ -1210,7 +1252,20 @@ window.AFRAME.registerComponent('xrf', {
let els = [...document.querySelectorAll('[xrf-get]')] let els = [...document.querySelectorAll('[xrf-get]')]
els.map( (el) => document.querySelector('a-scene').removeChild(el) ) els.map( (el) => document.querySelector('a-scene').removeChild(el) )
})(XRF.reset) })(XRF.reset)
// disable cam-controls (which will block updating camerarig position)
let coms = ['look-controls','wasd-controls']
const setComponents = (com,state) => () => {
coms.forEach( (com) => {
let el = document.querySelector('['+com+']')
if(!el) return
el.components[com].enabled = state
})
}
aScene.addEventListener('enter-vr', setComponents(coms,false) )
aScene.addEventListener('enter-ar', setComponents(coms,false) )
aScene.addEventListener('exit-vr', setComponents(coms,true) )
aScene.addEventListener('exit-ar', setComponents(coms,true) )
}, },
}) })

View file

@ -614,6 +614,10 @@ xrfragment.InteractiveGroup = function(THREE,renderer,camera){
super(); super();
if( !renderer || !camera ) return if( !renderer || !camera ) return
// extract camera when camera-rig is passed
camera.traverse( (n) => String(n.type).match(/Camera/) ? camera = n : null )
const scope = this; const scope = this;
const raycaster = new Raycaster(); const raycaster = new Raycaster();
@ -877,7 +881,7 @@ xrf.navigator.to = (url,event) => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
console.log("xrfragment: navigating to "+url) console.log("xrfragment: navigating to "+url)
if( !file || xrf.model.file == file ){ // we're already loaded if( !file || xrf.model.file == file ){ // we're already loaded
document.location.hash = `#${hash}` // just update the hash document.location.hash = `#${hash}` // just update the hash
xrf.eval( url, xrf.model ) // and eval URI XR fragments xrf.eval( url, xrf.model ) // and eval URI XR fragments
return resolve(xrf.model) return resolve(xrf.model)
@ -968,8 +972,6 @@ xrf.frag.env = function(v, opts){
xrf.frag.href = function(v, opts){ xrf.frag.href = function(v, opts){
let { mesh, model, camera, scene, renderer, THREE} = opts let { mesh, model, camera, scene, renderer, THREE} = opts
console.log("INIT HREF "+mesh.name)
const world = { const world = {
pos: new THREE.Vector3(), pos: new THREE.Vector3(),
scale: new THREE.Vector3(), scale: new THREE.Vector3(),
@ -1088,9 +1090,48 @@ xrf.frag.pos = function(v, opts){
//if( renderer.xr.isPresenting ) return // too far away //if( renderer.xr.isPresenting ) return // too far away
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ setting camera position to "+v.string) console.log(" └ setting camera position to "+v.string)
camera.position.x = v.x
camera.position.y = v.y if( !frag.q ){
camera.position.z = v.z
if( true ){//!renderer.xr.isPresenting ){
console.dir(camera)
camera.position.x = v.x
camera.position.y = v.y
camera.position.z = v.z
}
/*
else{ // XR
let cameraWorldPosition = new THREE.Vector3()
camera.object3D.getWorldPosition(this.cameraWorldPosition)
let newRigWorldPosition = new THREE.Vector3(v.x,v.y,x.z)
// Finally update the cameras position
let newRigLocalPosition.copy(this.newRigWorldPosition)
if (camera.object3D.parent) {
camera.object3D.parent.worldToLocal(newRigLocalPosition)
}
camera.setAttribute('position', newRigLocalPosition)
// Also take the headset/camera rotation itself into account
if (this.data.rotateOnTeleport) {
this.teleportOcamerainQuaternion
.setFromEuler(new THREE.Euler(0, this.teleportOcamerain.object3D.rotation.y, 0))
this.teleportOcamerainQuaternion.invert()
this.teleportOcamerainQuaternion.multiply(this.hitEntityQuaternion)
// Rotate the camera based on calculated teleport ocamerain rotation
this.cameraRig.object3D.setRotationFromQuaternion(this.teleportOcamerainQuaternion)
}
console.log("XR")
const offsetPosition = { x: - v.x, y: - v.y, z: - v.z, w: 1 };
const offsetRotation = new THREE.Quaternion();
const transform = new XRRigidTransform( offsetPosition, offsetRotation );
const teleportSpaceOffset = xrf.baseReferenceSpace.getOffsetReferenceSpace( transform );
renderer.xr.setReferenceSpace( teleportSpaceOffset );
}
*/
}
} }
xrf.frag.q = function(v, opts){ xrf.frag.q = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts

View file

@ -21,8 +21,8 @@
<a class="btn-foot" id="model" target="_blank" href="">⬇️ model</a> <a class="btn-foot" id="model" target="_blank" href="">⬇️ model</a>
<textarea style="display:none"></textarea> <textarea style="display:none"></textarea>
<a-scene light="defaultLightsEnabled: false"> <a-scene light="defaultLightsEnabled: false">
<a-entity id="player" > <a-entity id="player" wasd-controls>
<a-entity camera="fov:90" position="0 1.6 0" wasd-controls id="camera"></a-entity> <a-entity camera="fov:90" position="0 1.6 0" id="camera"></a-entity>
<a-entity id="left-hand" laser-controls="hand: left" raycaster="objects:.collidable;far:5500" oculus-touch-controls="hand: left" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor"></a-entity> <a-entity id="left-hand" laser-controls="hand: left" raycaster="objects:.collidable;far:5500" oculus-touch-controls="hand: left" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor"></a-entity>
<a-entity id="right-hand" laser-controls="hand: right" raycaster="objects:.collidable;far:5500" oculus-touch-controls="hand: right" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor"></a-entity> <a-entity id="right-hand" laser-controls="hand: right" raycaster="objects:.collidable;far:5500" oculus-touch-controls="hand: right" blink-controls="cameraRig:#player; teleportOrigin: #camera; collisionEntities: #floor"></a-entity>
</a-entity> </a-entity>
@ -46,8 +46,6 @@
setupConsole( $('textarea') ) setupConsole( $('textarea') )
setupUrlBar( $('input#uri') ) setupUrlBar( $('input#uri') )
// add look-controls at last (otherwise it'll be buggy after scene-updates)
$('[camera]').setAttribute("look-controls","")
// add screenshot component with camera to capture proper equirects // add screenshot component with camera to capture proper equirects
$('a-scene').setAttribute("screenshot",{camera: "[camera]",width: 4096*2, height:2048*2}) $('a-scene').setAttribute("screenshot",{camera: "[camera]",width: 4096*2, height:2048*2})

View file

@ -83,10 +83,16 @@
window.addEventListener( 'resize', onWindowResize ); window.addEventListener( 'resize', onWindowResize );
let cameraRig = new THREE.Group()
cameraRig.position.set( 0, 0, 0 );
cameraRig.add(camera)
scene.add(cameraRig)
// enable XR fragments // enable XR fragments
let XRF = xrfragment.init({ let XRF = xrfragment.init({
THREE, THREE,
camera, camera:cameraRig,
scene, scene,
renderer, renderer,
debug: true, debug: true,
@ -116,7 +122,7 @@
window.XRF = XRF // expose to form window.XRF = XRF // expose to form
let file = document.location.search.length > 2 ? document.location.search.substr(1) + document.location.hash : './../../assets/example3.gltf#pos=0,1,15' let file = document.location.search.length > 2 ? document.location.search.substr(1) + document.location.hash : './../../assets/example3.gltf#pos=1,0,4&rot=0,-30,0'
$('#model').setAttribute("href","./../../asset/"+file) $('#model').setAttribute("href","./../../asset/"+file)
XRF.navigator.to( file ) XRF.navigator.to( file )
@ -134,12 +140,6 @@
//controls.maxPolarAngle = Math.PI / 2; //controls.maxPolarAngle = Math.PI / 2;
//controls.target = new THREE.Vector3(0,1.6,0) //controls.target = new THREE.Vector3(0,1.6,0)
//let cameraRig = new THREE.Group()
//cameraRig.position.set( 0, 1.6, 15 );
camera.position.set( 0, 1.6, 15 );
//cameraRig.add(camera)
//cameraRig.position.set( 0, 4, 15 );
//controls.update() //controls.update()
const geometry = new THREE.BufferGeometry(); const geometry = new THREE.BufferGeometry();
@ -147,22 +147,22 @@
const controller1 = renderer.xr.getController( 0 ); const controller1 = renderer.xr.getController( 0 );
controller1.add( new THREE.Line( geometry ) ); controller1.add( new THREE.Line( geometry ) );
scene.add( controller1 ); cameraRig.add( controller1 );
const controller2 = renderer.xr.getController( 1 ); const controller2 = renderer.xr.getController( 1 );
controller2.add( new THREE.Line( geometry ) ); controller2.add( new THREE.Line( geometry ) );
scene.add( controller2 ); cameraRig.add( controller2 );
const controllerModelFactory = new XRControllerModelFactory(); const controllerModelFactory = new XRControllerModelFactory();
const controllerGrip1 = renderer.xr.getControllerGrip( 0 ); const controllerGrip1 = renderer.xr.getControllerGrip( 0 );
controllerGrip1.add( controllerModelFactory.createControllerModel( controllerGrip1 ) ); controllerGrip1.add( controllerModelFactory.createControllerModel( controllerGrip1 ) );
scene.add( controllerGrip1 ); cameraRig.add( controllerGrip1 );
const controllerGrip2 = renderer.xr.getControllerGrip( 1 ); const controllerGrip2 = renderer.xr.getControllerGrip( 1 );
controllerGrip2.add( controllerModelFactory.createControllerModel( controllerGrip2 ) ); controllerGrip2.add( controllerModelFactory.createControllerModel( controllerGrip2 ) );
scene.add( controllerGrip2 ); cameraRig.add( controllerGrip2 );
setupConsole() setupConsole()

View file

@ -32,6 +32,7 @@ window.AFRAME.registerComponent('xrf', {
// override the camera-related XR Fragments so the camera-rig is affected // override the camera-related XR Fragments so the camera-rig is affected
let camOverride = (xrf,v,opts) => { let camOverride = (xrf,v,opts) => {
opts.camera = $('[camera]').object3D.parent opts.camera = $('[camera]').object3D.parent
console.dir(opts.camera)
xrf(v,opts) xrf(v,opts)
} }
@ -50,11 +51,25 @@ window.AFRAME.registerComponent('xrf', {
// cleanup xrf-get objects when resetting scene // cleanup xrf-get objects when resetting scene
XRF.reset = ((reset) => () => { XRF.reset = ((reset) => () => {
reset()
console.log("aframe reset") console.log("aframe reset")
let els = [...document.querySelectorAll('[xrf-get]')] let els = [...document.querySelectorAll('[xrf-get]')]
els.map( (el) => document.querySelector('a-scene').removeChild(el) ) els.map( (el) => document.querySelector('a-scene').removeChild(el) )
reset()
})(XRF.reset) })(XRF.reset)
// disable cam-controls (which block updating camerarig position)
let coms = ['look-controls','wasd-controls']
const setComponents = (com,state) => () => {
coms.forEach( (com) => {
let el = document.querySelector('['+com+']')
if(!el) return
el.components[com].enabled = state
})
}
aScene.addEventListener('enter-vr', setComponents(coms,false) )
aScene.addEventListener('enter-ar', setComponents(coms,false) )
aScene.addEventListener('exit-vr', setComponents(coms,true) )
aScene.addEventListener('exit-ar', setComponents(coms,true) )
}, },
}) })

View file

@ -19,6 +19,10 @@ xrfragment.InteractiveGroup = function(THREE,renderer,camera){
super(); super();
if( !renderer || !camera ) return if( !renderer || !camera ) return
// extract camera when camera-rig is passed
camera.traverse( (n) => String(n.type).match(/Camera/) ? camera = n : null )
const scope = this; const scope = this;
const raycaster = new Raycaster(); const raycaster = new Raycaster();

View file

@ -6,7 +6,7 @@ xrf.navigator.to = (url,event) => {
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
console.log("xrfragment: navigating to "+url) console.log("xrfragment: navigating to "+url)
if( !file || xrf.model.file == file ){ // we're already loaded if( !file || xrf.model.file == file ){ // we're already loaded
document.location.hash = `#${hash}` // just update the hash document.location.hash = `#${hash}` // just update the hash
xrf.eval( url, xrf.model ) // and eval URI XR fragments xrf.eval( url, xrf.model ) // and eval URI XR fragments
return resolve(xrf.model) return resolve(xrf.model)

View file

@ -81,10 +81,10 @@ xrf.frag.href = function(v, opts){
} }
let teleport = mesh.userData.XRF.href.exec = (e) => { let teleport = mesh.userData.XRF.href.exec = (e) => {
let portalArea = 1 // 2 meter
const meshWorldPosition = new THREE.Vector3(); const meshWorldPosition = new THREE.Vector3();
meshWorldPosition.setFromMatrixPosition(mesh.matrixWorld); meshWorldPosition.setFromMatrixPosition(mesh.matrixWorld);
let portalArea = 1 // 2 meter
const cameraDirection = new THREE.Vector3(); const cameraDirection = new THREE.Vector3();
camera.getWorldPosition(cameraDirection); camera.getWorldPosition(cameraDirection);
cameraDirection.sub(meshWorldPosition); cameraDirection.sub(meshWorldPosition);
@ -93,9 +93,11 @@ xrf.frag.href = function(v, opts){
const newPos = meshWorldPosition.clone().add(cameraDirection); const newPos = meshWorldPosition.clone().add(cameraDirection);
const distance = camera.position.distanceTo(newPos); const distance = camera.position.distanceTo(newPos);
if( renderer.xr.isPresenting && distance > portalArea ) return // too far away //if( distance > portalArea ){
if( !renderer.xr.isPresenting && !confirm("teleport to "+v.string+" ?") ) return
xrf.navigator.to(v.string) // ok let's surf to HREF! xrf.navigator.to(v.string) // ok let's surf to HREF!
console.log("teleport!")
xrf.emit('href',{click:true,mesh,xrf:v}) xrf.emit('href',{click:true,mesh,xrf:v})
} }

View file

@ -1,7 +1,47 @@
xrf.frag.pos = function(v, opts){ xrf.frag.pos = function(v, opts){
//if( renderer.xr.isPresenting ) return // too far away
let { frag, mesh, model, camera, scene, renderer, THREE} = opts let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(" └ setting camera position to "+v.string) console.log(" └ setting camera position to "+v.string)
camera.position.x = v.x
camera.position.y = v.y if( !frag.q ){
camera.position.z = v.z
if( true ){//!renderer.xr.isPresenting ){
console.dir(camera)
camera.position.x = v.x
camera.position.y = v.y
camera.position.z = v.z
}
/*
else{ // XR
let cameraWorldPosition = new THREE.Vector3()
camera.object3D.getWorldPosition(this.cameraWorldPosition)
let newRigWorldPosition = new THREE.Vector3(v.x,v.y,x.z)
// Finally update the cameras position
let newRigLocalPosition.copy(this.newRigWorldPosition)
if (camera.object3D.parent) {
camera.object3D.parent.worldToLocal(newRigLocalPosition)
}
camera.setAttribute('position', newRigLocalPosition)
// Also take the headset/camera rotation itself into account
if (this.data.rotateOnTeleport) {
this.teleportOcamerainQuaternion
.setFromEuler(new THREE.Euler(0, this.teleportOcamerain.object3D.rotation.y, 0))
this.teleportOcamerainQuaternion.invert()
this.teleportOcamerainQuaternion.multiply(this.hitEntityQuaternion)
// Rotate the camera based on calculated teleport ocamerain rotation
this.cameraRig.object3D.setRotationFromQuaternion(this.teleportOcamerainQuaternion)
}
console.log("XR")
const offsetPosition = { x: - v.x, y: - v.y, z: - v.z, w: 1 };
const offsetRotation = new THREE.Quaternion();
const transform = new XRRigidTransform( offsetPosition, offsetRotation );
const teleportSpaceOffset = xrf.baseReferenceSpace.getOffsetReferenceSpace( transform );
renderer.xr.setReferenceSpace( teleportSpaceOffset );
}
*/
}
} }