diff --git a/example/aframe/sandbox/index.html b/example/aframe/sandbox/index.html index ebaf27b..5774ba5 100644 --- a/example/aframe/sandbox/index.html +++ b/example/aframe/sandbox/index.html @@ -39,7 +39,7 @@ - + @@ -58,7 +58,6 @@ // reroute console messages to snackbar notifications console.log = ( (log) => function(str){ - if( str.match(/URL:/) ) str += "

(use back-button to go back)" if( String(str).match(/:.*#/) ) window.notify(str) log(str) })(console.log) diff --git a/example/assets/index.glb b/example/assets/index.glb index 7e89f5b..5b049a5 100644 Binary files a/example/assets/index.glb and b/example/assets/index.glb differ diff --git a/src/3rd/js/aframe/index.js b/src/3rd/js/aframe/index.js index 0f6b61a..01c5509 100644 --- a/src/3rd/js/aframe/index.js +++ b/src/3rd/js/aframe/index.js @@ -37,11 +37,11 @@ window.AFRAME.registerComponent('xrf', { els.map( (mesh) => { mesh.material.visible = false let el = document.createElement("a-entity") - el.setAttribute("xrf-get", `name: ${mesh.name};reparent:true` ) + el.setAttribute("xrf-get", mesh.name ) el.setAttribute("class","floor ray") $('a-scene').appendChild(el) }) - blinkControls = blinkControls.components['blink-controls'].queryCollisionEntities() + blinkControls = blinkControls.components['blink-controls'].update({collisionEntities:true}) } }) @@ -124,12 +124,20 @@ window.AFRAME.registerComponent('xrf', { els.map( (el) => document.querySelector('a-scene').removeChild(el) ) }) - aScene.addEventListener('enter-vr', () => { - // undo lookup-control shenanigans (which blocks updating camerarig position in VR) - document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = true - document.querySelector('[camera]').removeAttribute("look-controls") - document.querySelector('[camera]').removeAttribute("wasd-controls") - }) + // *TODO* workaround no longer needed? + // + // aScene.addEventListener('enter-vr', () => { + // // undo lookup-control shenanigans (which blocks updating camerarig position in VR) + // document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = true + // document.querySelector('[camera]').components['look-controls'].pause() //removeAttribute("look-controls") + // document.querySelector('[camera]').components['wasd-controls'].pause() //removeAttribute("wasd-controls") + // }) + // aScene.addEventListener('exit-vr', () => { + // // redo lookup-control shenanigans (which blocks updating camerarig position in VR) + // document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = false + // document.querySelector('[camera]').components['look-controls'].play() //setAttribute("look-controls",'') + // document.querySelector('[camera]').components['wasd-controls'].play() //setAttribute("wasd-controls",'') + // }) AFRAME.XRF.navigator.to(this.data) .then( (model) => { diff --git a/src/3rd/js/pubsub.js b/src/3rd/js/pubsub.js index 86c4988..a0044e2 100644 --- a/src/3rd/js/pubsub.js +++ b/src/3rd/js/pubsub.js @@ -73,3 +73,9 @@ xrf.emit.promise = function(e, opts){ delete opts.promise }) } + +xrf.addEventListener('reset', () => { +// *TODO* do this nicely +// xrf._listeners['renderPost'] = [] +// xrf._listeners['render'] = [] +}) diff --git a/src/3rd/js/three/index.js b/src/3rd/js/three/index.js index 6a80602..d54206d 100644 --- a/src/3rd/js/three/index.js +++ b/src/3rd/js/three/index.js @@ -80,6 +80,8 @@ xrf.reset = () => { xrf.interactive = xrf.interactiveGroup( xrf.THREE, xrf.renderer, xrf.camera) xrf.add( xrf.interactive ) xrf.layers = 0 + + // reset certain events xrf.emit('reset',{}) // remove mixers xrf.mixers.map( (m) => m.stop()) diff --git a/src/3rd/js/three/xrf/dynamic/XRWG-lines.js b/src/3rd/js/three/xrf/dynamic/XRWG-lines.js index eac1024..708bd52 100644 --- a/src/3rd/js/three/xrf/dynamic/XRWG-lines.js +++ b/src/3rd/js/three/xrf/dynamic/XRWG-lines.js @@ -51,14 +51,16 @@ xrf.drawLineToMesh = (opts) => { } } -xrf.addEventListener('render', (opts) => { - // update focusline - let {time,model} = opts - if( !xrf.clock ) return - xrf.focusLine.material.color.r = (1.0 + Math.sin( xrf.clock.getElapsedTime()*10 ))/2 - xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( xrf.clock.getElapsedTime() ) - xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( xrf.clock.getElapsedTime() *3 ) - xrf.focusLine.material.opacity = (0.25 + 0.15*Math.sin( xrf.clock.getElapsedTime() * 3 )) * xrf.focusLine.opacity; - if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2 - if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0 +xrf.addEventListener('navigateLoaded', (opts) => { + xrf.addEventListener('render', (opts) => { + // update focusline + let {time,model} = opts + if( !xrf.clock ) return + xrf.focusLine.material.color.r = (1.0 + Math.sin( xrf.clock.getElapsedTime()*10 ))/2 + xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( xrf.clock.getElapsedTime() ) + xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( xrf.clock.getElapsedTime() *3 ) + xrf.focusLine.material.opacity = (0.25 + 0.15*Math.sin( xrf.clock.getElapsedTime() * 3 )) * xrf.focusLine.opacity; + if( xrf.focusLine.opacity > 0.0 ) xrf.focusLine.opacity -= time*0.2 + if( xrf.focusLine.opacity < 0.0 ) xrf.focusLine.opacity = 0 + }) }) diff --git a/src/3rd/js/three/xrf/src/non-euclidian.js b/src/3rd/js/three/xrf/src/non-euclidian.js index 076de4e..c631cdb 100644 --- a/src/3rd/js/three/xrf/src/non-euclidian.js +++ b/src/3rd/js/three/xrf/src/non-euclidian.js @@ -14,22 +14,24 @@ xrf.portalNonEuclidian = function(opts){ cameraPosition: new THREE.Vector3(), raycaster: new THREE.Raycaster(), isLocal: opts.isLocal, - isLens: false + isLens: false, + isInside: false, + setStencil: (stencilRef) => mesh.portal.stencilObjects.traverse( (n) => showPortal(n, stencilRef == 0) && n.stencil && n.stencil(stencilRef) ), + positionObjectsIfNeeded: (pos,scale) => !mesh.portal.isLens && mesh.portal.stencilObjects.traverse( (n) => n.positionAtStencil && (n.positionAtStencil(pos,scale)) ) } // allow objects to flip between original and stencil position (which puts them behind stencilplane) const addStencilFeature = (n) => { if( n.stencil ) return n // run once - n.stencil = ( (pos,scale) => (sRef,newPos, newScale) => { - if( !mesh.portal.isLens ){ - n.position.copy( sRef == 0 ? pos : newPos ) - if( sRef > 0 ) n.scale.multiply( newScale ) - else n.scale.copy( scale ) - n.updateMatrixWorld(true) - } - xrf.portalNonEuclidian.selectStencil(n, sRef ) - } - )( n.position.clone(), n.scale.clone() ) + + n.stencil = (sRef ) => xrf.portalNonEuclidian.selectStencil(n, sRef ) + n.positionAtStencil = (pos,scale) => (newPos,newScale) => { + n.position.copy( newPos || pos ) + n.scale.copy( scale ) + n.updateMatrixWorld(true) + } + // curry function + n.positionAtStencil = n.positionAtStencil( n.position.clone(), n.scale.clone() ) return n } @@ -89,22 +91,23 @@ xrf.portalNonEuclidian = function(opts){ xrf.addEventListener('renderPost', (opts) => { let {scene,camera,time,render,renderer} = opts - if( mesh.portal && mesh.portal.stencilObjects ){ + if( mesh.portal.needUpdate && mesh.portal && mesh.portal.stencilObjects ){ + let cameraDirection = mesh.portal.cameraDirection + let cameraPosition = mesh.portal.cameraPosition let stencilRef = mesh.portal.stencilRef let newPos = mesh.portal.posWorld let stencilObject = mesh.portal.stencilObject let newScale = mesh.scale - let cameraDirection = mesh.portal.cameraDirection - let cameraPosition = mesh.portal.cameraPosition let raycaster = mesh.portal.raycaster + let cam = xrf.camera.getCam ? xrf.camera.getCam() : camera cam.getWorldPosition(cameraPosition) - if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals cam.getWorldDirection(cameraDirection) + if( cameraPosition.distanceTo(newPos) > 20.0 ) return // dont render far portals // init if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = true - mesh.portal.stencilObjects.traverse( (n) => showPortal(n,false) && n.stencil && n.stencil(stencilRef,newPos,newScale) ) + mesh.portal.setStencil(stencilRef) renderer.autoClear = false renderer.autoClearDepth = false renderer.autoClearColor = false @@ -116,7 +119,7 @@ xrf.portalNonEuclidian = function(opts){ renderer.autoClearDepth = true renderer.autoClearColor = true renderer.autoClearStencil = true - mesh.portal.stencilObjects.traverse( (n) => showPortal(n,true) && n.stencil && (n.stencil(0)) ) + mesh.portal.setStencil(0) if( !mesh.portal.isLocal || mesh.portal.isLens ) stencilObject.visible = false @@ -134,6 +137,9 @@ xrf.portalNonEuclidian = function(opts){ } mesh.portal.needUpdate = false }) + + + return this } @@ -147,6 +153,8 @@ xrf.portalNonEuclidian = function(opts){ .setupListeners() .setupStencilObjects(scene,opts) + // move portal objects to portalposition + mesh.portal.positionObjectsIfNeeded(mesh.portal.posWorld, mesh.scale) } xrf.portalNonEuclidian.selectStencil = (n, stencilRef, nested) => { @@ -179,4 +187,20 @@ xrf.addEventListener('parseModel',(opts) => { }) +// (re)set portalObject when entering/leaving a portal +xrf.addEventListener('href', (opts) => { + let {mesh,v} = opts + if( opts.click && mesh.portal ){ + if( !opts.click ) return + xrf.scene.traverse( (n) => { + if( !n.portal ) return + // since we're leaving this portal destination, lets move objects back to the portal + if( n.portal.isInside ) n.portal.positionObjectsIfNeeded( n.portal.posWorld, n.scale ) + n.portal.isInside = false + }) + mesh.portal.isInside = true + mesh.portal.positionObjectsIfNeeded() // move objects back to original pos (since we are going there) + } +}) + xrf.portalNonEuclidian.stencilRef = 1