2023-05-12 22:06:21 +02:00
|
|
|
xrf.frag = {}
|
2023-05-17 21:31:28 +02:00
|
|
|
xrf.model = {}
|
2023-05-04 16:24:54 +02:00
|
|
|
|
2023-06-07 17:42:21 +02:00
|
|
|
xrf.init = ((init) => function(opts){
|
2023-09-21 13:05:30 +02:00
|
|
|
let scene = new opts.THREE.Group()
|
|
|
|
|
opts.scene.add(scene)
|
|
|
|
|
opts.scene = scene
|
2023-06-07 17:42:21 +02:00
|
|
|
init(opts)
|
2023-05-12 22:06:21 +02:00
|
|
|
if( opts.loaders ) Object.values(opts.loaders).map( xrf.patchLoader )
|
2023-05-17 21:31:28 +02:00
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.patchRenderer(opts.renderer)
|
2023-05-18 12:32:57 +02:00
|
|
|
xrf.navigator.init()
|
2023-06-07 17:42:21 +02:00
|
|
|
// return xrfragment lib as 'xrf' query functor (like jquery)
|
|
|
|
|
for ( let i in xrf ) xrf.query[i] = xrf[i]
|
|
|
|
|
return xrf.query
|
|
|
|
|
})(xrf.init)
|
2023-05-04 16:24:54 +02:00
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.patchRenderer = function(renderer){
|
|
|
|
|
renderer.xr.addEventListener( 'sessionstart', () => xrf.baseReferenceSpace = renderer.xr.getReferenceSpace() );
|
|
|
|
|
renderer.xr.enabled = true;
|
2023-05-10 19:12:15 +02:00
|
|
|
renderer.render = ((render) => function(scene,camera){
|
2023-05-12 22:06:21 +02:00
|
|
|
if( xrf.model && xrf.model.render )
|
|
|
|
|
xrf.model.render(scene,camera)
|
2023-05-10 19:12:15 +02:00
|
|
|
render(scene,camera)
|
|
|
|
|
})(renderer.render.bind(renderer))
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.patchLoader = function(loader){
|
2023-07-04 17:15:23 +02:00
|
|
|
if( loader.prototype.load.xrf_patched ) return // prevent patching aliased loaders twice
|
2023-05-04 16:24:54 +02:00
|
|
|
loader.prototype.load = ((load) => function(url, onLoad, onProgress, onError){
|
|
|
|
|
load.call( this,
|
|
|
|
|
url,
|
2023-06-07 17:42:21 +02:00
|
|
|
(model) => {
|
|
|
|
|
onLoad(model);
|
|
|
|
|
xrf.parseModel(model,url)
|
|
|
|
|
},
|
2023-05-04 16:24:54 +02:00
|
|
|
onProgress,
|
|
|
|
|
onError)
|
|
|
|
|
})(loader.prototype.load)
|
2023-07-04 17:15:23 +02:00
|
|
|
loader.prototype.load.xrf_patched = true
|
2023-05-04 16:24:54 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.getFile = (url) => url.split("/").pop().replace(/#.*/,'')
|
2023-05-05 18:53:42 +02:00
|
|
|
|
2023-05-12 22:06:21 +02:00
|
|
|
xrf.parseModel = function(model,url){
|
|
|
|
|
let file = xrf.getFile(url)
|
2023-05-05 18:53:42 +02:00
|
|
|
model.file = file
|
2023-05-18 17:11:11 +02:00
|
|
|
// eval embedded XR fragments
|
2023-09-15 19:42:37 +02:00
|
|
|
model.scene.traverse( (mesh) => xrf.hashbus.pub.mesh(mesh,model) )
|
2023-06-07 17:42:21 +02:00
|
|
|
// add animations
|
2023-06-08 18:53:11 +02:00
|
|
|
model.clock = new xrf.THREE.Clock();
|
|
|
|
|
model.mixer = new xrf.THREE.AnimationMixer(model.scene)
|
2023-10-11 13:46:38 +02:00
|
|
|
model.animations.map( (anim) => {
|
|
|
|
|
anim.action = model.mixer.clipAction( anim )
|
|
|
|
|
anim.action.play()
|
|
|
|
|
})
|
2023-09-15 19:42:37 +02:00
|
|
|
|
|
|
|
|
let tmp = new xrf.THREE.Vector3()
|
2023-06-07 17:42:21 +02:00
|
|
|
model.render = function(){
|
|
|
|
|
model.mixer.update( model.clock.getDelta() )
|
2023-05-05 13:26:17 +02:00
|
|
|
|
2023-09-15 19:42:37 +02:00
|
|
|
// update focusline
|
2023-09-21 13:05:30 +02:00
|
|
|
xrf.focusLine.material.color.r = (1.0 + Math.sin( model.clock.getElapsedTime()*10 ))/2
|
2023-09-15 19:42:37 +02:00
|
|
|
xrf.focusLine.material.dashSize = 0.2 + 0.02*Math.sin( model.clock.getElapsedTime() )
|
|
|
|
|
xrf.focusLine.material.gapSize = 0.1 + 0.02*Math.sin( model.clock.getElapsedTime() *3 )
|
|
|
|
|
xrf.focusLine.material.opacity = 0.25 + 0.15*Math.sin( model.clock.getElapsedTime() * 3 )
|
2023-05-12 22:06:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 19:42:37 +02:00
|
|
|
xrf.getLastModel = () => xrf.model.last
|
2023-05-12 22:06:21 +02:00
|
|
|
|
|
|
|
|
xrf.reset = () => {
|
2023-05-17 21:31:28 +02:00
|
|
|
const disposeObject = (obj) => {
|
|
|
|
|
if (obj.children.length > 0) obj.children.forEach((child) => disposeObject(child));
|
|
|
|
|
if (obj.geometry) obj.geometry.dispose();
|
|
|
|
|
if (obj.material) {
|
|
|
|
|
if (obj.material.map) obj.material.map.dispose();
|
|
|
|
|
obj.material.dispose();
|
2023-05-12 22:06:21 +02:00
|
|
|
}
|
2023-05-22 15:03:23 +02:00
|
|
|
obj.clear()
|
|
|
|
|
obj.removeFromParent()
|
2023-05-17 21:31:28 +02:00
|
|
|
return true
|
|
|
|
|
};
|
2023-05-22 15:03:23 +02:00
|
|
|
let nodes = []
|
|
|
|
|
xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false )
|
|
|
|
|
nodes.map( disposeObject ) // leave non-XRF objects intact
|
2023-05-18 12:32:57 +02:00
|
|
|
xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
|
2023-09-21 13:05:30 +02:00
|
|
|
xrf.add( xrf.interactive )
|
|
|
|
|
xrf.layers = 0
|
2023-05-12 22:06:21 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-17 21:31:28 +02:00
|
|
|
xrf.parseUrl = (url) => {
|
|
|
|
|
const urlObj = new URL( url.match(/:\/\//) ? url : String(`https://fake.com/${url}`).replace(/\/\//,'/') )
|
|
|
|
|
let dir = url.substring(0, url.lastIndexOf('/') + 1)
|
|
|
|
|
const file = urlObj.pathname.substring(urlObj.pathname.lastIndexOf('/') + 1);
|
|
|
|
|
const hash = url.match(/#/) ? url.replace(/.*#/,'') : ''
|
|
|
|
|
const ext = file.split('.').pop()
|
|
|
|
|
return {urlObj,dir,file,hash,ext}
|
2023-05-12 22:06:21 +02:00
|
|
|
}
|
2023-05-18 12:32:57 +02:00
|
|
|
|
|
|
|
|
xrf.add = (object) => {
|
|
|
|
|
object.isXRF = true // mark for easy deletion when replacing scene
|
|
|
|
|
xrf.scene.add(object)
|
|
|
|
|
}
|
2023-05-22 14:10:44 +02:00
|
|
|
|