added xrf-gaze for mobile (AR/VR)

This commit is contained in:
Leon van Kammen 2023-10-14 20:10:06 +02:00
parent 94f06d8c2d
commit b3c8d06955
8 changed files with 200 additions and 33 deletions

View file

@ -922,6 +922,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const _pointer = new Vector2();
const _event = { type: '', data: _pointer };
let object = {selected:false}
class InteractiveGroup extends Group {
@ -944,7 +945,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
if( nocollide.tid ) return // ratelimit
_event.type = "nocollide"
scope.objects.map( (c) => c.dispatchEvent(_event) )
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
nocollide.tid = setTimeout( () => nocollide.tid = null, 10 )
}
// Pointer Events
@ -968,15 +969,19 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const intersection = intersects[ 0 ];
const object = intersection.object;
object = intersection.object;
const uv = intersection.uv;
_event.type = event.type;
_event.data.set( uv.x, 1 - uv.y );
object.dispatchEvent( _event );
}else nocollide()
}else{
if( object.selected ) {
_event.type = 'mouseleave'
object.dispatchEvent(_event)
}
}
}
@ -1013,7 +1018,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const intersection = intersections[ 0 ];
const object = intersection.object;
object = intersection.object;
const uv = intersection.uv;
_event.type = events[ event.type ];
@ -1021,7 +1026,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
object.dispatchEvent( _event );
}else nocollide()
}else{
if( object.selected ) {
_event.type = 'mouseleave'
object.dispatchEvent(_event)
}
}
}
@ -1435,7 +1445,7 @@ xrf.frag.href = function(v, opts){
.catch( console.error )
}
let selected = (state) => () => {
let selected = mesh.userData.XRF.href.selected = (state) => () => {
if( mesh.selected == state ) return // nothing changed
xrf.interactive.objects.map( (o) => {
let newState = o.name == mesh.name ? state : false
@ -1456,7 +1466,7 @@ xrf.frag.href = function(v, opts){
mesh.addEventListener('click', click )
mesh.addEventListener('mousemove', selected(true) )
mesh.addEventListener('nocollide', selected(false) )
mesh.addEventListener('mouseleave', selected(false) )
// lazy add mesh (because we're inside a recursive traverse)
setTimeout( (mesh) => {
@ -2020,6 +2030,10 @@ window.AFRAME.registerComponent('xrf', {
})
aScene.emit('XRF',{})
// enable gaze-click on Mobile VR
aScene.setAttribute('xrf-gaze','')
})
}
@ -2139,6 +2153,66 @@ window.AFRAME.registerComponent('xrf-button', {
});
}
});
// gaze click on mobile VR
AFRAME.registerComponent('xrf-gaze',{
schema:{
spawn:{type:'boolean',default:false},
},
setGazer: function(state){
let cam = document.querySelector("[camera]")
if( state ){
if( cam.innerHTML.match(/cursor/) ) return; // avoid duplicate calls
cam.innerHTML = `<a-entity id="cursor" cursor="fuse: true; fuseTimeout: 1500"
animation__click="property: scale; startEvents: click; easing: easeInCubic; dur: 150; from: 0.1 0.1 0.1; to: 1 1 1"
animation__fusing="property: scale; startEvents: fusing; easing: easeInCubic; dur: 1500; from: 1 1 1; to: 0.1 0.1 0.1"
animation__mouseleave="property: scale; startEvents: mouseleave; easing: easeInCubic; dur: 500; to: 1 1 1"
raycaster="objects: .ray"
visible="true"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: #BBBBBB; shader: flat">
</a-entity>`
}else{
cam.innerHTML = ''
}
},
init:function(data){
this.immersive = false;
let enabled = () => AFRAME.utils.device.isMobile()
let setVisible = () => this.el.setAttribute('visible', enabled() )
this.setGazer(enabled())
setVisible();
document.querySelector("a-scene").addEventListener('exit-vr', () => {
this.immersive = false;
setVisible()
})
document.querySelector("a-scene").addEventListener('enter-vr', () => {
this.immersive = true;
setVisible()
if( !document.querySelector("#cursor") ) return
})
let highlightMesh = (state) => (e) => {
if( !e.target.object3D ) return
let obj = e.target.object3D.children[0]
if( obj.userData && obj.userData.XRF && obj.userData.XRF.href )
obj.userData.XRF.href.selected( state )()
}
this.el.addEventListener("mouseenter", highlightMesh(true) )
this.el.addEventListener("mouseleave", highlightMesh(false ) )
//this.el.addEventListener('click',function(evt){
// document.querySelector('a-scene').querySelector('#player').setAttribute('position',{
// x:this.getAttribute('position').x,
// y:this.getAttribute('position').y,
// z:this.getAttribute('position').z
// });
//});
}
});
window.AFRAME.registerComponent('xrf-get', {
schema: {
name: {type: 'string'},

View file

@ -922,6 +922,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const _pointer = new Vector2();
const _event = { type: '', data: _pointer };
let object = {selected:false}
class InteractiveGroup extends Group {
@ -944,7 +945,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
if( nocollide.tid ) return // ratelimit
_event.type = "nocollide"
scope.objects.map( (c) => c.dispatchEvent(_event) )
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
nocollide.tid = setTimeout( () => nocollide.tid = null, 10 )
}
// Pointer Events
@ -968,15 +969,19 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const intersection = intersects[ 0 ];
const object = intersection.object;
object = intersection.object;
const uv = intersection.uv;
_event.type = event.type;
_event.data.set( uv.x, 1 - uv.y );
object.dispatchEvent( _event );
}else nocollide()
}else{
if( object.selected ) {
_event.type = 'mouseleave'
object.dispatchEvent(_event)
}
}
}
@ -1013,7 +1018,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const intersection = intersections[ 0 ];
const object = intersection.object;
object = intersection.object;
const uv = intersection.uv;
_event.type = events[ event.type ];
@ -1021,7 +1026,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
object.dispatchEvent( _event );
}else nocollide()
}else{
if( object.selected ) {
_event.type = 'mouseleave'
object.dispatchEvent(_event)
}
}
}
@ -1435,7 +1445,7 @@ xrf.frag.href = function(v, opts){
.catch( console.error )
}
let selected = (state) => () => {
let selected = mesh.userData.XRF.href.selected = (state) => () => {
if( mesh.selected == state ) return // nothing changed
xrf.interactive.objects.map( (o) => {
let newState = o.name == mesh.name ? state : false
@ -1456,7 +1466,7 @@ xrf.frag.href = function(v, opts){
mesh.addEventListener('click', click )
mesh.addEventListener('mousemove', selected(true) )
mesh.addEventListener('nocollide', selected(false) )
mesh.addEventListener('mouseleave', selected(false) )
// lazy add mesh (because we're inside a recursive traverse)
setTimeout( (mesh) => {

View file

@ -922,6 +922,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const _pointer = new Vector2();
const _event = { type: '', data: _pointer };
let object = {selected:false}
class InteractiveGroup extends Group {
@ -944,7 +945,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
if( nocollide.tid ) return // ratelimit
_event.type = "nocollide"
scope.objects.map( (c) => c.dispatchEvent(_event) )
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
nocollide.tid = setTimeout( () => nocollide.tid = null, 10 )
}
// Pointer Events
@ -968,15 +969,19 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const intersection = intersects[ 0 ];
const object = intersection.object;
object = intersection.object;
const uv = intersection.uv;
_event.type = event.type;
_event.data.set( uv.x, 1 - uv.y );
object.dispatchEvent( _event );
}else nocollide()
}else{
if( object.selected ) {
_event.type = 'mouseleave'
object.dispatchEvent(_event)
}
}
}
@ -1013,7 +1018,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const intersection = intersections[ 0 ];
const object = intersection.object;
object = intersection.object;
const uv = intersection.uv;
_event.type = events[ event.type ];
@ -1021,7 +1026,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
object.dispatchEvent( _event );
}else nocollide()
}else{
if( object.selected ) {
_event.type = 'mouseleave'
object.dispatchEvent(_event)
}
}
}
@ -1435,7 +1445,7 @@ xrf.frag.href = function(v, opts){
.catch( console.error )
}
let selected = (state) => () => {
let selected = mesh.userData.XRF.href.selected = (state) => () => {
if( mesh.selected == state ) return // nothing changed
xrf.interactive.objects.map( (o) => {
let newState = o.name == mesh.name ? state : false
@ -1456,7 +1466,7 @@ xrf.frag.href = function(v, opts){
mesh.addEventListener('click', click )
mesh.addEventListener('mousemove', selected(true) )
mesh.addEventListener('nocollide', selected(false) )
mesh.addEventListener('mouseleave', selected(false) )
// lazy add mesh (because we're inside a recursive traverse)
setTimeout( (mesh) => {

View file

@ -209,7 +209,6 @@ function SnackBar(userOptions) {
if (userOptions.status !== undefined) {
_Options.status = userOptions.status;
}
console.dir(_Options)
}
snackbar.Open = function() {

View file

@ -85,6 +85,10 @@ window.AFRAME.registerComponent('xrf', {
})
aScene.emit('XRF',{})
// enable gaze-click on Mobile VR
aScene.setAttribute('xrf-gaze','')
})
}

View file

@ -0,0 +1,60 @@
// gaze click on mobile VR
AFRAME.registerComponent('xrf-gaze',{
schema:{
spawn:{type:'boolean',default:false},
},
setGazer: function(state){
let cam = document.querySelector("[camera]")
if( state ){
if( cam.innerHTML.match(/cursor/) ) return; // avoid duplicate calls
cam.innerHTML = `<a-entity id="cursor" cursor="fuse: true; fuseTimeout: 1500"
animation__click="property: scale; startEvents: click; easing: easeInCubic; dur: 150; from: 0.1 0.1 0.1; to: 1 1 1"
animation__fusing="property: scale; startEvents: fusing; easing: easeInCubic; dur: 1500; from: 1 1 1; to: 0.1 0.1 0.1"
animation__mouseleave="property: scale; startEvents: mouseleave; easing: easeInCubic; dur: 500; to: 1 1 1"
raycaster="objects: .ray"
visible="true"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: #BBBBBB; shader: flat">
</a-entity>`
}else{
cam.innerHTML = ''
}
},
init:function(data){
this.immersive = false;
let enabled = () => AFRAME.utils.device.isMobile()
let setVisible = () => this.el.setAttribute('visible', enabled() )
this.setGazer(enabled())
setVisible();
document.querySelector("a-scene").addEventListener('exit-vr', () => {
this.immersive = false;
setVisible()
})
document.querySelector("a-scene").addEventListener('enter-vr', () => {
this.immersive = true;
setVisible()
if( !document.querySelector("#cursor") ) return
})
let highlightMesh = (state) => (e) => {
if( !e.target.object3D ) return
let obj = e.target.object3D.children[0]
if( obj.userData && obj.userData.XRF && obj.userData.XRF.href )
obj.userData.XRF.href.selected( state )()
}
this.el.addEventListener("mouseenter", highlightMesh(true) )
this.el.addEventListener("mouseleave", highlightMesh(false ) )
//this.el.addEventListener('click',function(evt){
// document.querySelector('a-scene').querySelector('#player').setAttribute('position',{
// x:this.getAttribute('position').x,
// y:this.getAttribute('position').y,
// z:this.getAttribute('position').z
// });
//});
}
});

View file

@ -11,6 +11,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const _pointer = new Vector2();
const _event = { type: '', data: _pointer };
let object = {selected:false}
class InteractiveGroup extends Group {
@ -33,7 +34,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
if( nocollide.tid ) return // ratelimit
_event.type = "nocollide"
scope.objects.map( (c) => c.dispatchEvent(_event) )
nocollide.tid = setTimeout( () => nocollide.tid = null, 100 )
nocollide.tid = setTimeout( () => nocollide.tid = null, 10 )
}
// Pointer Events
@ -57,15 +58,19 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const intersection = intersects[ 0 ];
const object = intersection.object;
object = intersection.object;
const uv = intersection.uv;
_event.type = event.type;
_event.data.set( uv.x, 1 - uv.y );
object.dispatchEvent( _event );
}else nocollide()
}else{
if( object.selected ) {
_event.type = 'mouseleave'
object.dispatchEvent(_event)
}
}
}
@ -102,7 +107,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
const intersection = intersections[ 0 ];
const object = intersection.object;
object = intersection.object;
const uv = intersection.uv;
_event.type = events[ event.type ];
@ -110,7 +115,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){
object.dispatchEvent( _event );
}else nocollide()
}else{
if( object.selected ) {
_event.type = 'mouseleave'
object.dispatchEvent(_event)
}
}
}

View file

@ -106,7 +106,7 @@ xrf.frag.href = function(v, opts){
.catch( console.error )
}
let selected = (state) => () => {
let selected = mesh.userData.XRF.href.selected = (state) => () => {
if( mesh.selected == state ) return // nothing changed
xrf.interactive.objects.map( (o) => {
let newState = o.name == mesh.name ? state : false
@ -127,7 +127,7 @@ xrf.frag.href = function(v, opts){
mesh.addEventListener('click', click )
mesh.addEventListener('mousemove', selected(true) )
mesh.addEventListener('nocollide', selected(false) )
mesh.addEventListener('mouseleave', selected(false) )
// lazy add mesh (because we're inside a recursive traverse)
setTimeout( (mesh) => {