From 786173a9e093c100536974647de3a845888a4d20 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Thu, 15 Feb 2024 10:58:09 +0000 Subject: [PATCH] work in progress [might break] --- example/assets/index.glb | Bin 8562560 -> 8562060 bytes src/3rd/js/three/util/optimize.js | 85 ++++++++++++++++++++++++++++++ src/3rd/js/three/xrf/src.js | 3 +- src/3rd/js/three/xrf/t.js | 21 -------- src/3rd/js/three/xrf/uv.js | 72 ++++++++++++++----------- 5 files changed, 127 insertions(+), 54 deletions(-) create mode 100644 src/3rd/js/three/util/optimize.js diff --git a/example/assets/index.glb b/example/assets/index.glb index a1b58b6eb62a94873dcefbf9aded6907f2314a6e..eab4a05e24313ebe6ff6f68aced8a6f3e1a74f8f 100644 GIT binary patch delta 26204 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 { + opts.animatedObjects = [] + + xrf.optimize + .checkAnimations(opts) + .freezeUnAnimatedObjects(opts) + .disableShadows(opts) + .disableEmbeddedLights(opts) + .removeDuplicateLights() +} + + // check unused animations +xrf.optimize.checkAnimations = (opts) => { + console.log("TODO: fix freezeUnAnimatedObjects for SRC's") + return xrf.optimize + + let {model} = opts + model.animations.map( (anim) => { + // collect zombie animations and warn user + let zombies = anim.tracks.map( (t) => { + let name = t.name.replace(/\..*/,'') + let obj = model.scene.getObjectByName(name) + if( !model.scene.getObjectByName(name) ) return {anim:anim.name,obj:name} + else opts.animatedObjects.push(name) + return undefined + }) + if( zombies.length > 0 ){ // only warn for zombies in main scene (because src-scenes might be filtered anyways) + zombies + .filter( (z) => z ) // filter out undefined + .map( (z) => console.warn(`gltf: object '${z.obj}' not found (anim: '${z.anim}'`) ) + console.warn(`TIP: remove dots in objectnames in blender (which adds dots when duplicating)`) + } + }) + return xrf.optimize +} + +xrf.optimize.freezeUnAnimatedObjects = (opts) => { + console.log("TODO: fix freezeUnAnimatedObjects for SRC's") + return xrf.optimize + + let {model} = opts + let scene = model.scene + // increase performance by freezing all objects + scene.traverse( (n) => n.matrixAutoUpdate = false ) + // except animated objects and children + scene.traverse( (n) => { + if( ~opts.animatedObjects.indexOf(n.name) ){ + n.matrixAutoUpdate = true + n.traverse( (m) => m.matrixAutoUpdate = true ) + } + }) + return xrf.optimize +} + +xrf.optimize.disableShadows = (opts) => { + opts.model.scene.traverse( (n) => { + if( n.castShadow !== undefined ) n.castShadow = false + }) + return xrf.optimize +} + +xrf.optimize.disableEmbeddedLights = (opts) => { + if( !opts.isSRC ) return xrf.optimize + // remove lights from SRC's + opts.model.scene.traverse( (n) => { + if( n.type.match(/light/i) ) n.remove() + }) + return xrf.optimize +} + +xrf.optimize.removeDuplicateLights = () => { + // local/extern src's can cause duplicate lights which tax performance + let lights = {} + xrf.scene.traverse( (n) => { + if( n.type.match(/light/i) ){ + if( !lights[n.name] ) lights[n.name] = true + else n.remove() + } + }) + return xrf.optimize +} + +xrf.addEventListener('parseModel', (opts) => { + xrf.optimize(opts) +}) diff --git a/src/3rd/js/three/xrf/src.js b/src/3rd/js/three/xrf/src.js index 8c5dbdf..87066d5 100644 --- a/src/3rd/js/three/xrf/src.js +++ b/src/3rd/js/three/xrf/src.js @@ -40,10 +40,11 @@ xrf.frag.src.addModel = (model,url,frag,opts) => { }else{ xrf.frag.src.scale( scene, opts, url ) // scale scene mesh.add(scene) - xrf.emit('parseModel', {...opts, isSRC:true, scene, model}) } // flag everything isSRC & isXRF mesh.traverse( (n) => { n.isSRC = n.isXRF = n[ opts.isLocal ? 'isSRCLocal' : 'isSRCExternal' ] = true }) + + xrf.emit('parseModel', {...opts, isSRC:true, scene, model}) } xrf.frag.src.renderAsPortal = (mesh) => { diff --git a/src/3rd/js/three/xrf/t.js b/src/3rd/js/three/xrf/t.js index d1b0e9d..792cc4e 100644 --- a/src/3rd/js/three/xrf/t.js +++ b/src/3rd/js/three/xrf/t.js @@ -51,25 +51,6 @@ xrf.addEventListener('parseModel', (opts) => { mixer.actions.push( mixer.clipAction( anim, model.scene ) ) }) - mixer.checkZombies = (animations) => { - if( mixer.zombieCheck ) return // fire only once - animations.map( (anim) => { - // collect zombie animations and warn user - let zombies = anim.tracks.map( (t) => { - let name = t.name.replace(/\..*/,'') - let obj = model.scene.getObjectByName(name) - return !model.scene.getObjectByName(name) ? {anim:anim.name,obj:name} : undefined - }) - if( zombies.length > 0 && mixer.i == 0 ){ // only warn for zombies in main scene (because src-scenes might be filtered anyways) - zombies - .filter( (z) => z ) // filter out undefined - .map( (z) => console.warn(`gltf: object '${z.obj}' not found (anim: '${z.anim}'`) ) - console.warn(`TIP: remove dots in objectnames in blender (which adds dots when duplicating)`) - } - }) - mixer.zombieCheck = true - } - mixer.play = (t) => { mixer.isPlaying = t.x !== undefined && t.x != t.y mixer.updateLoop(t) @@ -118,8 +99,6 @@ xrf.addEventListener('parseModel', (opts) => { mixer.update.patched = true } - mixer.checkZombies( model.animations) - // calculate total duration/frame based on longest animation mixer.duration = 0 if( model.animations.length ){ diff --git a/src/3rd/js/three/xrf/uv.js b/src/3rd/js/three/xrf/uv.js index 25eab18..d4a55c1 100644 --- a/src/3rd/js/three/xrf/uv.js +++ b/src/3rd/js/three/xrf/uv.js @@ -2,24 +2,23 @@ xrf.frag.uv = function(v, opts){ let { frag, mesh, model, camera, scene, renderer, THREE} = opts if( !mesh.geometry ) return // nothing to do here - if( v.floats.length < 2 ) return console.warn('xrfragment.js: got less than 4 uv values ') + if( v.floats.length != 4 ) return console.warn('xrfragment.js: got less than 4 uv values ') xrf.frag.uv.init(mesh) mesh.uv.u = v.floats[0] mesh.uv.v = v.floats[1] - mesh.uv.uspeed = v.floats[2] || 1.0 + mesh.uv.uspeed = v.floats[2] || 1.0 mesh.uv.vspeed = v.floats[3] || 1.0 - mesh.uv.ushift = v.shift[0] - mesh.uv.vshift = v.shift[1] - mesh.uv.uloop = v.shift[2] || false - mesh.uv.vloop = v.shift[3] || false - debugger + mesh.uv.ushift = v.shift[0] || v.floats[0] < 0 // negative u is always relative + mesh.uv.vshift = v.shift[1] || v.floats[1] < 0 // negative v is always relative + mesh.uv.uloop = v.shift[2] || false + mesh.uv.vloop = v.shift[3] || false mesh.onBeforeRender = xrf.frag.uv.scroll } xrf.frag.uv.init = function(mesh){ - if( !mesh.uv ) mesh.uv = {u:0, v:0, uspeed:1, vspeed:1, uloop:false, vloop:false, uv:false, ushift:false,vshift:false} + if( !mesh.uv ) mesh.uv = {u:0, v:0, uspeed:1, vspeed:1, uloop:false, vloop:false, uv:false} let uv = mesh.geometry.getAttribute("uv") if( !uv.old ) uv.old = mesh.geometry.getAttribute("uv").clone() @@ -33,34 +32,43 @@ xrf.frag.uv.scroll = function(){ // translate! for( let i = 0; i < uv.count; i++ ){ - let u = uv.getX(i) - let v = uv.getY(i) - let uTarget = (this.uv.ushift ? u : uv.old.getX(i) ) + this.uv.u - let vTarget = (this.uv.vshift ? v : uv.old.getY(i) ) + this.uv.v - // scroll U - if( this.uv.uloop ){ - u += this.uv.uspeed * xrf.clock.delta - }else{ - // recover from super-high uv-values due to looped scrolling - if( Math.abs(u-uTarget) > 1.0 ) u = uv.old.getX(i) - u = u > uTarget ? u + (this.uv.uspeed * -uTarget ) // -xrf.clock.delta) - : u + (this.uv.uspeed * uTarget ) // xrf.clock.delta) - diffU += Math.abs( u - uTarget ) // are we done yet? (non-looping mode) - } + if( this.uv.uspeed == 1.0 ) uv.setX(i, this.uv.ushift ? uv.getX(i) + this.uv.u : uv.old.getX(i) + this.uv.u ) + if( this.uv.vspeed == 1.0 ) uv.setY(i, this.uv.vshift ? uv.getY(i) + this.uv.v : uv.old.getY(i) + this.uv.v ) - // scroll V - if( this.uv.vloop ){ - v += this.uv.vspeed * xrf.clock.delta - }else{ - // recover from super-high uv-values due to looped scrolling - if( Math.abs(v-vTarget) > 1.0 ) v = uv.old.getY(i) - v = v > vTarget ? v + (this.uv.vspeed * -vTarget ) // -xrf.clock.delta) - : v + (this.uv.vspeed * vTarget ) // xrf.clock.delta) - diffV += Math.abs( v - vTarget ) + if( this.uv.uloop || this.uv.vloop ){ + let u = uv.getX(i) + let v = uv.getY(i) + let uTarget = this.uv.ushift ? uv.getX(i) + this.uv.u : uv.old.getX(i) + this.uv.u + let vTarget = this.uv.vshift ? uv.getY(i) + this.uv.v : uv.old.getY(i) + this.uv.v + // scroll U + if( this.uv.uloop ){ + u += this.uv.uspeed * xrf.clock.delta + }else{ + // *TODO* tween to offset + //// recover from super-high uv-values due to looped scrolling + //if( Math.abs(u-uTarget) > 10.0 ) u = uv.old.getX(i) + //u = u > uTarget ? u + (this.uv.uspeed * -xrf.clock.delta) + // : u + (this.uv.uspeed * xrf.clock.delta) + //diffU += Math.abs( u - uTarget ) // are we done yet? (non-looping mode) + } + + // scroll V + if( this.uv.vloop ){ + v += this.uv.vspeed * xrf.clock.delta + }else{ + // *TODO* tween to offset + //// recover from super-high uv-values due to looped scrolling + //// recover from super-high uv-values due to looped scrolling + //if( Math.abs(v-vTarget) > 10.0 ) v = uv.old.getY(i) + //v = v > vTarget ? v + (this.uv.vspeed * -xrf.clock.delta) + // : v + (this.uv.vspeed * xrf.clock.delta) + //diffV += Math.abs( v - vTarget ) + } + uv.setXY(i,u,v) } - uv.setXY(i,u,v) + } uv.needsUpdate = true