Adaptive temporal smoothing + wider reset gate to reduce jitter without adding lag
This commit is contained in:
+23
-6
@@ -23,11 +23,20 @@ export class WorldFuser {
|
|||||||
this.anchorMats = new Map(); // markerId -> Matrix4
|
this.anchorMats = new Map(); // markerId -> Matrix4
|
||||||
this.smoothPos = null;
|
this.smoothPos = null;
|
||||||
this.smoothQuat = null;
|
this.smoothQuat = null;
|
||||||
this.posAlpha = 0.35; // smoothing factors (higher = snappier)
|
// adaptive smoothing bounds: minAlpha when nearly still (heavy smoothing,
|
||||||
this.quatAlpha = 0.35;
|
// kills jitter), maxAlpha when moving fast (light smoothing, stays responsive)
|
||||||
|
this.minAlpha = 0.08;
|
||||||
|
this.maxAlpha = 0.6;
|
||||||
this.lastFuseT = 0;
|
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) {
|
setScene(scene) {
|
||||||
this.anchorMats.clear();
|
this.anchorMats.clear();
|
||||||
for (const a of scene.anchors || []) {
|
for (const a of scene.anchors || []) {
|
||||||
@@ -72,12 +81,20 @@ export class WorldFuser {
|
|||||||
}
|
}
|
||||||
pos.multiplyScalar(1 / wSum);
|
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();
|
const now = performance.now();
|
||||||
if (this.smoothPos && now - this.lastFuseT < 500) {
|
if (this.smoothPos && now - this.lastFuseT < 1500) {
|
||||||
this.smoothPos.lerp(pos, this.posAlpha);
|
// 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);
|
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 {
|
} else {
|
||||||
this.smoothPos = pos.clone();
|
this.smoothPos = pos.clone();
|
||||||
this.smoothQuat = quat.clone();
|
this.smoothQuat = quat.clone();
|
||||||
|
|||||||
Reference in New Issue
Block a user