Spaces:
Running
Running
ego viewer: hand-pose 3D no longer blank when paused at t=0 (snap past leading all-zero pose frames)
Browse files- egoSample/mego.html +19 -5
egoSample/mego.html
CHANGED
|
@@ -166,8 +166,11 @@ function loadSig(slug){
|
|
| 166 |
const prev=document.getElementById('sigjs'); if(prev) prev.remove();
|
| 167 |
window.EPDATA=window.EPDATA||{};
|
| 168 |
const done=()=>{ SIG=window.EPDATA[slug]; if(!SIG) return; sizeCanvases(); drawCharts();
|
| 169 |
-
|
| 170 |
-
|
|
|
|
|
|
|
|
|
|
| 171 |
// start playback only once the master tile can actually play, so the per-frame
|
| 172 |
// slave sync chases a real timestamp instead of hammering seeks against t=0
|
| 173 |
const go=()=>{ if(_toggle && !playing) _toggle(); };
|
|
@@ -658,9 +661,20 @@ function smoothKp(pos,x,W,k){
|
|
| 658 |
acc[0]+=p[0]*wt; acc[1]+=p[1]*wt; acc[2]+=p[2]*wt; sw+=wt; }
|
| 659 |
return sw>0 ? [acc[0]/sw,acc[1]/sw,acc[2]/sw] : med;
|
| 660 |
}
|
| 661 |
-
function handAt(side,t){ const
|
| 662 |
-
|
| 663 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 664 |
let pts;
|
| 665 |
if(W>0){ pts=[]; for(let k=0;k<21;k++){ const p=smoothKp(H.pos,x,W,k); if(!p){ pts=null; break; } pts.push(p); } }
|
| 666 |
if(!pts){ const A=H.pos[j0],B=H.pos[j1]; pts=(handOk(A)&&handOk(B))?A.map((p,i)=>lerpV(p,B[i],a)):(handOk(A)?A:B); }
|
|
|
|
| 166 |
const prev=document.getElementById('sigjs'); if(prev) prev.remove();
|
| 167 |
window.EPDATA=window.EPDATA||{};
|
| 168 |
const done=()=>{ SIG=window.EPDATA[slug]; if(!SIG) return; sizeCanvases(); drawCharts();
|
| 169 |
+
// park on the first frame that actually has hand data (the raw pose arrays have
|
| 170 |
+
// ~2 leading all-zero frames) so the 3D panel isn't blank while the clip is paused
|
| 171 |
+
let fk=0; while(fk<SIG.n && !(handOk(SIG.handL.pos[fk])||handOk(SIG.handR.pos[fk]))) fk++;
|
| 172 |
+
const fv = fk<SIG.n ? (fk+0.5)/SIG.fps : 0;
|
| 173 |
+
if(master && fv>0 && master.currentTime<fv-0.01) setTime(fv); else if(master){ updateUI(master.currentTime||0); blitMain(); }
|
| 174 |
// start playback only once the master tile can actually play, so the per-frame
|
| 175 |
// slave sync chases a real timestamp instead of hammering seeks against t=0
|
| 176 |
const go=()=>{ if(_toggle && !playing) _toggle(); };
|
|
|
|
| 661 |
acc[0]+=p[0]*wt; acc[1]+=p[1]*wt; acc[2]+=p[2]*wt; sw+=wt; }
|
| 662 |
return sw>0 ? [acc[0]/sw,acc[1]/sw,acc[2]/sw] : med;
|
| 663 |
}
|
| 664 |
+
function handAt(side,t){ const H=SIG['hand'+side], N=SIG.n;
|
| 665 |
+
let x=Math.max(0,Math.min(N-1.0001, t*SIG.fps));
|
| 666 |
+
// MEgo hand pose carries a few all-zero frames at the very start/end of each
|
| 667 |
+
// episode. If the viewer is parked exactly there (e.g. paused at t=0 because the
|
| 668 |
+
// browser blocked video autoplay), snap to the nearest populated frame so the
|
| 669 |
+
// panel shows the first/last real pose instead of going blank.
|
| 670 |
+
const ok=j=>handOk(H.pos[j]);
|
| 671 |
+
if(!ok(Math.floor(x)) && !ok(Math.ceil(x))){
|
| 672 |
+
let hi=Math.ceil(x); while(hi<N && !ok(hi)) hi++;
|
| 673 |
+
let lo=Math.floor(x); while(lo>=0 && !ok(lo)) lo--;
|
| 674 |
+
if(hi>=N && lo<0) return null;
|
| 675 |
+
x = (hi<N && (lo<0 || hi-x<=x-lo)) ? hi : lo;
|
| 676 |
+
}
|
| 677 |
+
const j0=Math.floor(x), j1=Math.min(N-1,j0+1), a=x-j0, W=CAL.smoothW||0;
|
| 678 |
let pts;
|
| 679 |
if(W>0){ pts=[]; for(let k=0;k<21;k++){ const p=smoothKp(H.pos,x,W,k); if(!p){ pts=null; break; } pts.push(p); } }
|
| 680 |
if(!pts){ const A=H.pos[j0],B=H.pos[j1]; pts=(handOk(A)&&handOk(B))?A.map((p,i)=>lerpV(p,B[i],a)):(handOk(A)?A:B); }
|