diff --git a/public/js/ar/fuse.js b/public/js/ar/fuse.js index 0cc81ba..f6a21b5 100644 --- a/public/js/ar/fuse.js +++ b/public/js/ar/fuse.js @@ -23,11 +23,20 @@ export class WorldFuser { this.anchorMats = new Map(); // markerId -> Matrix4 this.smoothPos = null; this.smoothQuat = null; - this.posAlpha = 0.35; // smoothing factors (higher = snappier) - this.quatAlpha = 0.35; + // adaptive smoothing bounds: minAlpha when nearly still (heavy smoothing, + // kills jitter), maxAlpha when moving fast (light smoothing, stays responsive) + this.minAlpha = 0.08; + this.maxAlpha = 0.6; this.lastFuseT = 0; } + // Map a motion magnitude between [lo, hi] thresholds to an alpha in + // [minAlpha, maxAlpha]. Below lo => minAlpha (still); above hi => maxAlpha (moving). + adaptAlpha(delta, lo, hi) { + const tt = Math.min(1, Math.max(0, (delta - lo) / (hi - lo))); + return this.minAlpha + (this.maxAlpha - this.minAlpha) * tt; + } + setScene(scene) { this.anchorMats.clear(); for (const a of scene.anchors || []) { @@ -72,12 +81,20 @@ export class WorldFuser { } pos.multiplyScalar(1 / wSum); - // temporal smoothing + // temporal smoothing — adaptive: smooth hard when nearly still (kills jitter), + // loosen when genuinely moving (stays responsive). Reset only after a real + // tracking gap so brief single-frame dropouts don't cause a visible snap. const now = performance.now(); - if (this.smoothPos && now - this.lastFuseT < 500) { - this.smoothPos.lerp(pos, this.posAlpha); + if (this.smoothPos && now - this.lastFuseT < 1500) { + // positional delta in cm; rotational delta in radians + const dPos = this.smoothPos.distanceTo(pos); if (this.smoothQuat.dot(quat) < 0) quat.set(-quat.x, -quat.y, -quat.z, -quat.w); - this.smoothQuat.slerp(quat, this.quatAlpha); + const dAng = 2 * Math.acos(Math.min(1, Math.abs(this.smoothQuat.dot(quat)))); + // map motion -> alpha in [minAlpha, maxAlpha]. Small motion => small alpha. + const pAlpha = this.adaptAlpha(dPos, 0.5, 6); // still<0.5cm .. moving>6cm + const qAlpha = this.adaptAlpha(dAng, 0.01, 0.15); // still<0.6° .. moving>8.6° + this.smoothPos.lerp(pos, pAlpha); + this.smoothQuat.slerp(quat, qAlpha); } else { this.smoothPos = pos.clone(); this.smoothQuat = quat.clone();