diff --git a/example/assets/index.glb b/example/assets/index.glb index 2ac1398..0a7c03d 100644 Binary files a/example/assets/index.glb and b/example/assets/index.glb differ diff --git a/src/3rd/js/three/xrf/dynamic/filter.js b/src/3rd/js/three/xrf/dynamic/filter.js index 50eea44..09bdfa8 100644 --- a/src/3rd/js/three/xrf/dynamic/filter.js +++ b/src/3rd/js/three/xrf/dynamic/filter.js @@ -12,7 +12,9 @@ xrf.filter.scene = function(opts){ xrf.filter .sort(frag) // get (sorted) filters from XR Fragments .process(frag,scene) // show/hide things - + + scene.visible = true // always enable scene + return scene } @@ -25,22 +27,27 @@ xrf.filter.sort = function(frag){ } xrf.filter.process = function(frag,scene,opts){ - // include all when query starts with negative objectnames/tags are included - let firstFilter = frag.filters[0].filter.get() - let showAll = firstFilter.show === false - let showers = frag.filters.filter( (v) => v.filter.get().show === true ) - if( !showAll ) scene.traverse( (n) => n.visible = false ) + const hasName = (m,name,filter) => m.name == name + const hasNameOrTag = (m,name_or_tag,filter) => hasName(m,name_or_tag) || m.userData[filter.key] + const cleanupKey = (k) => k.replace(/[-\*]/g,'') - // reparent if first selector is positive and has no value - if( firstFilter.show === true ){ - let obj = scene.getObjectByName( firstFilter.key ) - while( scene.children.length > 0 ) scene.children[0].removeFromParent() - if(obj) scene.add(obj) + let firstFilter = frag.filters[0].filter.get() + let showers = frag.filters.filter( (v) => v.filter.get().show === true ) + + // reparent scene based on object in case it matches a primary (non-negating) selector + if( !firstFilter.value && firstFilter.show === true ){ + let obj + scene.traverse( (n) => hasName(n, firstFilter.key,firstFilter) && (obj = n) ) + if(obj){ + while( scene.children.length > 0 ) scene.children[0].removeFromParent() + scene.add( obj ) + } } - + + // then show/hide things based on secondary selectors frag.filters.map( (v) => { const filter = v.filter.get() - const name_or_tag = v.fragment.replace(/[-\*]/g,'') + const name_or_tag = cleanupKey(v.fragment) let seen = {} const setVisibleUnseen = (m,visible) => { @@ -50,7 +57,6 @@ xrf.filter.process = function(frag,scene,opts){ } scene.traverse( (m) => { - const isMatch = m.name == name_or_tag || m.userData[filter.key] // filter on value(expression) #foo=>3 e.g. if( filter.value && m.userData[filter.key] ){ @@ -63,12 +69,13 @@ xrf.filter.process = function(frag,scene,opts){ } // include/exclude object(s) when id/tag matches (#foo or #-foo e.g.) - if( isMatch ){ + if( hasNameOrTag(m,name_or_tag,filter) ){ m.visible = filter.show if( filter.deep ) m.traverse( (n) => n.visible = m.visible ) } }) }) + return xrf.filter } diff --git a/src/3rd/js/three/xrf/src.js b/src/3rd/js/three/xrf/src.js index 3bfad1c..f921b08 100644 --- a/src/3rd/js/three/xrf/src.js +++ b/src/3rd/js/three/xrf/src.js @@ -28,7 +28,7 @@ xrf.frag.src = function(v, opts){ mesh.add(model.scene) mesh.traverse( (n) => n.isSRC = n.isXRF = true ) // mark everything SRC xrf.emit('parseModel', {...opts, scene, model}) - if( mesh.material ) mesh.material.visible = false + if( mesh.material ) mesh.material.visible = false // hide placeholder object } const enableSourcePortation = (src) => { @@ -93,6 +93,13 @@ xrf.frag.src.eval = function(scene, opts, url){ xrf.frag.src.scale = function(scene, opts, url){ let { mesh, model, camera, renderer, THREE} = opts + // remove invisible objects (hidden by selectors) which might corrupt boundingbox size-detection + let cleanScene = scene.clone() + if( !cleanScene ) debugger + let remove = [] + cleanScene.traverse( (n) => !n.visible && n.children.length == 0 && (remove.push(n)) ) + remove.map( (n) => n.removeFromParent() ) + let restrictTo3DBoundingBox = mesh.geometry if( restrictTo3DBoundingBox ){ // spec 3 of https://xrfragment.org/#src @@ -100,23 +107,11 @@ xrf.frag.src.scale = function(scene, opts, url){ // normalize instanced objectsize to boundingbox let sizeFrom = new THREE.Vector3() let sizeTo = new THREE.Vector3() - let empty = new THREE.Object3D() - -// *TODO* exclude invisible objects from boundingbox size-detection -// -// THREE.Box3.prototype.expandByObject = (function(expandByObject){ -// return function(object,precise){ -// return expandByObject.call(this, object.visible ? object : empty, precise) -// } -// })(THREE.Box3.prototype.expandByObject) - new THREE.Box3().setFromObject(mesh).getSize(sizeTo) - new THREE.Box3().setFromObject(scene).getSize(sizeFrom) + new THREE.Box3().setFromObject(cleanScene).getSize(sizeFrom) let ratio = sizeFrom.divide(sizeTo) scene.scale.multiplyScalar( 1.0 / Math.max(ratio.x, ratio.y, ratio.z)); - // let factor = getMax(sizeTo) < getMax(sizeFrom) ? getMax(sizeTo) / getMax(sizeFrom) : getMax(sizeFrom) / getMax(sizeTo) - // scene.scale.multiplyScalar( factor ) }else{ // spec 4 of https://xrfragment.org/#src // spec 2 of https://xrfragment.org/#scaling%20of%20instanced%20objects @@ -131,30 +126,10 @@ xrf.frag.src.filterScene = (scene,opts) => { xrf.filter.scene({scene,frag}) if( scene.children.length == 1 ) scene.children[0].position.set(0,0,0) - /* - if( !frag.filter ){ - src = new THREE.Group() - if( Object.keys(frag).length > 0 ){ - for( var i in frag ){ - if( scene.getObjectByName(i) ){ - src.add( obj = scene.getObjectByName(i).clone(true) ) - } - hashbus.pub.fragment(i, Object.assign(opts,{frag, model,scene})) - } - } - if( src.children.length == 1 ) obj.position.set(0,0,0); - } - - // filtering of objects using query - if( Object.keys(frag).length > 1 ){ - src = scene - xrf.filter.scene(src,frag) - } - src.traverse( (m) => { + scene.traverse( (m) => { if( m.userData && (m.userData.src || m.userData.href) ) return ; // prevent infinite recursion hashbus.pub.mesh(m,{scene,recursive:true}) // cool idea: recursion-depth based distance between face & src }) - */ return scene } diff --git a/src/3rd/js/three/xrf/src/video.js b/src/3rd/js/three/xrf/src/video.js index 5d7c621..8123f68 100644 --- a/src/3rd/js/three/xrf/src/video.js +++ b/src/3rd/js/three/xrf/src/video.js @@ -16,7 +16,7 @@ let loadVideo = (mimetype) => function(url,opts){ mesh.material = mat // set range video.addEventListener('timeupdate', function timeupdate() { - if (video.t && video.currentTime < video.t.y || video.currentTime >= video.y.z ) { + if (video.t && video.currentTime < video.t.y || video.currentTime >= video.t.z ) { vid.currentTime = video.t.y } },false) diff --git a/test/aframe/filter.js b/test/aframe/filter.js index 60720ed..6c9067b 100644 --- a/test/aframe/filter.js +++ b/test/aframe/filter.js @@ -28,7 +28,7 @@ filterScene = (URI) => { scene = filterScene("#b") test = () => !scene.getObjectByName("a") && scene.getObjectByName("b").visible && - !scene.getObjectByName("c") + !scene.getObjectByName("c").visible console.assert( test(), {scene,reason:`objectname: #b => a = removed b = visible c = removed`}) scene = filterScene("#b*") @@ -68,6 +68,7 @@ test = () => scene.getObjectByName("a").visible && console.assert( test(), {scene,reason:`objectname: #-b&b => a = visible b = visible c = invisible`}) scene = filterScene("#score") +console.dir(scene) test = () => !scene.getObjectByName("a") && scene.getObjectByName("b").visible && !scene.getObjectByName("c").visible @@ -80,13 +81,13 @@ test = () => !scene.getObjectByName("a") && console.assert( test(), {scene,reason:`objectname: #score=>1 => a = removed b = visible c = invisible`}) scene = filterScene("#score=>3") -test = () => !scene.getObjectByName("a").visible && +test = () => !scene.getObjectByName("a") && !scene.getObjectByName("b").visible && !scene.getObjectByName("c").visible console.assert( test(), {scene,reason:`objectname: #score=>3 => a = invisible b = visible c = invisible`}) scene = filterScene("#score*=>1") -test = () => !scene.getObjectByName("a").visible && +test = () => !scene.getObjectByName("a") && scene.getObjectByName("b").visible && scene.getObjectByName("c").visible console.assert( test(), {scene,reason:`objectname: #score*=>1 => a = invisible b = visible c = visible`})