This commit is contained in:
parent
ae98cf9ca0
commit
c5f1f066dd
6 changed files with 185 additions and 79 deletions
84
com/controlattach.js
Normal file
84
com/controlattach.js
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
*Usage:
|
||||||
|
* <a-entity controlattach="el: #leftHand; class: foo"></a-entity>
|
||||||
|
* <a-entity id="leftHand">
|
||||||
|
* <a-entity class="foo" position="0 0 0" rotation="0 0 0" scale="0 0 0"></a-entity>
|
||||||
|
* <a-entity>
|
||||||
|
*
|
||||||
|
* NOTE: you can hint different position/rotation-offsets by adding controller-specific entities to the target:
|
||||||
|
*
|
||||||
|
* <a-entity id="leftHand">
|
||||||
|
* <a-entity class="foo" position="0 0 0" rotation="0 0 0" scale="0 0 0"></a-entity>
|
||||||
|
* <a-entity class="foo hand-tracking-controls" position="0 0 0" rotation="0 0 0" scale="0 0 0"></a-entity>
|
||||||
|
* <a-entity>
|
||||||
|
*
|
||||||
|
* The controllernames are hinted by the 'controllermodelready' event:
|
||||||
|
*
|
||||||
|
* 'hand-tracking-controls',
|
||||||
|
* 'meta-touch-controls',
|
||||||
|
* 'valve-index-controls',
|
||||||
|
* 'logitech-mx-ink-controls',
|
||||||
|
* 'windows-motion-controls',
|
||||||
|
* 'hp-mixed-reality-controls',
|
||||||
|
* 'generic-tracked-controller-controls',
|
||||||
|
* 'pico-controls',
|
||||||
|
* (and more in the future)
|
||||||
|
*/
|
||||||
|
|
||||||
|
AFRAME.registerComponent('controlattach', {
|
||||||
|
schema:{
|
||||||
|
el: {type:"selector"},
|
||||||
|
class: {type:"string"}
|
||||||
|
},
|
||||||
|
init: function(){
|
||||||
|
if( !this.data.el ) return console.warn(`controlattach.js: cannot find ${this.data.el}`)
|
||||||
|
this.controllers = {}
|
||||||
|
this.remember()
|
||||||
|
this.data.el.addEventListener('controllermodelready', this.bindPlaceHolders.bind(this,["controllermodelready"]) )
|
||||||
|
this.data.el.addEventListener('controllerconnected', this.bindPlaceHolders.bind(this,["controllerconnected"] ) )
|
||||||
|
},
|
||||||
|
|
||||||
|
bindPlaceHolders: function(type,e){
|
||||||
|
let controllerName = e.detail.name
|
||||||
|
let selector = `.${this.data.class}.${controllerName}`
|
||||||
|
let placeholder = this.data.el.querySelector(selector)
|
||||||
|
if( !placeholder ){
|
||||||
|
placeholder = this.data.el.querySelector(`.${this.data.class}`)
|
||||||
|
console.log("fallback")
|
||||||
|
}
|
||||||
|
if( !placeholder ) return console.warn("controlattach.js: could not find placeholder to attach to")
|
||||||
|
this.attachPlaceHolder(type,e,placeholder, controllerName)
|
||||||
|
},
|
||||||
|
|
||||||
|
attachPlaceHolder: function(type, el, placeholder, controllerName){
|
||||||
|
this.el.object3DMap = {} // unsync THREE <-> AFRAME entity
|
||||||
|
placeholder.object3D.add( this.obj )
|
||||||
|
if( controllerName != 'hand-tracking-controls' ){
|
||||||
|
// re-add for controller-models which don't re-add children ('meta-touch-controls' e.g.)
|
||||||
|
if( this.data.el.getObject3D("mesh") ){
|
||||||
|
this.data.el.getObject3D("mesh").add(placeholder.object3D)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// these are handled by the placeholder entity
|
||||||
|
this.obj.position.set(0,0,0);
|
||||||
|
this.obj.rotation.set(0,0,0);
|
||||||
|
this.obj.scale.set(1,1,1);
|
||||||
|
},
|
||||||
|
|
||||||
|
detach: function(){
|
||||||
|
this.el.setObject3D( this.obj.uuid, this.obj )
|
||||||
|
this.el.object3D.position.copy( this.position )
|
||||||
|
this.el.object3D.rotation.copy( this.rotation )
|
||||||
|
this.el.object3D.scale.copy( this.scale )
|
||||||
|
},
|
||||||
|
|
||||||
|
remember: function(){
|
||||||
|
this.obj = this.el.object3D
|
||||||
|
this.position = this.el.object3D.position.clone()
|
||||||
|
this.rotation = this.el.object3D.rotation.clone()
|
||||||
|
this.scale = this.el.object3D.scale.clone()
|
||||||
|
this.parent = this.el.object3D.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
@ -383,18 +383,13 @@ if( typeof AFRAME != 'undefined '){
|
||||||
instance.addEventListener('window.onresize', resize )
|
instance.addEventListener('window.onresize', resize )
|
||||||
instance.addEventListener('window.onmaximize', resize )
|
instance.addEventListener('window.onmaximize', resize )
|
||||||
|
|
||||||
const focus = (showdom) => (e) => {
|
const focus = (e) => {
|
||||||
this.el.emit('focus',e.detail)
|
this.el.emit('focus',e.detail)
|
||||||
if( this.el.components.window && this.data.renderer == 'canvas'){
|
|
||||||
this.el.components.window.show( showdom )
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.el.addEventListener('obbcollisionstarted', focus(false) )
|
this.el.addEventListener('obbcollisionstarted', focus )
|
||||||
this.el.sceneEl.addEventListener('enter-vr', focus(false) )
|
this.el.sceneEl.addEventListener('exit-vr', focus )
|
||||||
this.el.sceneEl.addEventListener('enter-ar', focus(false) )
|
this.el.sceneEl.addEventListener('exit-ar', focus )
|
||||||
this.el.sceneEl.addEventListener('exit-vr', focus(true) )
|
|
||||||
this.el.sceneEl.addEventListener('exit-ar', focus(true) )
|
|
||||||
|
|
||||||
instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera
|
instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
* displays app (icons) in 2D and 3D handmenu (enduser can launch desktop-like 'apps')
|
* displays app (icons) in 2D and 3D handmenu (enduser can launch desktop-like 'apps')
|
||||||
*
|
*
|
||||||
* ```html
|
* ```html
|
||||||
* <a-entity launcher="attach: #left-hand"></a-entity>
|
* <a-entity launcher="attach: #left-hand" wearable></a-entity>
|
||||||
*
|
*
|
||||||
* <a-assets>
|
* <a-assets>
|
||||||
* <a-mixin id="menuitem" geometry="primitive: plane; width: 0.15; height: 0.15; depth: 0.02" obb-collider="size: 0.03 0.03 0.03" ></a-mixin>
|
* <a-mixin id="menuitem" geometry="primitive: plane; width: 0.15; height: 0.15; depth: 0.02" obb-collider="size: 0.03 0.03 0.03" ></a-mixin>
|
||||||
|
|
@ -90,28 +90,8 @@ AFRAME.registerComponent('launcher', {
|
||||||
this.worldPosition = new THREE.Vector3()
|
this.worldPosition = new THREE.Vector3()
|
||||||
|
|
||||||
this.el.setAttribute("dom","")
|
this.el.setAttribute("dom","")
|
||||||
|
this.el.setAttribute("pressable","")
|
||||||
this.render()
|
this.render()
|
||||||
|
|
||||||
// this.tick = AFRAME.utils.throttleTick( this.tick, 100, this );
|
|
||||||
|
|
||||||
// this.el.sceneEl.addEventListener('enter-vr', (e) => this.preventAccidentalButtonPresses() )
|
|
||||||
// this.el.sceneEl.addEventListener('enter-ar', (e) => this.preventAccidentalButtonPresses() )
|
|
||||||
// this.el.sceneEl.addEventListener('exit-vr', (e) => this.preventAccidentalButtonPresses() )
|
|
||||||
// this.el.sceneEl.addEventListener('exit-ar', (e) => this.preventAccidentalButtonPresses() )
|
|
||||||
|
|
||||||
//if( this.data.attach ){
|
|
||||||
// if( this.isHand(this.data.attach) ){
|
|
||||||
// this.data.attach.addEventListener('model-loaded', () => {
|
|
||||||
// this.ready = true
|
|
||||||
// //this.data.attach.appendChild(this.el)
|
|
||||||
// let armature = this.data.attach.object3D.getObjectByName('Armature')
|
|
||||||
// if( !armature ) return console.warn('cannot find armature')
|
|
||||||
// let object3D = this.el.object3D.children[0]
|
|
||||||
// this.el.remove()
|
|
||||||
// setTimeout( () => this.data.attach.object3D.add(object3D), 500)
|
|
||||||
// })
|
|
||||||
// }else this.data.attach.appendChild(this.el)
|
|
||||||
//}else console.warn("launcher.js: attach-option not given")
|
|
||||||
},
|
},
|
||||||
|
|
||||||
isHand: (el) => {
|
isHand: (el) => {
|
||||||
|
|
@ -119,7 +99,7 @@ AFRAME.registerComponent('launcher', {
|
||||||
},
|
},
|
||||||
|
|
||||||
dom: {
|
dom: {
|
||||||
scale: 1,
|
scale: 0.4,
|
||||||
events: ['click'],
|
events: ['click'],
|
||||||
html: (me) => `<div class="iconmenu">loading components..</div>`,
|
html: (me) => `<div class="iconmenu">loading components..</div>`,
|
||||||
css: (me) => `.iconmenu {
|
css: (me) => `.iconmenu {
|
||||||
|
|
@ -203,14 +183,14 @@ AFRAME.registerComponent('launcher', {
|
||||||
let i = 0
|
let i = 0
|
||||||
let j = 0
|
let j = 0
|
||||||
let colors = this.data.colors
|
let colors = this.data.colors
|
||||||
const add2D = (launchCom,el,manifest) => {
|
const add2D = (launchCom,manifest) => {
|
||||||
let btn = document.createElement('button')
|
let btn = document.createElement('button')
|
||||||
let iconDefault = "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNMjAuMTcwMiAzTDIwLjE2NjMgMy4wMDQ1M0MyMS43NDU4IDMuMDkwODQgMjMgNC4zOTg5NiAyMyA2VjE4QzIzIDE5LjY1NjkgMjEuNjU2OSAyMSAyMCAyMUg0QzIuMzQzMTUgMjEgMSAxOS42NTY5IDEgMThWNkMxIDQuMzQzMTUgMi4zNDMxNSAzIDQgM0gyMC4xNzAyWk0xMC40NzY0IDVIMTYuNDc2NEwxMy4wODkgOUg3LjA4ODk5TDEwLjQ3NjQgNVpNNS4wODg5OSA5TDguNDc2NDQgNUg0QzMuNDQ3NzIgNSAzIDUuNDQ3NzIgMyA2VjlINS4wODg5OVpNMyAxMVYxOEMzIDE4LjU1MjMgMy40NDc3MiAxOSA0IDE5SDIwQzIwLjU1MjMgMTkgMjEgMTguNTUyMyAyMSAxOFYxMUgzWk0yMSA5VjZDMjEgNS40NDc3MSAyMC41NTIzIDUgMjAgNUgxOC40NzY0TDE1LjA4OSA5SDIxWiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgo8L3N2Zz4="
|
let iconDefault = "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBmaWxsLXJ1bGU9ImV2ZW5vZGQiCiAgICBjbGlwLXJ1bGU9ImV2ZW5vZGQiCiAgICBkPSJNMjAuMTcwMiAzTDIwLjE2NjMgMy4wMDQ1M0MyMS43NDU4IDMuMDkwODQgMjMgNC4zOTg5NiAyMyA2VjE4QzIzIDE5LjY1NjkgMjEuNjU2OSAyMSAyMCAyMUg0QzIuMzQzMTUgMjEgMSAxOS42NTY5IDEgMThWNkMxIDQuMzQzMTUgMi4zNDMxNSAzIDQgM0gyMC4xNzAyWk0xMC40NzY0IDVIMTYuNDc2NEwxMy4wODkgOUg3LjA4ODk5TDEwLjQ3NjQgNVpNNS4wODg5OSA5TDguNDc2NDQgNUg0QzMuNDQ3NzIgNSAzIDUuNDQ3NzIgMyA2VjlINS4wODg5OVpNMyAxMVYxOEMzIDE4LjU1MjMgMy40NDc3MiAxOSA0IDE5SDIwQzIwLjU1MjMgMTkgMjEgMTguNTUyMyAyMSAxOFYxMUgzWk0yMSA5VjZDMjEgNS40NDc3MSAyMC41NTIzIDUgMjAgNUgxOC40NzY0TDE1LjA4OSA5SDIxWiIKICAgIGZpbGw9ImN1cnJlbnRDb2xvciIKICAvPgo8L3N2Zz4="
|
||||||
btn.innerHTML = `${ manifest?.icons?.length > 0
|
btn.innerHTML = `${ manifest?.icons?.length > 0
|
||||||
? `<img src='${manifest.icons[0].src || iconDefault}' title='${manifest.name}: ${manifest.description}'/>`
|
? `<img src='${manifest.icons[0].src || iconDefault}' title='${manifest.name}: ${manifest.description}'/>`
|
||||||
: `${manifest.short_name || manifest.name}`
|
: `${manifest.short_name || manifest.name}`
|
||||||
}`
|
}`
|
||||||
btn.addEventListener('click', () => el.emit('launcher',{}) )
|
btn.addEventListener('click', () => launchCom.launcher() )
|
||||||
this.el.dom.appendChild(btn)
|
this.el.dom.appendChild(btn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,15 +201,21 @@ AFRAME.registerComponent('launcher', {
|
||||||
// console.warn(`could not find component '${launchComponentKey}' (forgot to include script-tag?)`)
|
// console.warn(`could not find component '${launchComponentKey}' (forgot to include script-tag?)`)
|
||||||
const manifest = c.manifest
|
const manifest = c.manifest
|
||||||
if( manifest ){
|
if( manifest ){
|
||||||
add2D(c,c.el,manifest)
|
add2D(c,manifest)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.setOriginToMiddle(this.el.object3D)
|
||||||
},
|
},
|
||||||
|
|
||||||
tick: function(){
|
setOriginToMiddle: function(object) {
|
||||||
|
var box = new THREE.Box3().setFromObject(object);
|
||||||
|
var center = new THREE.Vector3();
|
||||||
|
box.getCenter(center);
|
||||||
|
object.position.sub(center);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
manifest: { // HTML5 manifest to identify app to xrsh
|
manifest: { // HTML5 manifest to identify app to xrsh
|
||||||
"short_name": "launcher",
|
"short_name": "launcher",
|
||||||
"name": "App Launcher",
|
"name": "App Launcher",
|
||||||
|
|
@ -302,7 +288,11 @@ AFRAME.registerSystem('launcher',{
|
||||||
name:"foo"+i,
|
name:"foo"+i,
|
||||||
// icon: "https://..."
|
// icon: "https://..."
|
||||||
description: "lorem ipsum",
|
description: "lorem ipsum",
|
||||||
cb: () => alert("foo")
|
cb: () => {
|
||||||
|
let el = document.createElement("a-box")
|
||||||
|
el.setAttribute("position", `${Math.random()*10} ${Math.random()*10} ${Math.random()*10}`)
|
||||||
|
this.el.sceneEl.appendChild(el)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,7 +320,14 @@ AFRAME.registerSystem('launcher',{
|
||||||
let searchEvent = 'launcher'
|
let searchEvent = 'launcher'
|
||||||
let els = [...this.sceneEl.getElementsByTagName("*")]
|
let els = [...this.sceneEl.getElementsByTagName("*")]
|
||||||
let seen = {}
|
let seen = {}
|
||||||
this.launchables = [];
|
this.launchables = [
|
||||||
|
/*
|
||||||
|
* {
|
||||||
|
* manifest: {...}
|
||||||
|
* launcher: () => ....
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
];
|
||||||
|
|
||||||
// collect manually registered launchables
|
// collect manually registered launchables
|
||||||
this.registered.map( (launchable) => this.launchables.push(launchable) )
|
this.registered.map( (launchable) => this.launchables.push(launchable) )
|
||||||
|
|
@ -341,7 +338,9 @@ AFRAME.registerSystem('launcher',{
|
||||||
if( el.components ){
|
if( el.components ){
|
||||||
for( let i in el.components ){
|
for( let i in el.components ){
|
||||||
if( el.components[i].events && el.components[i].events[searchEvent] && !seen[i] ){
|
if( el.components[i].events && el.components[i].events[searchEvent] && !seen[i] ){
|
||||||
this.launchables.push(hasEvent = seen[i] = el.components[i])
|
let com = hasEvent = seen[i] = el.components[i]
|
||||||
|
com.launcher = () => com.el.emit('launcher',{})
|
||||||
|
this.launchables.push(com)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@ window.AFRAME.registerComponent('pinch-to-teleport', {
|
||||||
pos.x += direction.x
|
pos.x += direction.x
|
||||||
pos.z += direction.z
|
pos.z += direction.z
|
||||||
// set the new position
|
// set the new position
|
||||||
|
if( !this.data.rig ){
|
||||||
this.data.rig.setAttribute("position", pos);
|
this.data.rig.setAttribute("position", pos);
|
||||||
|
}
|
||||||
// !!! NOTE - it would be more efficient to do the
|
// !!! NOTE - it would be more efficient to do the
|
||||||
// position change on the players THREE.Object:
|
// position change on the players THREE.Object:
|
||||||
// `player.object3D.position.add(direction)`
|
// `player.object3D.position.add(direction)`
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,11 @@
|
||||||
|
|
||||||
AFRAME.registerComponent('pressable', {
|
AFRAME.registerComponent('pressable', {
|
||||||
schema: {
|
schema: {
|
||||||
pressDistance: {
|
pressDistance: { default: 0.003 },
|
||||||
default: 0.01
|
pressDuration: { default: 300 }
|
||||||
}
|
|
||||||
},
|
},
|
||||||
init: function() {
|
init: function() {
|
||||||
this.worldPosition = new THREE.Vector3();
|
this.worldPosition = new THREE.Vector3();
|
||||||
this.fingerWorldPosition = new THREE.Vector3();
|
|
||||||
this.raycaster = new THREE.Raycaster()
|
this.raycaster = new THREE.Raycaster()
|
||||||
this.handEls = document.querySelectorAll('[hand-tracking-controls]');
|
this.handEls = document.querySelectorAll('[hand-tracking-controls]');
|
||||||
this.pressed = false;
|
this.pressed = false;
|
||||||
|
|
@ -34,39 +32,41 @@ AFRAME.registerComponent('pressable', {
|
||||||
var handEl;
|
var handEl;
|
||||||
let minDistance = 5
|
let minDistance = 5
|
||||||
|
|
||||||
// compensate for xrf-get AFRAME component (which references non-reparented buffergeometries from the 3D model)
|
// compensate for an object inside a group
|
||||||
let object3D = this.el.object3D.child || this.el.object3D
|
let object3D = this.el.object3D.type == "Group" ? this.el.object3D.children[0] : this.el.object3D
|
||||||
|
|
||||||
for (var i = 0; i < handEls.length; i++) {
|
for (var i = 0; i < handEls.length; i++) {
|
||||||
handEl = handEls[i];
|
handEl = handEls[i];
|
||||||
let indexTipPosition = handEl.components['hand-tracking-controls'].indexTipPosition
|
let indexTip = handEl.object3D.getObjectByName('index-finger-tip')
|
||||||
// Apply the relative position to the parent's world position
|
if( ! indexTip ) return // nothing to do here
|
||||||
handEl.object3D.updateMatrixWorld();
|
|
||||||
handEl.object3D.getWorldPosition( this.fingerWorldPosition )
|
|
||||||
this.fingerWorldPosition.add( indexTipPosition )
|
|
||||||
|
|
||||||
this.raycaster.far = this.data.pressDistance
|
this.raycaster.far = this.data.pressDistance
|
||||||
// Create a direction vector (doesnt matter because it is supershort for 'touch' purposes)
|
|
||||||
const direction = new THREE.Vector3(1.0,0,0);
|
// Create a direction vector to negative Z
|
||||||
this.raycaster.set(this.fingerWorldPosition, direction)
|
const direction = new THREE.Vector3(0,0,-1.0);
|
||||||
|
direction.normalize()
|
||||||
|
this.raycaster.set(indexTip.position, direction)
|
||||||
intersects = this.raycaster.intersectObjects([object3D],true)
|
intersects = this.raycaster.intersectObjects([object3D],true)
|
||||||
|
|
||||||
object3D.getWorldPosition(this.worldPosition)
|
object3D.getWorldPosition(this.worldPosition)
|
||||||
|
|
||||||
distance = this.fingerWorldPosition.distanceTo(this.worldPosition)
|
distance = indexTip.position.distanceTo(this.worldPosition)
|
||||||
minDistance = distance < minDistance ? distance : minDistance
|
minDistance = distance < minDistance ? distance : minDistance
|
||||||
|
|
||||||
if (intersects.length ){
|
if (intersects.length ){
|
||||||
|
this.i = this.i || 0;
|
||||||
if( !this.pressed ){
|
if( !this.pressed ){
|
||||||
this.el.emit('pressedstarted');
|
this.el.emit('pressedstarted', intersects);
|
||||||
this.el.emit('click');
|
this.el.emit('click', intersects);
|
||||||
|
document.querySelector('[isoterminal]').components.isoterminal.term.term.write("\r\nclick"+(++this.i))
|
||||||
this.pressed = setTimeout( () => {
|
this.pressed = setTimeout( () => {
|
||||||
this.el.emit('pressedended');
|
this.el.emit('pressedended', intersects);
|
||||||
this.pressed = null
|
this.pressed = null
|
||||||
},300)
|
}, this.data.pressDuration )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.distance = minDistance
|
this.distance = minDistance
|
||||||
}
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,56 @@
|
||||||
AFRAME.registerComponent('wearable', {
|
AFRAME.registerComponent('wearable', {
|
||||||
schema:{
|
schema:{
|
||||||
el: {type:"selector"},
|
el: {type:"selector"},
|
||||||
position: {type:"vec3"},
|
controlPos: {type:"vec3"},
|
||||||
rotation: {type:"vec3"}
|
controlRot: {type:"vec3"},
|
||||||
|
handPos: {type:"vec3"},
|
||||||
|
handRot: {type:"vec3"}
|
||||||
},
|
},
|
||||||
init: function(){
|
init: function(){
|
||||||
this.position = this.el.object3D.position.clone()
|
this.remember()
|
||||||
this.rotation = this.el.object3D.rotation.clone()
|
|
||||||
if( !this.el ) return console.warn(`wear.js: cannot find ${this.data.el}`)
|
|
||||||
let ctl = this.data.el
|
|
||||||
|
|
||||||
// hand vs controller attach-heuristics
|
if( !this.data.el ) return console.warn(`wear.js: cannot find ${this.data.el}`)
|
||||||
this.el.sceneEl.addEventListener('controllersupdated', (e) => {
|
this.data.el.object3D.name = 'wearable'
|
||||||
if( !this.data.el.components['hand-tracking-controls'].controllerPresent ){
|
|
||||||
this.attach( ctl.components['hand-tracking-controls'].wristObject3D )
|
// hand vs controller multi attach-heuristics (intended to survived AFRAME updates)
|
||||||
}else{
|
this.data.el.addEventListener('controllermodelready', this.attachWhatEverController.bind(this) ) // downside: no model yet
|
||||||
this.attach( ctl.object3D )
|
this.data.el.addEventListener('model-loaded', this.attachWhatEverController.bind(this) ) // downside: only called once [model not added yet]
|
||||||
}
|
this.el.sceneEl.addEventListener('controllersupdated', this.attachWhatEverController.bind(this) ) // downside: only called when switching [no model yet]
|
||||||
})
|
},
|
||||||
|
|
||||||
|
attachWhatEverController: function(e){
|
||||||
|
setTimeout( () => { // needed because the events are called before the model was added via add())
|
||||||
|
let wrist = false
|
||||||
|
let hand = this.data.el.components['hand-tracking-controls']
|
||||||
|
if( hand && hand.controllerPresent ) wrist = hand.wristObject3D
|
||||||
|
this.attach( wrist || this.data.el.object3D)
|
||||||
|
this.update( wrist ? 'hand' : 'control')
|
||||||
|
},100)
|
||||||
},
|
},
|
||||||
|
|
||||||
attach: function(target){
|
attach: function(target){
|
||||||
if( target.uuid == this.el.object3D.parent.uuid ) return; // already attached
|
if( this.target && target.uuid == this.target.uuid ) return// already attached
|
||||||
target.add(this.el.object3D)
|
target.add(this.el.object3D )
|
||||||
this.el.object3D.position.copy( this.data.position )
|
this.target = target
|
||||||
this.el.object3D.rotation.copy( this.data.rotation )
|
},
|
||||||
target.updateMatrixWorld();
|
|
||||||
|
detach: function(){
|
||||||
|
this.parent.add(this.el.object3D)
|
||||||
|
this.el.object3D.position.copy( this.position )
|
||||||
|
this.el.object3D.rotation.copy( this.rotation )
|
||||||
|
},
|
||||||
|
|
||||||
|
remember: function(){
|
||||||
|
this.position = this.el.object3D.position.clone()
|
||||||
|
this.rotation = this.el.object3D.rotation.clone()
|
||||||
|
this.parent = this.el.object3D.parent
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function(type){
|
||||||
|
let position = type == 'hand' ? this.data.handPos : this.data.controlPos
|
||||||
|
let rotation = type == 'hand' ? this.data.handRot : this.data.controlRot
|
||||||
|
this.el.object3D.position.copy( position )
|
||||||
|
this.el.object3D.rotation.set( rotation.x, rotation.y, rotation.z )
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue