From 6f8403da9d4808fe21460841c4182ffd0225dbca Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Tue, 5 Mar 2024 11:56:06 +0000 Subject: [PATCH] work in progress [might break] --- example/aframe/sandbox/index.html | 7 ++-- src/3rd/js/aframe/index.js | 6 ++-- src/3rd/js/aframe/pressable.js | 51 ++++++++++++++++++++++++++++++ src/3rd/js/aframe/xrf-get.js | 5 +-- src/3rd/js/aframe/xrf-pinchmove.js | 28 ++++++++++++++++ src/3rd/js/index.js | 13 -------- src/3rd/js/three/xrf/href.js | 8 +++-- 7 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 src/3rd/js/aframe/pressable.js create mode 100644 src/3rd/js/aframe/xrf-pinchmove.js diff --git a/example/aframe/sandbox/index.html b/example/aframe/sandbox/index.html index 25d059d..e699a70 100644 --- a/example/aframe/sandbox/index.html +++ b/example/aframe/sandbox/index.html @@ -18,13 +18,13 @@ light="defaultLightsEnabled: false"> - + - + @@ -73,8 +73,7 @@ - - + diff --git a/src/3rd/js/aframe/index.js b/src/3rd/js/aframe/index.js index 3120309..5f9e84f 100644 --- a/src/3rd/js/aframe/index.js +++ b/src/3rd/js/aframe/index.js @@ -139,14 +139,14 @@ window.AFRAME.registerComponent('xrf', { let {mesh,clickHandler} = opts; let createEl = function(c){ let el = document.createElement("a-entity") - el.setAttribute("xrf-get",c.name ) // turn into AFRAME entity + el.setAttribute("xrf-get",c.name ) // turn into AFRAME entity + el.setAttribute("pressable", '' ) // detect click via hand-detection el.setAttribute("class","ray") // expose to raycaster - el.setAttribute("pressable", '') // detect hand-controller click // respond to cursor via laser-controls (https://aframe.io/docs/1.4.0/components/laser-controls.html) el.addEventListener("click", clickHandler ) el.addEventListener("mouseenter", mesh.userData.XRF.href.selected(true) ) el.addEventListener("mouseleave", mesh.userData.XRF.href.selected(false) ) - el.addEventListener("pressedstarted", clickHandler ) + el.addEventListener("pressedended", clickHandler ) $('a-scene').appendChild(el) } createEl(mesh) diff --git a/src/3rd/js/aframe/pressable.js b/src/3rd/js/aframe/pressable.js new file mode 100644 index 0000000..15f1555 --- /dev/null +++ b/src/3rd/js/aframe/pressable.js @@ -0,0 +1,51 @@ +// this makes WebXR hand controls able to click things (by touching it) + +AFRAME.registerComponent('pressable', { + schema: { + pressDistance: { + default: 0.01 + } + }, + init: function() { + this.worldPosition = new THREE.Vector3(); + this.handWorldPosition = new THREE.Vector3(); + this.handEls = document.querySelectorAll('[hand-tracking-controls]'); + this.pressed = false; + + }, + tick: function() { + var handEls = this.handEls; + var handEl; + var distance; + for (var i = 0; i < handEls.length; i++) { + handEl = handEls[i]; + let indexTipPosition = handEl.components['hand-tracking-controls'].indexTipPosition + handEl.object3D.localToWorld( this.handWorldPosition ) + this.handWorldPosition.add( indexTipPosition ) + + distance = this.calculateFingerDistance(this.handWorldPosition); + if( xrf.debug == 10 && this.el.id == "xrf-button_teleport_me_down_there" ){ debugger } + + if (distance < this.data.pressDistance && distance !== 0.0 ) { + if (!this.pressed) { + this.el.emit('pressedstarted'); + } + this.pressed = true; + return; + } + } + if (this.pressed) { + this.el.emit('pressedended'); + } + this.pressed = false; + }, + calculateFingerDistance: function(fingerPosition) { + var el = this.el; + //worldPosition.copy(el.object3D.position); + el.object3D.updateMatrixWorld(); + el.object3D.localToWorld(this.worldPosition); + if( xrf.debug == 10 && this.el.id == "xrf-button_teleport_me_down_there" ){ debugger } + + return this.worldPosition.distanceTo(fingerPosition); + } +}); diff --git a/src/3rd/js/aframe/xrf-get.js b/src/3rd/js/aframe/xrf-get.js index 80ed250..e3d2620 100644 --- a/src/3rd/js/aframe/xrf-get.js +++ b/src/3rd/js/aframe/xrf-get.js @@ -37,10 +37,11 @@ window.AFRAME.registerComponent('xrf-get', { mesh.scale.copy(world.scale) mesh.setRotationFromQuaternion(world.quat); }else{ - // lets create a dummy add function so that the mesh won't get reparented + // lets create a dummy add function so that the mesh won't get reparented during setObject3D this.el.object3D.add = (a) => a } - this.el.setObject3D('mesh',mesh) + this.el.object3D = mesh //setObject3D('mesh',mesh) + if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`) }else console.warn("xrf-get ignore: "+JSON.stringify(this.data)) }, evt && evt.timeout ? evt.timeout: 500) diff --git a/src/3rd/js/aframe/xrf-pinchmove.js b/src/3rd/js/aframe/xrf-pinchmove.js new file mode 100644 index 0000000..7eaf2e6 --- /dev/null +++ b/src/3rd/js/aframe/xrf-pinchmove.js @@ -0,0 +1,28 @@ +// poor man's way to move forward using hand gesture pinch + +window.AFRAME.registerComponent('xrf-pinchmove', { + schema:{ + rig: {type: "selector"} + }, + init: function(){ + + this.el.addEventListener("pinchended", () => { + // get the cameras world direction + let direction = new THREE.Vector3() + this.el.sceneEl.camera.getWorldDirection(direction); + // multiply the direction by a "speed" factor + direction.multiplyScalar(0.4) + // get the current position + var pos = player.getAttribute("position") + // add the direction vector + pos.x += direction.x + pos.z += direction.z + // set the new position + this.data.rig.setAttribute("position", pos); + // !!! NOTE - it would be more efficient to do the + // position change on the players THREE.Object: + // `player.object3D.position.add(direction)` + // but it would break "getAttribute("position") + }) + }, +}) diff --git a/src/3rd/js/index.js b/src/3rd/js/index.js index 068d034..c33dacf 100644 --- a/src/3rd/js/index.js +++ b/src/3rd/js/index.js @@ -38,19 +38,6 @@ xrf.detectCameraRig = function(opts){ } } -xrf.roundrobin = (frag, store) => { - if( !frag.args || frag.args.length == 0 ) return 0 - if( !store.rr ) store.rr = {} - let label = frag.fragment - if( store.rr[label] ) return store.rr[label].next() - store.rr[label] = frag.args - store.rr[label].next = () => { - store.rr[label].index = (store.rr[label].index + 1) % store.rr[label].length - return store.rr[label].index - } - return store.rr[label].index = 0 -} - xrf.stats = () => { // bookmarklet from https://github.com/zlgenuine/threejs_stats (function(){ diff --git a/src/3rd/js/three/xrf/href.js b/src/3rd/js/three/xrf/href.js index 6dcaa30..1119114 100644 --- a/src/3rd/js/three/xrf/href.js +++ b/src/3rd/js/three/xrf/href.js @@ -35,7 +35,11 @@ xrf.frag.href = function(v, opts){ let click = mesh.userData.XRF.href.exec = (e) => { - if( !mesh.material.visible ) return // ignore invisible nodes + if( !mesh.material || !mesh.material.visible ) return // ignore invisible nodes + if( e.type == "pressedended" && !e.detail ){ + console.dir(e) + return + } // bubble up! mesh.traverseAncestors( (n) => n.userData && n.userData.href && n.dispatchEvent({type:e.type,data:{}}) ) @@ -59,7 +63,7 @@ xrf.frag.href = function(v, opts){ } let selected = mesh.userData.XRF.href.selected = (state) => () => { - if( !mesh.material.visible && !mesh.isSRC ) return // ignore invisible nodes + if( (!mesh.material && !mesh.material.visible) && !mesh.isSRC ) return // ignore invisible nodes if( mesh.selected == state ) return // nothing changed xrf.interactive.objects.map( (o) => {