audio first attempt

This commit is contained in:
Leon van Kammen 2023-10-16 16:58:56 +02:00
parent 4c92ead37f
commit 5c2602d40b
12 changed files with 528 additions and 335 deletions

View File

@ -891,6 +891,8 @@ xrf.reset = () => {
xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false ) xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false )
nodes.map( disposeObject ) // leave non-XRF objects intact nodes.map( disposeObject ) // leave non-XRF objects intact
xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera) xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
if( xrf.audio ) xrf.audio.map( (a) => a.remove() )
xrf.audio = []
xrf.add( xrf.interactive ) xrf.add( xrf.interactive )
xrf.layers = 0 xrf.layers = 0
} }
@ -908,7 +910,6 @@ xrf.add = (object) => {
object.isXRF = true // mark for easy deletion when replacing scene object.isXRF = true // mark for easy deletion when replacing scene
xrf.scene.add(object) xrf.scene.add(object)
} }
// wrapper to survive in/outside modules // wrapper to survive in/outside modules
xrf.InteractiveGroup = function(THREE,renderer,camera){ xrf.InteractiveGroup = function(THREE,renderer,camera){
@ -1820,9 +1821,100 @@ xrf.frag.src.type = {}
xrf.frag.src.type['unknown'] = function( url, opts ){ xrf.frag.src.type['unknown'] = function( url, opts ){
return new Promise( (resolve,reject) => { return new Promise( (resolve,reject) => {
reject(`${url} mimetype not supported (yet)`) reject(`${url} mimetype not found or supported (yet)`)
}) })
} }
xrf.frag.t = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(` └ setting animation loop to ${v.x} ${v.y} ${v.z}` )
if( !model.animations || model.animations[0] == undefined ) return console.warn('no animation in scene')
model.mixer.t = v
let duration = model.animations[0].duration
let frames = model.animations[0].tracks[0].times.length
let mixer = model.mixer
mixer.loop = mixer.loop || {frameStart:0,frameStop:99999999,speed: 1}
let fps = frames / duration
mixer.loop.speed = v.x
mixer.loop.speedAbs = Math.abs(v.x)
mixer.loop.frameStart = v.y || mixer.loop.frameStart
mixer.loop.frameStop = v.z || mixer.loop.frameStop
// always recalculate time using frameStart/Stop
mixer.loop.timeStart = mixer.loop.frameStart / (fps * mixer.loop.speedAbs)
mixer.loop.timeStop = mixer.loop.frameStop / (fps * mixer.loop.speedAbs)
// update speed
mixer.timeScale = mixer.loop.speed
let updateTime = (time) => {
mixer.setTime(time)
mixer.time = Math.abs(mixer.time)
mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
// (re)trigger audio
xrf.audio.map( (a) => {
a.play()
a.currentTime = time
})
}
if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart )
// update loop when needed
if( !mixer.update.patched ){
let update = mixer.update
mixer.update = function(time){
mixer.time = Math.abs(mixer.time)
if( time == 0 ) return update.call(mixer,time)
if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop * mixer.loop.speedAbs ){
setTimeout( (time) => updateTime(time),0,mixer.loop.timeStart) // prevent recursion
}
return update.call( mixer, time )
}
mixer.update.patched = true
}
}
/*
* mimetype: audio/aac
* mimetype: audio/mpeg
* mimetype: audio/ogg
* mimetype: audio/weba
* mimetype: audio/wav
*/
let loadAudio = (mimetype) => function(url,opts){
let {mesh} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
// global audio
if( mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0 ){
let audio = window.document.createElement('audio')
// init fallback formats
let fallback = ['mp3','ogg','wav','weba','aac']
let addSource = (ext) => {
const src = window.document.createElement('source')
src.setAttribute("src", url)
src.setAttribute("type",mimetype)
audio.appendChild(src)
}
fallback
.filter( (e) => e != ext )
.map( addSource )
document.body.appendChild(audio)
xrf.audio.push(audio)
}
}
let audioMimeTypes = [
'audio/wav',
'audio/mpeg',
'audio/weba',
'audio/aac',
'audio/ogg',
'application/ogg'
]
audioMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadAudio(mimetype) )
/* /*
* mimetype: model/gltf+json * mimetype: model/gltf+json
@ -1889,52 +1981,6 @@ xrf.frag.src.type['image/png'] = function(url,opts){
xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png'] xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png']
xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png'] xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png']
xrf.frag.t = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(` └ setting animation loop to ${v.x} ${v.y} ${v.z}` )
if( !model.animations || model.animations[0] == undefined ) return console.warn('no animation in scene')
model.mixer.t = v
let duration = model.animations[0].duration
let frames = model.animations[0].tracks[0].times.length
let mixer = model.mixer
mixer.loop = mixer.loop || {frameStart:0,frameStop:99999999,speed: 1}
let fps = frames / duration
mixer.loop.speed = v.x
mixer.loop.speedAbs = Math.abs(v.x)
mixer.loop.frameStart = v.y || mixer.loop.frameStart
mixer.loop.frameStop = v.z || mixer.loop.frameStop
// always recalculate time using frameStart/Stop
mixer.loop.timeStart = mixer.loop.frameStart / (fps * mixer.loop.speedAbs)
mixer.loop.timeStop = mixer.loop.frameStop / (fps * mixer.loop.speedAbs)
// update speed
mixer.timeScale = mixer.loop.speed
let updateTime = (time) => {
mixer.setTime(time)
mixer.time = Math.abs(mixer.time)
mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
}
if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart )
// update loop when needed
if( !mixer.update.patched ){
let update = mixer.update
mixer.update = function(time){
mixer.time = Math.abs(mixer.time)
if( time == 0 ) return update.call(mixer,time)
if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop * mixer.loop.speedAbs ){
setTimeout( (time) => updateTime(time),0,mixer.loop.timeStart) // prevent recursion
}
return update.call( mixer, time )
}
mixer.update.patched = true
}
}
window.AFRAME.registerComponent('xrf', { window.AFRAME.registerComponent('xrf', {
schema: { schema: {
}, },

View File

@ -891,6 +891,8 @@ xrf.reset = () => {
xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false ) xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false )
nodes.map( disposeObject ) // leave non-XRF objects intact nodes.map( disposeObject ) // leave non-XRF objects intact
xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera) xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
if( xrf.audio ) xrf.audio.map( (a) => a.remove() )
xrf.audio = []
xrf.add( xrf.interactive ) xrf.add( xrf.interactive )
xrf.layers = 0 xrf.layers = 0
} }
@ -908,7 +910,6 @@ xrf.add = (object) => {
object.isXRF = true // mark for easy deletion when replacing scene object.isXRF = true // mark for easy deletion when replacing scene
xrf.scene.add(object) xrf.scene.add(object)
} }
// wrapper to survive in/outside modules // wrapper to survive in/outside modules
xrf.InteractiveGroup = function(THREE,renderer,camera){ xrf.InteractiveGroup = function(THREE,renderer,camera){
@ -1820,9 +1821,100 @@ xrf.frag.src.type = {}
xrf.frag.src.type['unknown'] = function( url, opts ){ xrf.frag.src.type['unknown'] = function( url, opts ){
return new Promise( (resolve,reject) => { return new Promise( (resolve,reject) => {
reject(`${url} mimetype not supported (yet)`) reject(`${url} mimetype not found or supported (yet)`)
}) })
} }
xrf.frag.t = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(` └ setting animation loop to ${v.x} ${v.y} ${v.z}` )
if( !model.animations || model.animations[0] == undefined ) return console.warn('no animation in scene')
model.mixer.t = v
let duration = model.animations[0].duration
let frames = model.animations[0].tracks[0].times.length
let mixer = model.mixer
mixer.loop = mixer.loop || {frameStart:0,frameStop:99999999,speed: 1}
let fps = frames / duration
mixer.loop.speed = v.x
mixer.loop.speedAbs = Math.abs(v.x)
mixer.loop.frameStart = v.y || mixer.loop.frameStart
mixer.loop.frameStop = v.z || mixer.loop.frameStop
// always recalculate time using frameStart/Stop
mixer.loop.timeStart = mixer.loop.frameStart / (fps * mixer.loop.speedAbs)
mixer.loop.timeStop = mixer.loop.frameStop / (fps * mixer.loop.speedAbs)
// update speed
mixer.timeScale = mixer.loop.speed
let updateTime = (time) => {
mixer.setTime(time)
mixer.time = Math.abs(mixer.time)
mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
// (re)trigger audio
xrf.audio.map( (a) => {
a.play()
a.currentTime = time
})
}
if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart )
// update loop when needed
if( !mixer.update.patched ){
let update = mixer.update
mixer.update = function(time){
mixer.time = Math.abs(mixer.time)
if( time == 0 ) return update.call(mixer,time)
if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop * mixer.loop.speedAbs ){
setTimeout( (time) => updateTime(time),0,mixer.loop.timeStart) // prevent recursion
}
return update.call( mixer, time )
}
mixer.update.patched = true
}
}
/*
* mimetype: audio/aac
* mimetype: audio/mpeg
* mimetype: audio/ogg
* mimetype: audio/weba
* mimetype: audio/wav
*/
let loadAudio = (mimetype) => function(url,opts){
let {mesh} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
// global audio
if( mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0 ){
let audio = window.document.createElement('audio')
// init fallback formats
let fallback = ['mp3','ogg','wav','weba','aac']
let addSource = (ext) => {
const src = window.document.createElement('source')
src.setAttribute("src", url)
src.setAttribute("type",mimetype)
audio.appendChild(src)
}
fallback
.filter( (e) => e != ext )
.map( addSource )
document.body.appendChild(audio)
xrf.audio.push(audio)
}
}
let audioMimeTypes = [
'audio/wav',
'audio/mpeg',
'audio/weba',
'audio/aac',
'audio/ogg',
'application/ogg'
]
audioMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadAudio(mimetype) )
/* /*
* mimetype: model/gltf+json * mimetype: model/gltf+json
@ -1889,49 +1981,3 @@ xrf.frag.src.type['image/png'] = function(url,opts){
xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png'] xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png']
xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png'] xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png']
xrf.frag.t = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(` └ setting animation loop to ${v.x} ${v.y} ${v.z}` )
if( !model.animations || model.animations[0] == undefined ) return console.warn('no animation in scene')
model.mixer.t = v
let duration = model.animations[0].duration
let frames = model.animations[0].tracks[0].times.length
let mixer = model.mixer
mixer.loop = mixer.loop || {frameStart:0,frameStop:99999999,speed: 1}
let fps = frames / duration
mixer.loop.speed = v.x
mixer.loop.speedAbs = Math.abs(v.x)
mixer.loop.frameStart = v.y || mixer.loop.frameStart
mixer.loop.frameStop = v.z || mixer.loop.frameStop
// always recalculate time using frameStart/Stop
mixer.loop.timeStart = mixer.loop.frameStart / (fps * mixer.loop.speedAbs)
mixer.loop.timeStop = mixer.loop.frameStop / (fps * mixer.loop.speedAbs)
// update speed
mixer.timeScale = mixer.loop.speed
let updateTime = (time) => {
mixer.setTime(time)
mixer.time = Math.abs(mixer.time)
mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
}
if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart )
// update loop when needed
if( !mixer.update.patched ){
let update = mixer.update
mixer.update = function(time){
mixer.time = Math.abs(mixer.time)
if( time == 0 ) return update.call(mixer,time)
if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop * mixer.loop.speedAbs ){
setTimeout( (time) => updateTime(time),0,mixer.loop.timeStart) // prevent recursion
}
return update.call( mixer, time )
}
mixer.update.patched = true
}
}

View File

@ -891,6 +891,8 @@ xrf.reset = () => {
xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false ) xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false )
nodes.map( disposeObject ) // leave non-XRF objects intact nodes.map( disposeObject ) // leave non-XRF objects intact
xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera) xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
if( xrf.audio ) xrf.audio.map( (a) => a.remove() )
xrf.audio = []
xrf.add( xrf.interactive ) xrf.add( xrf.interactive )
xrf.layers = 0 xrf.layers = 0
} }
@ -908,7 +910,6 @@ xrf.add = (object) => {
object.isXRF = true // mark for easy deletion when replacing scene object.isXRF = true // mark for easy deletion when replacing scene
xrf.scene.add(object) xrf.scene.add(object)
} }
// wrapper to survive in/outside modules // wrapper to survive in/outside modules
xrf.InteractiveGroup = function(THREE,renderer,camera){ xrf.InteractiveGroup = function(THREE,renderer,camera){
@ -1820,9 +1821,100 @@ xrf.frag.src.type = {}
xrf.frag.src.type['unknown'] = function( url, opts ){ xrf.frag.src.type['unknown'] = function( url, opts ){
return new Promise( (resolve,reject) => { return new Promise( (resolve,reject) => {
reject(`${url} mimetype not supported (yet)`) reject(`${url} mimetype not found or supported (yet)`)
}) })
} }
xrf.frag.t = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(` └ setting animation loop to ${v.x} ${v.y} ${v.z}` )
if( !model.animations || model.animations[0] == undefined ) return console.warn('no animation in scene')
model.mixer.t = v
let duration = model.animations[0].duration
let frames = model.animations[0].tracks[0].times.length
let mixer = model.mixer
mixer.loop = mixer.loop || {frameStart:0,frameStop:99999999,speed: 1}
let fps = frames / duration
mixer.loop.speed = v.x
mixer.loop.speedAbs = Math.abs(v.x)
mixer.loop.frameStart = v.y || mixer.loop.frameStart
mixer.loop.frameStop = v.z || mixer.loop.frameStop
// always recalculate time using frameStart/Stop
mixer.loop.timeStart = mixer.loop.frameStart / (fps * mixer.loop.speedAbs)
mixer.loop.timeStop = mixer.loop.frameStop / (fps * mixer.loop.speedAbs)
// update speed
mixer.timeScale = mixer.loop.speed
let updateTime = (time) => {
mixer.setTime(time)
mixer.time = Math.abs(mixer.time)
mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
// (re)trigger audio
xrf.audio.map( (a) => {
a.play()
a.currentTime = time
})
}
if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart )
// update loop when needed
if( !mixer.update.patched ){
let update = mixer.update
mixer.update = function(time){
mixer.time = Math.abs(mixer.time)
if( time == 0 ) return update.call(mixer,time)
if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop * mixer.loop.speedAbs ){
setTimeout( (time) => updateTime(time),0,mixer.loop.timeStart) // prevent recursion
}
return update.call( mixer, time )
}
mixer.update.patched = true
}
}
/*
* mimetype: audio/aac
* mimetype: audio/mpeg
* mimetype: audio/ogg
* mimetype: audio/weba
* mimetype: audio/wav
*/
let loadAudio = (mimetype) => function(url,opts){
let {mesh} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
// global audio
if( mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0 ){
let audio = window.document.createElement('audio')
// init fallback formats
let fallback = ['mp3','ogg','wav','weba','aac']
let addSource = (ext) => {
const src = window.document.createElement('source')
src.setAttribute("src", url)
src.setAttribute("type",mimetype)
audio.appendChild(src)
}
fallback
.filter( (e) => e != ext )
.map( addSource )
document.body.appendChild(audio)
xrf.audio.push(audio)
}
}
let audioMimeTypes = [
'audio/wav',
'audio/mpeg',
'audio/weba',
'audio/aac',
'audio/ogg',
'application/ogg'
]
audioMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadAudio(mimetype) )
/* /*
* mimetype: model/gltf+json * mimetype: model/gltf+json
@ -1889,50 +1981,4 @@ xrf.frag.src.type['image/png'] = function(url,opts){
xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png'] xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png']
xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png'] xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png']
xrf.frag.t = function(v, opts){
let { frag, mesh, model, camera, scene, renderer, THREE} = opts
console.log(` └ setting animation loop to ${v.x} ${v.y} ${v.z}` )
if( !model.animations || model.animations[0] == undefined ) return console.warn('no animation in scene')
model.mixer.t = v
let duration = model.animations[0].duration
let frames = model.animations[0].tracks[0].times.length
let mixer = model.mixer
mixer.loop = mixer.loop || {frameStart:0,frameStop:99999999,speed: 1}
let fps = frames / duration
mixer.loop.speed = v.x
mixer.loop.speedAbs = Math.abs(v.x)
mixer.loop.frameStart = v.y || mixer.loop.frameStart
mixer.loop.frameStop = v.z || mixer.loop.frameStop
// always recalculate time using frameStart/Stop
mixer.loop.timeStart = mixer.loop.frameStart / (fps * mixer.loop.speedAbs)
mixer.loop.timeStop = mixer.loop.frameStop / (fps * mixer.loop.speedAbs)
// update speed
mixer.timeScale = mixer.loop.speed
let updateTime = (time) => {
mixer.setTime(time)
mixer.time = Math.abs(mixer.time)
mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
}
if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart )
// update loop when needed
if( !mixer.update.patched ){
let update = mixer.update
mixer.update = function(time){
mixer.time = Math.abs(mixer.time)
if( time == 0 ) return update.call(mixer,time)
if( mixer.loop.speed > 0.0 && mixer.time > mixer.loop.timeStop * mixer.loop.speedAbs ){
setTimeout( (time) => updateTime(time),0,mixer.loop.timeStart) // prevent recursion
}
return update.call( mixer, time )
}
mixer.update.patched = true
}
}
export default xrf; export default xrf;

File diff suppressed because one or more lines are too long

BIN
example/assets/test.ogg Normal file

Binary file not shown.

3
make
View File

@ -70,7 +70,8 @@ build_js(){
src/3rd/js/*.js \ src/3rd/js/*.js \
src/3rd/js/three/*.js \ src/3rd/js/three/*.js \
src/3rd/js/three/xrmacro/*.js \ src/3rd/js/three/xrmacro/*.js \
src/3rd/js/three/xrf/*.js > dist/xrfragment.three.js src/3rd/js/three/xrf/*.js \
src/3rd/js/three/xrf/src/*.js > dist/xrfragment.three.js
# add THREE module # add THREE module
cat dist/xrfragment.three.js > dist/xrfragment.three.module.js cat dist/xrfragment.three.js > dist/xrfragment.three.module.js
echo "export default xrf;" >> dist/xrfragment.three.module.js echo "export default xrf;" >> dist/xrfragment.three.module.js

View File

@ -90,6 +90,8 @@ xrf.reset = () => {
xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false ) xrf.scene.traverse( (child) => child.isXRF ? nodes.push(child) : false )
nodes.map( disposeObject ) // leave non-XRF objects intact nodes.map( disposeObject ) // leave non-XRF objects intact
xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera) xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera)
if( xrf.audio ) xrf.audio.map( (a) => a.remove() )
xrf.audio = []
xrf.add( xrf.interactive ) xrf.add( xrf.interactive )
xrf.layers = 0 xrf.layers = 0
} }
@ -107,4 +109,3 @@ xrf.add = (object) => {
object.isXRF = true // mark for easy deletion when replacing scene object.isXRF = true // mark for easy deletion when replacing scene
xrf.scene.add(object) xrf.scene.add(object)
} }

View File

@ -153,72 +153,6 @@ xrf.frag.src.type = {}
xrf.frag.src.type['unknown'] = function( url, opts ){ xrf.frag.src.type['unknown'] = function( url, opts ){
return new Promise( (resolve,reject) => { return new Promise( (resolve,reject) => {
reject(`${url} mimetype not supported (yet)`) reject(`${url} mimetype not found or supported (yet)`)
}) })
} }
/*
* mimetype: model/gltf+json
*/
xrf.frag.src.type['gltf'] = function( url, opts ){
return new Promise( (resolve,reject) => {
let {mesh,src} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
let loader
const Loader = xrf.loaders[ext]
if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext
if( !dir.match("://") ){ // force relative path
dir = dir[0] == './' ? dir : `./${dir}`
loader = new Loader().setPath( dir )
}else loader = new Loader()
loader.load(url, (model) => {
resolve(model)
})
})
}
/*
* mimetype: image/png
* mimetype: image/jpg
* mimetype: image/gif
*/
xrf.frag.src.type['image/png'] = function(url,opts){
let {mesh} = opts
let restrictTo3DBoundingBox = mesh.geometry
const texture = new THREE.TextureLoader().load( url );
texture.colorSpace = THREE.SRGBColorSpace;
//const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: url.match(/(png|gif)/) ? true : false,
side: THREE.DoubleSide,
color: 0xFFFFFF,
opacity:1
});
// stretch image by pinning uv-coordinates to corners
if( mesh.geometry ){
if( mesh.geometry.attributes.uv ){ // buffergeometries
let uv = mesh.geometry.attributes.uv;
// i u v
uv.setXY(0, 0, 0 )
uv.setXY(1, 1, 0 )
uv.setXY(2, 0, 1 )
uv.setXY(3, 1, 1 )
}else {
console.warn("xrfragment: uv's of ${url} might be off for non-buffer-geometries *TODO*")
//if( geometry.faceVertexUvs ){
// *TODO* force uv's of dynamically created geometries (in threejs)
//}
}
}
mesh.material = material
}
xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png']
xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png']

View File

@ -0,0 +1,42 @@
/*
* mimetype: audio/aac
* mimetype: audio/mpeg
* mimetype: audio/ogg
* mimetype: audio/weba
* mimetype: audio/wav
*/
let loadAudio = (mimetype) => function(url,opts){
let {mesh} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
// global audio
if( mesh.position.x == 0 && mesh.position.y == 0 && mesh.position.z == 0 ){
let audio = window.document.createElement('audio')
// init fallback formats
let fallback = ['mp3','ogg','wav','weba','aac']
let addSource = (ext) => {
const src = window.document.createElement('source')
src.setAttribute("src", url)
src.setAttribute("type",mimetype)
audio.appendChild(src)
}
fallback
.filter( (e) => e != ext )
.map( addSource )
document.body.appendChild(audio)
xrf.audio.push(audio)
}
}
let audioMimeTypes = [
'audio/wav',
'audio/mpeg',
'audio/weba',
'audio/aac',
'audio/ogg',
'application/ogg'
]
audioMimeTypes.map( (mimetype) => xrf.frag.src.type[ mimetype ] = loadAudio(mimetype) )
// *TODO* https://www.svgrepo.com/svg/20195/play-button should trigger play?

View File

@ -0,0 +1,23 @@
/*
* mimetype: model/gltf+json
*/
xrf.frag.src.type['gltf'] = function( url, opts ){
return new Promise( (resolve,reject) => {
let {mesh,src} = opts
let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url)
let loader
const Loader = xrf.loaders[ext]
if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext
if( !dir.match("://") ){ // force relative path
dir = dir[0] == './' ? dir : `./${dir}`
loader = new Loader().setPath( dir )
}else loader = new Loader()
loader.load(url, (model) => {
resolve(model)
})
})
}

View File

@ -0,0 +1,42 @@
/*
* mimetype: image/png
* mimetype: image/jpg
* mimetype: image/gif
*/
xrf.frag.src.type['image/png'] = function(url,opts){
let {mesh} = opts
let restrictTo3DBoundingBox = mesh.geometry
const texture = new THREE.TextureLoader().load( url );
texture.colorSpace = THREE.SRGBColorSpace;
//const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: url.match(/(png|gif)/) ? true : false,
side: THREE.DoubleSide,
color: 0xFFFFFF,
opacity:1
});
// stretch image by pinning uv-coordinates to corners
if( mesh.geometry ){
if( mesh.geometry.attributes.uv ){ // buffergeometries
let uv = mesh.geometry.attributes.uv;
// i u v
uv.setXY(0, 0, 0 )
uv.setXY(1, 1, 0 )
uv.setXY(2, 0, 1 )
uv.setXY(3, 1, 1 )
}else {
console.warn("xrfragment: uv's of ${url} might be off for non-buffer-geometries *TODO*")
//if( geometry.faceVertexUvs ){
// *TODO* force uv's of dynamically created geometries (in threejs)
//}
}
}
mesh.material = material
}
xrf.frag.src.type['image/gif'] = xrf.frag.src.type['image/png']
xrf.frag.src.type['image/jpg'] = xrf.frag.src.type['image/png']

View File

@ -25,6 +25,11 @@ xrf.frag.t = function(v, opts){
mixer.setTime(time) mixer.setTime(time)
mixer.time = Math.abs(mixer.time) mixer.time = Math.abs(mixer.time)
mixer.update(0) // (forgetting) this little buddy costed me lots of time :] mixer.update(0) // (forgetting) this little buddy costed me lots of time :]
// (re)trigger audio
xrf.audio.map( (a) => {
a.play()
a.currentTime = time
})
} }
if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart ) if( v.y > 0 || v.z > 0 ) updateTime( mixer.loop.timeStart )