From d8d626b86fe25fe0439d7254a613f012b7743ba6 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Mon, 22 May 2023 18:58:05 +0200 Subject: [PATCH] work in progress [might break] --- dist/xrfragment.aframe.js | 154 ++++++++++++++++++++++++++---- example/aframe/sandbox/index.html | 54 ++++++----- src/3rd/aframe/index.js | 55 +---------- src/3rd/aframe/xrf-button.js | 108 +++++++++++++++++++++ src/3rd/aframe/xrf-get.js | 35 +++++++ src/3rd/aframe/xrf-wear.js | 26 +++++ 6 files changed, 341 insertions(+), 91 deletions(-) create mode 100644 src/3rd/aframe/xrf-button.js create mode 100644 src/3rd/aframe/xrf-get.js create mode 100644 src/3rd/aframe/xrf-wear.js diff --git a/dist/xrfragment.aframe.js b/dist/xrfragment.aframe.js index d5a0959..f22d6e3 100644 --- a/dist/xrfragment.aframe.js +++ b/dist/xrfragment.aframe.js @@ -1227,7 +1227,7 @@ window.AFRAME.registerComponent('xrf', { // override the camera-related XR Fragments so the camera-rig is affected let camOverride = (xrf,v,opts) => { - opts.camera = $('[camera]').object3D.parent + opts.camera = document.querySelector('[camera]').object3D.parent console.dir(opts.camera) xrf(v,opts) } @@ -1240,7 +1240,7 @@ window.AFRAME.registerComponent('xrf', { let {mesh,camera} = opts; let el = document.createElement("a-entity") el.setAttribute("xrf-get",mesh.name ) - el.setAttribute("class","collidable") + el.setAttribute("class","ray") el.addEventListener("click", mesh.userData.XRF.href.exec ) $('a-scene').appendChild(el) } @@ -1253,22 +1253,118 @@ window.AFRAME.registerComponent('xrf', { els.map( (el) => document.querySelector('a-scene').removeChild(el) ) })(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) ) + // undo lookup-control shenanigans (which blocks updating camerarig position in VR) + aScene.addEventListener('enter-vr', () => document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = true ) }, }) +window.AFRAME.registerComponent('xrf-button', { + schema: { + label: { + default: 'label' + }, + width: { + default: 0.11 + }, + toggable: { + default: false + }, + textSize: { + default: 0.66 + }, + color:{ + default: '#111' + }, + textColor:{ + default: '#fff' + }, + hicolor:{ + default: '#555555' + }, + action:{ + default: '' + } + }, + init: function() { + var el = this.el; + var labelEl = this.labelEl = document.createElement('a-entity'); + this.color = this.data.color + el.setAttribute('geometry', { + primitive: 'box', + width: this.data.width, + height: 0.05, + depth: 0.005 + }); + el.setAttribute('material', { + color: this.color, + transparent:true, + opacity:0.3 + }); + el.setAttribute('pressable', ''); + labelEl.setAttribute('position', '0 0 0.01'); + labelEl.setAttribute('text', { + value: this.data.label, + color: this.data.textColor, + align: 'center' + }); + labelEl.setAttribute('scale', `${this.data.textSize} ${this.data.textSize} ${this.data.textSize}`); + this.el.appendChild(labelEl); + this.bindMethods(); + this.el.addEventListener('stateadded', this.stateChanged); + this.el.addEventListener('stateremoved', this.stateChanged); + this.el.addEventListener('pressedstarted', this.onPressedStarted); + this.el.addEventListener('pressedended', this.onPressedEnded); + this.el.addEventListener('mouseenter', (e) => this.onMouseEnter(e) ); + this.el.addEventListener('mouseleave', (e) => this.onMouseLeave(e) ); + if( this.data.action ){ + this.el.addEventListener('click', new Function(this.data.action) ) + } + }, + bindMethods: function() { + this.stateChanged = this.stateChanged.bind(this); + this.onPressedStarted = this.onPressedStarted.bind(this); + this.onPressedEnded = this.onPressedEnded.bind(this); + }, + update: function(oldData) { + if (oldData.label !== this.data.label) { + this.labelEl.setAttribute('text', 'value', this.data.label); + } + }, + stateChanged: function() { + var color = this.el.is('pressed') ? this.data.hicolor : this.color; + this.el.setAttribute('material', { + color: color + }); + }, + onMouseEnter: function(){ + this.el.setAttribute('material', { color: this.data.hicolor }); + }, + onMouseLeave: function(){ + this.el.setAttribute('material', { color: this.color }); + }, + onPressedStarted: function() { + var el = this.el; + el.setAttribute('material', { + color: this.data.hicolor + }); + el.emit('click'); + if (this.data.togabble) { + if (el.is('pressed')) { + el.removeState('pressed'); + } else { + el.addState('pressed'); + } + } + }, + onPressedEnded: function() { + if (this.el.is('pressed')) { + return; + } + this.el.setAttribute('material', { + color: this.color + }); + } +}); window.AFRAME.registerComponent('xrf-get', { schema: { name: {type: 'string'}, @@ -1298,9 +1394,35 @@ window.AFRAME.registerComponent('xrf-get', { }) - if( this.el.className == "collidable" ) this.el.emit("update") + if( this.el.className == "ray" ) this.el.emit("update") } }); +window.AFRAME.registerComponent('xrf-wear', { + schema:{ + el: {type:"selector"}, + position: {type:"vec3"}, + rotation: {type:"vec3"} + }, + init: function(){ + $('a-scene').addEventListener('enter-vr', (e) => this.wear(e) ) + $('a-scene').addEventListener('exit-vr', (e) => this.unwear(e) ) + }, + wear: function(){ + if( !this.wearable ){ + let d = this.data + this.wearable = new THREE.Group() + this.el.object3D.children.map( (c) => this.wearable.add(c) ) + this.wearable.position.set( d.position.x, d.position.y, d.position.z) + this.wearable.rotation.set( d.rotation.x, d.rotation.y, d.rotation.z) + } + this.data.el.object3D.add(this.wearable) + }, + unwear: function(){ + this.data.el.remove(this.wearable) + this.wearable.children.map( (c) => this.el.object3D.add(c) ) + delete this.wearable + } +}) diff --git a/example/aframe/sandbox/index.html b/example/aframe/sandbox/index.html index 00f21a1..367f4f9 100644 --- a/example/aframe/sandbox/index.html +++ b/example/aframe/sandbox/index.html @@ -1,37 +1,43 @@ - - AFRAME - xrfragment sandbox - - + + AFRAME - xrfragment sandbox + + - + - - - + + +
- +
sourcecode ⬇️ model - + - - - - - + + + + + + + + + + + - - + }) + + diff --git a/src/3rd/aframe/index.js b/src/3rd/aframe/index.js index f4918f6..fb5ad06 100644 --- a/src/3rd/aframe/index.js +++ b/src/3rd/aframe/index.js @@ -31,7 +31,7 @@ window.AFRAME.registerComponent('xrf', { // override the camera-related XR Fragments so the camera-rig is affected let camOverride = (xrf,v,opts) => { - opts.camera = $('[camera]').object3D.parent + opts.camera = document.querySelector('[camera]').object3D.parent console.dir(opts.camera) xrf(v,opts) } @@ -44,7 +44,7 @@ window.AFRAME.registerComponent('xrf', { let {mesh,camera} = opts; let el = document.createElement("a-entity") el.setAttribute("xrf-get",mesh.name ) - el.setAttribute("class","collidable") + el.setAttribute("class","ray") el.addEventListener("click", mesh.userData.XRF.href.exec ) $('a-scene').appendChild(el) } @@ -57,54 +57,7 @@ window.AFRAME.registerComponent('xrf', { els.map( (el) => document.querySelector('a-scene').removeChild(el) ) })(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) ) + // undo lookup-control shenanigans (which blocks updating camerarig position in VR) + aScene.addEventListener('enter-vr', () => document.querySelector('[camera]').object3D.parent.matrixAutoUpdate = true ) }, }) - -window.AFRAME.registerComponent('xrf-get', { - schema: { - name: {type: 'string'}, - clone: {type: 'boolean', default:false} - }, - - init: function () { - - var el = this.el; - var meshname = this.data.name || this.data; - - this.el.addEventListener('update', (evt) => { - - let scene = AFRAME.XRF.scene - let mesh = scene.getObjectByName(meshname); - if (!mesh){ - console.error("mesh with name '"+meshname+"' not found in model") - return; - } - if( !this.data.clone ) mesh.parent.remove(mesh) - ////mesh.updateMatrixWorld(); - this.el.object3D.position.setFromMatrixPosition(scene.matrixWorld); - this.el.object3D.quaternion.setFromRotationMatrix(scene.matrixWorld); - mesh.xrf = true // mark for deletion by xrf - this.el.setObject3D('mesh', mesh ); - if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`) - - }) - - if( this.el.className == "collidable" ) this.el.emit("update") - - } - -}); - diff --git a/src/3rd/aframe/xrf-button.js b/src/3rd/aframe/xrf-button.js new file mode 100644 index 0000000..43ea9d6 --- /dev/null +++ b/src/3rd/aframe/xrf-button.js @@ -0,0 +1,108 @@ +window.AFRAME.registerComponent('xrf-button', { + schema: { + label: { + default: 'label' + }, + width: { + default: 0.11 + }, + toggable: { + default: false + }, + textSize: { + default: 0.66 + }, + color:{ + default: '#111' + }, + textColor:{ + default: '#fff' + }, + hicolor:{ + default: '#555555' + }, + action:{ + default: '' + } + }, + init: function() { + var el = this.el; + var labelEl = this.labelEl = document.createElement('a-entity'); + this.color = this.data.color + el.setAttribute('geometry', { + primitive: 'box', + width: this.data.width, + height: 0.05, + depth: 0.005 + }); + el.setAttribute('material', { + color: this.color, + transparent:true, + opacity:0.3 + }); + el.setAttribute('pressable', ''); + labelEl.setAttribute('position', '0 0 0.01'); + labelEl.setAttribute('text', { + value: this.data.label, + color: this.data.textColor, + align: 'center' + }); + labelEl.setAttribute('scale', `${this.data.textSize} ${this.data.textSize} ${this.data.textSize}`); + this.el.appendChild(labelEl); + this.bindMethods(); + this.el.addEventListener('stateadded', this.stateChanged); + this.el.addEventListener('stateremoved', this.stateChanged); + this.el.addEventListener('pressedstarted', this.onPressedStarted); + this.el.addEventListener('pressedended', this.onPressedEnded); + this.el.addEventListener('mouseenter', (e) => this.onMouseEnter(e) ); + this.el.addEventListener('mouseleave', (e) => this.onMouseLeave(e) ); + + if( this.data.action ){ + this.el.addEventListener('click', new Function(this.data.action) ) + } + }, + bindMethods: function() { + this.stateChanged = this.stateChanged.bind(this); + this.onPressedStarted = this.onPressedStarted.bind(this); + this.onPressedEnded = this.onPressedEnded.bind(this); + }, + update: function(oldData) { + if (oldData.label !== this.data.label) { + this.labelEl.setAttribute('text', 'value', this.data.label); + } + }, + stateChanged: function() { + var color = this.el.is('pressed') ? this.data.hicolor : this.color; + this.el.setAttribute('material', { + color: color + }); + }, + onMouseEnter: function(){ + this.el.setAttribute('material', { color: this.data.hicolor }); + }, + onMouseLeave: function(){ + this.el.setAttribute('material', { color: this.color }); + }, + onPressedStarted: function() { + var el = this.el; + el.setAttribute('material', { + color: this.data.hicolor + }); + el.emit('click'); + if (this.data.togabble) { + if (el.is('pressed')) { + el.removeState('pressed'); + } else { + el.addState('pressed'); + } + } + }, + onPressedEnded: function() { + if (this.el.is('pressed')) { + return; + } + this.el.setAttribute('material', { + color: this.color + }); + } +}); diff --git a/src/3rd/aframe/xrf-get.js b/src/3rd/aframe/xrf-get.js new file mode 100644 index 0000000..eab5c00 --- /dev/null +++ b/src/3rd/aframe/xrf-get.js @@ -0,0 +1,35 @@ +window.AFRAME.registerComponent('xrf-get', { + schema: { + name: {type: 'string'}, + clone: {type: 'boolean', default:false} + }, + + init: function () { + + var el = this.el; + var meshname = this.data.name || this.data; + + this.el.addEventListener('update', (evt) => { + + let scene = AFRAME.XRF.scene + let mesh = scene.getObjectByName(meshname); + if (!mesh){ + console.error("mesh with name '"+meshname+"' not found in model") + return; + } + if( !this.data.clone ) mesh.parent.remove(mesh) + ////mesh.updateMatrixWorld(); + this.el.object3D.position.setFromMatrixPosition(scene.matrixWorld); + this.el.object3D.quaternion.setFromRotationMatrix(scene.matrixWorld); + mesh.xrf = true // mark for deletion by xrf + this.el.setObject3D('mesh', mesh ); + if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`) + + }) + + if( this.el.className == "ray" ) this.el.emit("update") + + } + +}); + diff --git a/src/3rd/aframe/xrf-wear.js b/src/3rd/aframe/xrf-wear.js new file mode 100644 index 0000000..0babf4c --- /dev/null +++ b/src/3rd/aframe/xrf-wear.js @@ -0,0 +1,26 @@ +window.AFRAME.registerComponent('xrf-wear', { + schema:{ + el: {type:"selector"}, + position: {type:"vec3"}, + rotation: {type:"vec3"} + }, + init: function(){ + $('a-scene').addEventListener('enter-vr', (e) => this.wear(e) ) + $('a-scene').addEventListener('exit-vr', (e) => this.unwear(e) ) + }, + wear: function(){ + if( !this.wearable ){ + let d = this.data + this.wearable = new THREE.Group() + this.el.object3D.children.map( (c) => this.wearable.add(c) ) + this.wearable.position.set( d.position.x, d.position.y, d.position.z) + this.wearable.rotation.set( d.rotation.x, d.rotation.y, d.rotation.z) + } + this.data.el.object3D.add(this.wearable) + }, + unwear: function(){ + this.data.el.remove(this.wearable) + this.wearable.children.map( (c) => this.el.object3D.add(c) ) + delete this.wearable + } +})