xrsh-com/com/osbutton.js

87 lines
2.7 KiB
JavaScript

AFRAME.registerComponent('osbutton',{
data:{
width: {type: 'number', default: 0.4},
height: {type: 'number', default: 0.2},
depth: {type: 'number', default: 0.06},
color: {type: 'color', default: 'blue'},
distance: {type: 'number'},
label: {type: 'string'}
},
init: function(){
this
.createBox()
.setupDistanceTick()
},
setupDistanceTick: function(){
// we throttle by distance, to support scenes with loads of clickable objects (far away)
if( !this.data.distance ) this.data.distance = 0.9
this.distance = -1
this.worldPosition = new THREE.Vector3()
this.posCam = new THREE.Vector3()
this.tick = this.throttleByDistance( () => this.showSource() )
},
createBox: function(){
let geometry = this.geometry = new THREE.BoxGeometry(this.data.width, this.data.height, this.data.depth);
this.material = new THREE.MeshStandardMaterial({color: this.data.color });
this.mesh = new THREE.Mesh(this.geometry, this.material);
this.scaleChildToButton(this.el.object3D, this.mesh)
this.el.object3D.add(this.mesh)
return this
},
throttleByDistance: function(f){
return function(){
if( this.distance < 0 ) return f() // first call
if( !f.tid ){
let x = this.distance
let y = x*(x*0.05)*1000 // parabolic curve
f.tid = setTimeout( function(){
f.tid = null
f()
}, y )
}
}
},
showSource: function(){
this.el.sceneEl.camera.getWorldPosition(this.posCam)
this.el.object3D.getWorldPosition(this.worldPosition)
this.distance = this.posCam.distanceTo(this.worldPosition)
if( this.distance < this.data.distance ){
this.material.side = THREE.BackSide
}else{
this.material.side = THREE.FrontSide
}
},
scaleChildToButton: function(scene, mesh ){
let cleanScene = scene.clone()
let remove = []
const notVisible = (n) => !n.visible || (n.material && !n.material.visible)
cleanScene.traverse( (n) => notVisible(n) && n.children.length == 0 && (remove.push(n)) )
remove.map( (n) => n.removeFromParent() )
let restrictTo3DBoundingBox = mesh.geometry
if( restrictTo3DBoundingBox ){
// normalize instanced objectsize to boundingbox
let sizeFrom = new THREE.Vector3()
let sizeTo = new THREE.Vector3()
let empty = new THREE.Object3D()
new THREE.Box3().setFromObject(mesh).getSize(sizeTo)
new THREE.Box3().setFromObject(cleanScene).getSize(sizeFrom)
let ratio = sizeFrom.divide(sizeTo)
scene.children.map( (c) => {
if( c.uuid != mesh.uuid ){
c.scale.multiplyScalar( 1.0 / Math.max(ratio.x, ratio.y, ratio.z))
}
})
}
},
})