Add controller support
Browse files- README.md +1 -1
- index.html +4 -3
- static/demo.min.js +586 -1
- style.css +0 -28
README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
---
|
2 |
-
title: Character Animation Motion
|
3 |
emoji: 💻
|
4 |
colorFrom: pink
|
5 |
colorTo: yellow
|
|
|
1 |
---
|
2 |
+
title: Character Animation Motion VAEs
|
3 |
emoji: 💻
|
4 |
colorFrom: pink
|
5 |
colorTo: yellow
|
index.html
CHANGED
@@ -16,7 +16,7 @@
|
|
16 |
--accent-color: rgb(6, 69, 173);
|
17 |
--fg-color: rgb(32, 33, 34);
|
18 |
--bg-color: #fff;
|
19 |
-
--max-content-width:
|
20 |
}
|
21 |
|
22 |
body {
|
@@ -82,8 +82,9 @@
|
|
82 |
<div id="mvaeScene" style="position: absolute; width: 100%; height: 100%"></div>
|
83 |
</div>
|
84 |
<ul>
|
85 |
-
<
|
86 |
-
<li
|
|
|
87 |
</ul>
|
88 |
<div>
|
89 |
<hr>
|
|
|
16 |
--accent-color: rgb(6, 69, 173);
|
17 |
--fg-color: rgb(32, 33, 34);
|
18 |
--bg-color: #fff;
|
19 |
+
--max-content-width: 65vw;
|
20 |
}
|
21 |
|
22 |
body {
|
|
|
82 |
<div id="mvaeScene" style="position: absolute; width: 100%; height: 100%"></div>
|
83 |
</div>
|
84 |
<ul>
|
85 |
+
<p>Try connecting a PlayStation or Xbox controller!</p>
|
86 |
+
<li><em>Left-drag</em> or <em>Right-stick</em> to rotate, and scroll to zoom</li>
|
87 |
+
<li>Place target or change direction: <em>Right-click</em> or <em>GamePad Left-stick</em></li>
|
88 |
</ul>
|
89 |
<div>
|
90 |
<hr>
|
static/demo.min.js
CHANGED
@@ -1 +1,586 @@
|
|
1 |
-
(()=>{const e=document.getElementById("demoButton");e.onclick=async function(t){e.onclick=null,e.innerText="Loading Modules ~10s",await Promise.all([import("./onnx.min.js"),import("./three/build/three.module.min.js"),import("./three/examples/jsm/controls/OrbitControls.min.js"),import("./three/examples/jsm/libs/dat.gui.module.min.js")]).then(e=>{window.THREE=e[1],window.OrbitControls=e[2].OrbitControls,window.GUI=e[3].GUI});const o=await Promise.all([fetch("./static/mvae.onnx").then(e=>e.arrayBuffer()),fetch("./static/target_controller.onnx").then(e=>e.arrayBuffer()),fetch("./static/joystick_controller.onnx").then(e=>e.arrayBuffer())]).then(e=>({mvae:e[0],target:e[1],joystick:e[2]})),n={};for(let[e,t]of Object.entries(o))n[e]=new onnx.InferenceSession({backendHint:"webgl"}),await n[e].loadModel(t);const i=document.getElementById("mvaeScene"),s=new THREE.WebGLRenderer({antialias:!0,alpha:!0});s.setPixelRatio(window.devicePixelRatio),s.setSize(i.clientWidth,i.clientHeight),s.outputEncoding=THREE.sRGBEncoding,s.shadowMap.enabled=!0,s.domElement.style.outline="none",i.appendChild(s.domElement);const a=new THREE.Scene;a.background=new THREE.Color(2632756),a.fog=new THREE.Fog(2632756,10,400);const r=new THREE.PerspectiveCamera(25,i.clientWidth/i.clientHeight,.1,1e3);r.position.set(30,4,30),r.lookAt(0,0,0);const c=new OrbitControls(r,s.domElement);c.enableDamping=!0,c.keys={LEFT:65,UP:87,RIGHT:68,BOTTOM:83},c.minDistance=20,c.maxDistance=200,c.update();const l=new THREE.TextureLoader,d=new THREE.Raycaster,p=new THREE.Vector2;let E=0,h=0,u=0,w=[0,0,0],m=new onnx.Tensor(new Float32Array(32),"float32",[1,32]),f=new onnx.Tensor(new Float32Array(267),"float32",[1,267]);const M=[.2337,.0663,.0614,.9697,.2778,.7038,.9697,.2778,.7038,.1865,.3471,.1654,.2632,.3683,.2215,.3824,.408,.3032,.3247,.3808,.2617,.3247,.3808,.2617,.3628,.3749,.2736,.3628,.3749,.2736,.4146,.3826,.2113,.4146,.3826,.2113,.0048,.3071,.0048,.7615,.3368,.6285,.7615,.3368,.6285,.0158,.3156,.016,.0158,.3156,.016,.4892,.2069,.3532,.4892,.2069,.3532,.0492,.3164,.0526,.12,.3314,.1132,.5161,.4031,.2726,.5161,.4031,.2726,.4056,.1132,.1208,.4056,.1132,.1208,.2268,.054,.0672,.2245,.0548,.0669,.2213,.0567,.0698,.223,.0554,.0677,.223,.0554,.0677,.2255,.0607,.0691,.2255,.0607,.0691,.2488,.1168,.0937,.2488,.1168,.0937,.2337,.0527,.0714,.3489,.1147,.1136,.3489,.1147,.1136,.2348,.0533,.0728,.2348,.0533,.0728,.291,.0778,.081,.291,.0778,.081,.2317,.0529,.0705,.229,.0534,.0686,.2855,.1421,.1301,.2855,.1421,.1301,.4053,.3292,.1624,.4053,.3292,.1624,.0919,.2076,.0945,.1048,.2116,.1123,.1294,.1692,.1227,.1161,.2072,.1589,.1161,.2072,.1589,.2761,.2619,.2591,.2761,.2619,.2591,.397,.3733,.2129,.397,.3733,.2129,.0409,.1883,.0369,.243,.4652,.1788,.243,.4652,.1788,.1376,.3043,.2111,.1376,.3043,.2111,.2872,.3043,.2376,.2872,.3043,.2376,.0686,.2018,.0612,.0799,.2049,.0769,.4131,.4178,.326,.413,.4178,.326,.1946,.2185,.0824,.1946,.2185,.0824,.083,.1624,.0254,.0995,.1588,.0252,.1439,.1504,.0314,.2075,.1172,.1885,.2075,.1172,.1885,.2097,.2119,.1359,.2097,.2119,.1359,.2097,.2119,.1359,.2097,.2119,.1359,.0372,.2014,.0372,.1857,.2257,.0808,.1857,.2257,.0808,.1552,.2805,.094,.1552,.2805,.094,.1552,.2805,.094,.1552,.2805,.094,.052,.1751,.0286,.0664,.1678,.0266,.2818,.2703,.1431,.2818,.2703,.1431],g=[.26107,-4.7486e-7,1.401e-7,-.0028028,.30103,-.36838,-.0027801,.30103,.36839,.14925,3.8383,-8.6033e-7,.24685,4.1773,-6.7364e-7,.41594,4.6868,-2.4816e-8,.28113,4.435,-.088858,.28113,4.435,.088857,.29221,4.4636,-.59573,.29222,4.4636,.59572,-.11323,3.8501,.90934,-.11324,3.8501,-.90934,-5509e-8,2.9514,7.9133e-12,-.31353,.66536,-.27751,-.31351,.66536,.27751,-.049933,2.9565,-.3931,-.049933,2.9565,.3931,.38439,1.6758,-.43913,.3844,1.6758,.43913,.0083124,3.2001,-5.0445e-7,.075637,3.536,-8.0779e-7,.36293,3.3118,-.7784,.36294,3.3118,.7784,.28288,1953e-7,-.013949,.28288,19532e-8,.013949,.25435,-11878e-8,-5.0363e-7,.25261,-10782e-8,-5.3367e-7,.25019,-84664e-9,-5.927e-7,.25142,-1101e-7,8511e-8,.25142,-11008e-8,-86227e-9,.25097,-53605e-9,.0012627,.25097,-53493e-9,-.0012638,.25386,29768e-9,-.0051661,.25386,29656e-9,.0051651,.25973,-12142e-8,-4.7796e-7,.2802,25689e-8,-.011458,.2802,25717e-8,.011458,.25962,-13255e-8,-58587e-8,.25962,-13255e-8,58493e-8,.27278,18581e-9,-.009093,.27278,18695e-9,.0090928,.25799,-12785e-8,-4.7312e-7,.25601,-12486e-8,-4.8496e-7,.25366,6089e-7,.0079774,.25366,60939e-8,-.0079785,-.20331,-.81218,75829e-8,-.20331,-.81218,-75517e-8,.93253,-.26446,-17862e-10,.91736,-.30011,-22849e-10,.83715,-.4886,-9844e-9,.90167,-.32442,-.0079873,.90167,-.32442,.0079802,.66979,-.5487,.1958,.66978,-.5487,-.19581,.51202,.53974,-.32292,.51202,.53974,.32291,.97553,-.099292,-4.7701e-8,-.61732,-.55017,.093872,-.61732,-.55018,-.093873,-.85457,-.27279,.19796,-.85457,-.27279,-.19796,-.7157,.48543,.14351,-.71571,.48542,-.14351,.95673,-.18836,-8.6077e-7,.94572,-.22657,-13113e-10,.46985,.51673,.24654,.46985,.51673,-.24655,-.16761,.039161,-.93701,.16762,-.039163,-.93701,-17539e-10,6.0989e-7,-.98291,-21627e-10,13742e-10,-.98196,-10023e-9,11619e-10,-.97758,-.32096,-.89459,-.066042,.32096,.89459,-.066042,-.37467,-.18443,.84751,.37468,.18443,.8475,.37468,.18443,.8475,-.37467,-.18443,.84751,4.7733e-8,-19534e-10,-.9781,-.16384,.043208,-.93774,.16385,-.04321,-.93774,-.19273,-.020136,-.9224,.19273,.020141,-.9224,-.19272,-.020145,-.9224,.19273,.02015,-.9224,-8.4422e-7,-8.6653e-7,-.98276,-13142e-10,-1.3712e-7,-.98322,-.25745,-.20945,.8467,.25746,.20945,.84669],T=[.37343,.025392,-.0036897,.91467,.20899,-1.0637,-1.6662,.73143,-.88882,.29283,3.852,.27816,.45728,4.1711,.35562,.73643,4.6469,.45095,.54106,4.4424,.32156,.55217,4.4007,.49731,.53249,4.5413,-.19381,.64737,4.3115,1.0057,.088589,3.682,1.3214,.22347,4.0642,-.8903,0,3.0089,0,.41466,.50355,-.9374,-1.4528,1.225,-.63671,-.031384,3.1669,-.37173,-.067839,2.8752,.37637,.66035,1.8958,-.76142,-.1062,1.5319,-.28707,.044212,3.2461,.09468,.1651,3.5656,.19719,.74468,3.3334,-.84051,.64904,3.2906,.73755,.17409,-.12108,.025089,.38499,.28025,.12745,.36488,-.015865,-.0033239,.36296,-.011497,-.016055,.36115,-.0059476,-.03615,.36703,-.014265,-.032338,.35635,-99516e-8,-.027624,.4116,-.069391,-.048794,.30963,.025622,-.011095,.23451,.092727,.0062983,.55357,-.22211,-.038469,.37352,-.028061,.024014,.20644,-.078941,.076509,.49427,.2346,.15348,.37234,-.038626,.019442,.37435,-.018714,.027618,.28971,-.076181,-.01701,.64407,-.034401,-.012438,.37001,-.024745,.017678,.36711,-.020063,.0071973,.74105,-.11856,.037614,.16907,-.22738,.063841,.0089425,-.99831,-.057434,-.98963,-.11627,-.084324,.89335,-.42454,-.14729,.8646,-.47384,-.16715,.75405,-.64569,-.12038,.85399,-.50816,-.1117,.84038,-.48479,-.24236,.65666,-.7256,.20567,.45273,-.68694,-.56846,.45016,.879,-.1572,.46176,.38382,.79967,.97032,-.23754,-.045353,-.49521,-.86664,.060737,-.93292,.33144,.14074,-.85423,-.50399,.12763,-.99094,.08114,-.10699,-.95551,.1355,.26199,-.29873,.87383,.38365,.94078,-.32382,-.10032,.91878,-.37446,-.12497,.46267,.51188,.72382,.60684,.72977,.31492,-.2146,.054182,-.9752,.023719,.44674,-.89435,-.038452,.25434,-.96635,-.061361,.2306,-.97111,.0088725,.19328,-.9811,-.52004,-.8404,-.15259,.51074,.85799,.054759,-.6713,-.43805,.59789,.63929,-.19434,.744,.63929,-.19434,.744,-.6713,-.43805,.59789,.045352,.36296,-.9307,-.2144,.054166,-.97524,.023728,.44659,-.89442,-.23929,.16321,-.95713,.13181,.43593,-.89027,-.23929,.16321,-.95713,.13181,.43593,-.89027,.0032209,.30445,-.95252,-.016893,.279,-.96014,-.35985,-.63774,.68102,.35872,-.60504,.71081],y=[[12,0],[16,12],[14,16],[15,17],[17,13],[13,1],[5,7],[7,10],[10,20],[6,8],[8,9],[9,21],[3,18],[14,15]],R=1/.3048,x=2*Math.PI;function H(){u=0,w=[0,0,0],c.target.x=0,c.target.z=0,B.position.x=15,B.position.z=15,h=0,E=0,function(){for(let e=0;e<f.data.length;e++)f.set((T[e]-g[e])/M[e],[0,e])}()}const k=new GUI({autoPlace:!1});let A={Task:"target",Reset:!1,Pause:!1};k.add(A,"Task",{Target:"target",Joystick:"joystick"}).setValue("target").onChange(()=>{H(),s.domElement.focus()});const z=k.add(A,"Reset");z.onChange(()=>{H(),setTimeout(()=>{A.Reset=!1,z.updateDisplay()},100)}),k.add(A,"Pause"),document.getElementById("guiContainer").appendChild(k.domElement);const j=new THREE.SpotLight(16777215);j.position.set(100,1e3,100),j.castShadow=!0,a.add(j);const v=l.load("./static/grid.png");v.wrapS=v.wrapT=THREE.RepeatWrapping,v.repeat.set(50,50),v.anisotropy=16,v.encoding=THREE.sRGBEncoding;const P=new THREE.Mesh(new THREE.PlaneBufferGeometry(400,400),new THREE.MeshLambertMaterial({map:v}));P.rotation.x=-Math.PI/2,P.receiveShadow=!0,a.add(P);const B=new THREE.Mesh(new THREE.SphereBufferGeometry(.15,16,16),new THREE.MeshBasicMaterial({color:16711680}));a.add(B);const I=new THREE.SphereBufferGeometry(.07,16,16),b=new THREE.MeshBasicMaterial({color:3422263}),C=[];for(let e=0;e<22;e++){const e=new THREE.Mesh(I,b);a.add(e),C.push(e)}C[11];const L=new THREE.CylinderBufferGeometry(.06,.06,1,16),G=new THREE.MeshBasicMaterial({color:4096764}),S=[];for(let e=0;e<y.length;e++){const e=new THREE.Mesh(L,G);a.add(e),S.push(e)}const D=new THREE.Mesh(new THREE.SphereBufferGeometry(.125,16,16),new THREE.MeshBasicMaterial({color:4096764}));a.add(D),H();document.documentElement;function V(e,t){const o=s.domElement,n=o.getBoundingClientRect();p.x=(e-n.x)/o.clientWidth*2-1,p.y=-(t-n.y)/o.clientHeight*2+1,d.setFromCamera(p,r);const i=d.intersectObjects([P]);for(const e of i)B.position.x=e.point.x,B.position.z=e.point.z;"joystick"==A.Task&&(h=Math.atan2(B.position.z-w[2],B.position.x-w[0]))}let q={};window.addEventListener("resize",function(){r.aspect=i.clientWidth/i.clientHeight,r.updateProjectionMatrix(),s.setSize(i.clientWidth,i.clientHeight)},!1),s.domElement.addEventListener("click",function(e){if(!e.ctrlKey&&!e.metaKey)return;e.preventDefault(),E=0,V(e.clientX,e.clientY)},!1),s.domElement.addEventListener("touchstart",function(e){e.preventDefault(),E=0,V(e.touches[0].clientX,e.touches[0].clientY)},!1),s.domElement.addEventListener("keydown",function(e){e.preventDefault(),q[e.code]=!0,"joystick"==A.Task&&(h=0,q.ArrowUp&&q.ArrowLeft?E=7*Math.PI/4:q.ArrowUp&&q.ArrowRight?E=Math.PI/4:q.ArrowDown&&q.ArrowLeft?E=5*Math.PI/4:q.ArrowDown&&q.ArrowRight?E=3*Math.PI/4:q.ArrowLeft?E=3*Math.PI/2:q.ArrowUp?E=0:q.ArrowRight?E=Math.PI/2:q.ArrowDown&&(E=Math.PI))},!1),s.domElement.addEventListener("keyup",function(e){e.preventDefault(),q[e.code]=!1},!1);let O=performance.now();const F=async()=>{requestAnimationFrame(F);let e=performance.now(),t=e-O;if(!A.Pause&&t>1e3/30){O=e-t%(1e3/30);const o=Math.cos(u),i=Math.sin(u),l=-i,d=o;let p=[0,0];if("target"==A.Task){let e=[B.position.x-w[0],B.position.z-w[2]],t=Math.sqrt(e.reduce((e,t)=>e+t*t,0));if(t*R<2)do{B.position.x=.3048*(80*Math.random()-40),B.position.z=.3048*(80*Math.random()-40),e=[B.position.x-w[0],B.position.z-w[2]],t=Math.sqrt(e.reduce((e,t)=>e+t*t,0))}while(t*R<20);p[0]=(o*e[0]+l*e[1])*R,p[1]=(i*e[0]+d*e[1])*R}else if("joystick"==A.Task){B.position.x=w[0]+2*Math.cos(h+E),B.position.z=w[2]+2*Math.sin(h+E);const e=Math.atan2(B.position.z-w[2],B.position.x-w[0])+u;p[0]=.65*Math.cos(e),p[1]=.65*Math.sin(e),c.target.x=w[0],c.target.z=w[2]}else console.log(`Oops, "${A.Task}" if not a supported task.`);let T=new onnx.Tensor(new Float32Array(269),"float32",[1,269]);for(let e=0;e<f.size;e++){const t=f.get([0,e])*M[e]+g[e];T.set(t,[0,e])}for(let e=0;e<p.length;e++){const t=p[e]+1e-5;T.set(t,[0,f.size+e])}await n[A.Task].run([T]).then(e=>{m=e.values().next().value}),await n.mvae.run([m,f]).then(e=>{f=e.values().next().value});const H=f.data.slice(0,69).map((e,t)=>.3048*(e*M[t]+g[t]));H[2]=H[2]/.3048;const k=H[0],z=H[1],j=o*k+i*z,v=l*k+d*z;w[0]+=j,w[2]+=v,u=(u+H[2])%x;for(let e=0;e<C.length;e++){const t=3*(e+1),n=t+1,s=t+2,a=H[t],r=H[s],c=o*a+i*r,p=l*a+d*r;C[e].position.x=c+w[0],C[e].position.y=H[n],C[e].position.z=p+w[2]}for(let e=0;e<S.length;e++){const[t,o]=y[e],[n,i,s]=[C[t].position.x,C[t].position.y,C[t].position.z],[a,r,c]=[C[o].position.x,C[o].position.y,C[o].position.z],l=[(a+n)/2,(r+i)/2,(c+s)/2],d=[a-n,r-i,c-s],p=Math.sqrt(d.reduce((e,t)=>e+t*t,0)),E=[d[2],0,-d[0],p+d[1]],h=Math.sqrt(E.reduce((e,t)=>e+t*t,0));S[e].scale.y=p,S[e].position.x=l[0],S[e].position.y=l[1],S[e].position.z=l[2],S[e].quaternion.x=E[0]/h,S[e].quaternion.y=E[1]/h,S[e].quaternion.z=E[2]/h,S[e].quaternion.w=E[3]/h}D.position.x=1.75*C[4].position.x-.75*C[3].position.x,D.position.y=1.75*C[4].position.y-.75*C[3].position.y,D.position.z=1.75*C[4].position.z-.75*C[3].position.z,c.update(),s.render(a,r)}};e.remove(),F()}})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(() => {
|
2 |
+
|
3 |
+
// Original gamepad logic: https://gist.github.com/videlais/8110000
|
4 |
+
// Modified from: https://codepen.io/XanderLuciano/pen/vddOOG?editors=0010
|
5 |
+
class GamePad {
|
6 |
+
constructor() {
|
7 |
+
this.supported = (navigator.webkitGetGamepads && navigator.webkitGetGamepads()) ||
|
8 |
+
!!navigator.webkitGamepads || !!navigator.mozGamepads ||
|
9 |
+
!!navigator.msGamepads || !!navigator.gamepads ||
|
10 |
+
(navigator.getGamepads && navigator.getGamepads());
|
11 |
+
|
12 |
+
this.ticking = false;
|
13 |
+
this.connected = false;
|
14 |
+
|
15 |
+
this.lStick = new THREE.Vector3(0,0,0);
|
16 |
+
this.rStick = new THREE.Vector3(0,0,0);
|
17 |
+
|
18 |
+
// Recommended deadzones for Xbox One controller
|
19 |
+
this.SPACEMOUSE_THRESHOLD = 3000 / 32767.0;
|
20 |
+
|
21 |
+
this.gamepads = [];
|
22 |
+
this.prevRawGamepadTypes = [];
|
23 |
+
this.prevTimestamps = [];
|
24 |
+
|
25 |
+
this.init();
|
26 |
+
}
|
27 |
+
|
28 |
+
init() {
|
29 |
+
if (this.supported) {
|
30 |
+
// Older Firefox
|
31 |
+
window.addEventListener('MozGamepadConnected', (e) => this.onGamepadConnect(e), false);
|
32 |
+
window.addEventListener('MozGamepadDisconnected', (e) => this.onGamepadDisconnect(e), false);
|
33 |
+
|
34 |
+
//W3C Specification
|
35 |
+
window.addEventListener('gamepadconnected', (e) => this.onGamepadConnect(e), false);
|
36 |
+
window.addEventListener('gamepaddisconnected', (e) => this.onGamepadDisconnect(e), false);
|
37 |
+
|
38 |
+
// Chrome
|
39 |
+
if (navigator.webkitGetGamepads && navigator.webkitGetGamepads()) {
|
40 |
+
this.startPolling();
|
41 |
+
}
|
42 |
+
|
43 |
+
//CocoonJS
|
44 |
+
if(navigator.getGamepads && navigator.getGamepads()) {
|
45 |
+
this.startPolling();
|
46 |
+
}
|
47 |
+
} else {
|
48 |
+
console.log('Gamepad API not supported or not detected!');
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
startPolling() {
|
53 |
+
if (!this.ticking) {
|
54 |
+
this.ticking = true;
|
55 |
+
this.update();
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
stopPolling() {
|
60 |
+
this.ticking = false;
|
61 |
+
}
|
62 |
+
|
63 |
+
// Called externally
|
64 |
+
update() {
|
65 |
+
this.pollStatus();
|
66 |
+
if (this.ticking) {
|
67 |
+
this.pollJoysticks();
|
68 |
+
}
|
69 |
+
}
|
70 |
+
|
71 |
+
pollStatus() {
|
72 |
+
this.pollGamepads();
|
73 |
+
for (let i in this.gamepads) {
|
74 |
+
let gamepad = this.gamepads[i];
|
75 |
+
if (gamepad.timestamp && (gamepad.timestamp === this.prevTimestamps[i])) {
|
76 |
+
continue;
|
77 |
+
}
|
78 |
+
this.prevTimestamps[i] = gamepad.timestamp;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
pollGamepads() {
|
83 |
+
let rawGamepads = (navigator.webkitGetGamepads && navigator.webkitGetGamepads()) ||
|
84 |
+
navigator.webkitGamepads || navigator.mozGamepads ||
|
85 |
+
navigator.msGamepads || navigator.gamepads ||
|
86 |
+
(navigator.getGamepads && navigator.getGamepads());
|
87 |
+
if (rawGamepads) {
|
88 |
+
this.gamepads = [];
|
89 |
+
for (let i = 0, max = rawGamepads.length; i < max; i++) {
|
90 |
+
if (typeof rawGamepads[i] !== this.prevRawGamepadTypes[i]) {
|
91 |
+
this.prevRawGamepadTypes[i] = typeof rawGamepads[i];
|
92 |
+
}
|
93 |
+
if (rawGamepads[i]) {
|
94 |
+
this.gamepads.push(rawGamepads[i]);
|
95 |
+
}
|
96 |
+
}
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
pollJoysticks() {
|
101 |
+
let pad = 0;
|
102 |
+
|
103 |
+
// Reset all input to 0
|
104 |
+
// this.lStick.set(0, 0, 0);
|
105 |
+
this.rStick.set(0, 0, 0);
|
106 |
+
|
107 |
+
if (this.gamepads[pad]) {
|
108 |
+
|
109 |
+
let panX = this.gamepads[pad].axes[0];
|
110 |
+
let panY = this.gamepads[pad].axes[1];
|
111 |
+
let rollX = this.gamepads[pad].axes[2];
|
112 |
+
let rollY = this.gamepads[pad].axes[3];
|
113 |
+
|
114 |
+
if (panX < -this.SPACEMOUSE_THRESHOLD ||
|
115 |
+
panX > this.SPACEMOUSE_THRESHOLD) {
|
116 |
+
this.lStick.x = panX;
|
117 |
+
}
|
118 |
+
|
119 |
+
if (panY < -this.SPACEMOUSE_THRESHOLD ||
|
120 |
+
panY > this.SPACEMOUSE_THRESHOLD) {
|
121 |
+
this.lStick.y = -panY;
|
122 |
+
}
|
123 |
+
|
124 |
+
if (rollX < -this.SPACEMOUSE_THRESHOLD ||
|
125 |
+
rollX > this.SPACEMOUSE_THRESHOLD) {
|
126 |
+
this.rStick.x = rollX;
|
127 |
+
}
|
128 |
+
|
129 |
+
if (rollY < -this.SPACEMOUSE_THRESHOLD ||
|
130 |
+
rollY > this.SPACEMOUSE_THRESHOLD) {
|
131 |
+
this.rStick.y = -rollY;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
}
|
135 |
+
|
136 |
+
onGamepadConnect(event) {
|
137 |
+
console.log('Gamepad Connected!');
|
138 |
+
this.connected = true;
|
139 |
+
let gamepad = event.gamepad;
|
140 |
+
this.gamepads[event.gamepad.id] = gamepad;
|
141 |
+
this.startPolling();
|
142 |
+
}
|
143 |
+
|
144 |
+
onGamepadDisconnect(event) {
|
145 |
+
console.log('Gamepad Disconnected!');
|
146 |
+
this.connected = false;
|
147 |
+
this.gamepads[event.gamepad.id] = null;
|
148 |
+
if (this.gamepads.length === 0) {
|
149 |
+
this.stopPolling();
|
150 |
+
}
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
const button = document.getElementById("demoButton");
|
155 |
+
button.onclick = async function (event) {
|
156 |
+
// Prevent loading multiple instances
|
157 |
+
button.onclick = null;
|
158 |
+
|
159 |
+
button.innerText = "Loading Modules ~10s"
|
160 |
+
await Promise.all([
|
161 |
+
import("./onnx.min.js"),
|
162 |
+
import("./three/build/three.module.min.js"),
|
163 |
+
import("./three/examples/jsm/controls/OrbitControls.min.js"),
|
164 |
+
import("./three/examples/jsm/libs/dat.gui.module.min.js"),
|
165 |
+
]).then((results) => {
|
166 |
+
window.THREE = results[1];
|
167 |
+
window.OrbitControls = results[2].OrbitControls;
|
168 |
+
window.GUI = results[3].GUI;
|
169 |
+
});
|
170 |
+
|
171 |
+
const modelFiles = await Promise.all([
|
172 |
+
fetch("./static/mvae.onnx").then((f) => f.arrayBuffer()),
|
173 |
+
fetch("./static/target_controller.onnx").then((f) => f.arrayBuffer()),
|
174 |
+
fetch("./static/joystick_controller.onnx").then((f) => f.arrayBuffer()),
|
175 |
+
]).then((files) => {
|
176 |
+
return {
|
177 |
+
mvae: files[0],
|
178 |
+
target: files[1],
|
179 |
+
joystick: files[2]
|
180 |
+
}
|
181 |
+
})
|
182 |
+
|
183 |
+
// Create Onnx model
|
184 |
+
const onnxSessions = {};
|
185 |
+
for (let [key, file] of Object.entries(modelFiles)) {
|
186 |
+
onnxSessions[key] = new onnx.InferenceSession({
|
187 |
+
backendHint: "webgl",
|
188 |
+
});
|
189 |
+
await onnxSessions[key].loadModel(file);
|
190 |
+
}
|
191 |
+
|
192 |
+
// Connect Controller
|
193 |
+
const gamepad = new GamePad();
|
194 |
+
window.gamepad = gamepad;
|
195 |
+
|
196 |
+
// Make ThreeJS scene
|
197 |
+
const container = document.getElementById("mvaeScene")
|
198 |
+
const renderer = new THREE.WebGLRenderer({
|
199 |
+
antialias: true,
|
200 |
+
alpha: true,
|
201 |
+
});
|
202 |
+
renderer.setPixelRatio(window.devicePixelRatio);
|
203 |
+
renderer.setSize(container.clientWidth, container.clientHeight);
|
204 |
+
renderer.outputEncoding = THREE.sRGBEncoding;
|
205 |
+
renderer.shadowMap.enabled = true;
|
206 |
+
renderer.domElement.style.outline = "none";
|
207 |
+
container.appendChild(renderer.domElement);
|
208 |
+
|
209 |
+
const scene = new THREE.Scene();
|
210 |
+
scene.background = new THREE.Color(0x282c34);
|
211 |
+
scene.fog = new THREE.Fog(0x282c34, 10, 400);
|
212 |
+
|
213 |
+
let aspectRatio = container.clientWidth / container.clientHeight;
|
214 |
+
const camera = new THREE.PerspectiveCamera(25, aspectRatio, 0.1, 1000);
|
215 |
+
camera.lookAt(0, 0, 0);
|
216 |
+
camera.position.set(-30, 10, 0);
|
217 |
+
const controls = new OrbitControls(camera, renderer.domElement);
|
218 |
+
controls.enableDamping = true;
|
219 |
+
controls.minDistance = 20;
|
220 |
+
controls.maxDistance = 200;
|
221 |
+
controls.update();
|
222 |
+
|
223 |
+
// Utilities
|
224 |
+
const loader = new THREE.TextureLoader();
|
225 |
+
const raycaster = new THREE.Raycaster();
|
226 |
+
const mouse = new THREE.Vector2();
|
227 |
+
|
228 |
+
// Character states
|
229 |
+
let speed = 1;
|
230 |
+
let heading = 0;
|
231 |
+
let rootFacing = 0;
|
232 |
+
let rootXYZ = [0, 0, 0];
|
233 |
+
let action = new onnx.Tensor(new Float32Array(32), "float32", [1, 32]);
|
234 |
+
let condition = new onnx.Tensor(new Float32Array(267), "float32", [1, 267]);
|
235 |
+
|
236 |
+
const poseStd = [0.2337,0.0663,0.0614,0.9697,0.2778,0.7038,0.9697,0.2778,0.7038,0.1865,0.3471,0.1654,0.2632,0.3683,0.2215,0.3824,0.408,0.3032,0.3247,0.3808,0.2617,0.3247,0.3808,0.2617,0.3628,0.3749,0.2736,0.3628,0.3749,0.2736,0.4146,0.3826,0.2113,0.4146,0.3826,0.2113,0.0048,0.3071,0.0048,0.7615,0.3368,0.6285,0.7615,0.3368,0.6285,0.0158,0.3156,0.016,0.0158,0.3156,0.016,0.4892,0.2069,0.3532,0.4892,0.2069,0.3532,0.0492,0.3164,0.0526,0.12,0.3314,0.1132,0.5161,0.4031,0.2726,0.5161,0.4031,0.2726,0.4056,0.1132,0.1208,0.4056,0.1132,0.1208,0.2268,0.054,0.0672,0.2245,0.0548,0.0669,0.2213,0.0567,0.0698,0.223,0.0554,0.0677,0.223,0.0554,0.0677,0.2255,0.0607,0.0691,0.2255,0.0607,0.0691,0.2488,0.1168,0.0937,0.2488,0.1168,0.0937,0.2337,0.0527,0.0714,0.3489,0.1147,0.1136,0.3489,0.1147,0.1136,0.2348,0.0533,0.0728,0.2348,0.0533,0.0728,0.291,0.0778,0.081,0.291,0.0778,0.081,0.2317,0.0529,0.0705,0.229,0.0534,0.0686,0.2855,0.1421,0.1301,0.2855,0.1421,0.1301,0.4053,0.3292,0.1624,0.4053,0.3292,0.1624,0.0919,0.2076,0.0945,0.1048,0.2116,0.1123,0.1294,0.1692,0.1227,0.1161,0.2072,0.1589,0.1161,0.2072,0.1589,0.2761,0.2619,0.2591,0.2761,0.2619,0.2591,0.397,0.3733,0.2129,0.397,0.3733,0.2129,0.0409,0.1883,0.0369,0.243,0.4652,0.1788,0.243,0.4652,0.1788,0.1376,0.3043,0.2111,0.1376,0.3043,0.2111,0.2872,0.3043,0.2376,0.2872,0.3043,0.2376,0.0686,0.2018,0.0612,0.0799,0.2049,0.0769,0.4131,0.4178,0.326,0.413,0.4178,0.326,0.1946,0.2185,0.0824,0.1946,0.2185,0.0824,0.083,0.1624,0.0254,0.0995,0.1588,0.0252,0.1439,0.1504,0.0314,0.2075,0.1172,0.1885,0.2075,0.1172,0.1885,0.2097,0.2119,0.1359,0.2097,0.2119,0.1359,0.2097,0.2119,0.1359,0.2097,0.2119,0.1359,0.0372,0.2014,0.0372,0.1857,0.2257,0.0808,0.1857,0.2257,0.0808,0.1552,0.2805,0.094,0.1552,0.2805,0.094,0.1552,0.2805,0.094,0.1552,0.2805,0.094,0.052,0.1751,0.0286,0.0664,0.1678,0.0266,0.2818,0.2703,0.1431,0.2818,0.2703,0.1431];
|
237 |
+
const poseAvg = [2.6107e-1,-4.7486e-7,1.401e-7,-2.8028e-3,3.0103e-1,-3.6838e-1,-2.7801e-3,3.0103e-1,3.6839e-1,1.4925e-1,3.8383,-8.6033e-7,2.4685e-1,4.1773,-6.7364e-7,4.1594e-1,4.6868,-2.4816e-8,2.8113e-1,4.435,-8.8858e-2,2.8113e-1,4.435,8.8857e-2,2.9221e-1,4.4636,-5.9573e-1,2.9222e-1,4.4636,5.9572e-1,-1.1323e-1,3.8501,9.0934e-1,-1.1324e-1,3.8501,-9.0934e-1,-5.509e-5,2.9514,7.9133e-12,-3.1353e-1,6.6536e-1,-2.7751e-1,-3.1351e-1,6.6536e-1,2.7751e-1,-4.9933e-2,2.9565,-3.931e-1,-4.9933e-2,2.9565,3.931e-1,3.8439e-1,1.6758,-4.3913e-1,3.844e-1,1.6758,4.3913e-1,8.3124e-3,3.2001,-5.0445e-7,7.5637e-2,3.536,-8.0779e-7,3.6293e-1,3.3118,-7.784e-1,3.6294e-1,3.3118,7.784e-1,2.8288e-1,1.953e-4,-1.3949e-2,2.8288e-1,1.9532e-4,1.3949e-2,2.5435e-1,-1.1878e-4,-5.0363e-7,2.5261e-1,-1.0782e-4,-5.3367e-7,2.5019e-1,-8.4664e-5,-5.927e-7,2.5142e-1,-1.101e-4,8.511e-5,2.5142e-1,-1.1008e-4,-8.6227e-5,2.5097e-1,-5.3605e-5,1.2627e-3,2.5097e-1,-5.3493e-5,-1.2638e-3,2.5386e-1,2.9768e-5,-5.1661e-3,2.5386e-1,2.9656e-5,5.1651e-3,2.5973e-1,-1.2142e-4,-4.7796e-7,2.802e-1,2.5689e-4,-1.1458e-2,2.802e-1,2.5717e-4,1.1458e-2,2.5962e-1,-1.3255e-4,-5.8587e-4,2.5962e-1,-1.3255e-4,5.8493e-4,2.7278e-1,1.8581e-5,-9.093e-3,2.7278e-1,1.8695e-5,9.0928e-3,2.5799e-1,-1.2785e-4,-4.7312e-7,2.5601e-1,-1.2486e-4,-4.8496e-7,2.5366e-1,6.089e-4,7.9774e-3,2.5366e-1,6.0939e-4,-7.9785e-3,-2.0331e-1,-8.1218e-1,7.5829e-4,-2.0331e-1,-8.1218e-1,-7.5517e-4,9.3253e-1,-2.6446e-1,-1.7862e-6,9.1736e-1,-3.0011e-1,-2.2849e-6,8.3715e-1,-4.886e-1,-9.844e-6,9.0167e-1,-3.2442e-1,-7.9873e-3,9.0167e-1,-3.2442e-1,7.9802e-3,6.6979e-1,-5.487e-1,1.958e-1,6.6978e-1,-5.487e-1,-1.9581e-1,5.1202e-1,5.3974e-1,-3.2292e-1,5.1202e-1,5.3974e-1,3.2291e-1,9.7553e-1,-9.9292e-2,-4.7701e-8,-6.1732e-1,-5.5017e-1,9.3872e-2,-6.1732e-1,-5.5018e-1,-9.3873e-2,-8.5457e-1,-2.7279e-1,1.9796e-1,-8.5457e-1,-2.7279e-1,-1.9796e-1,-7.157e-1,4.8543e-1,1.4351e-1,-7.1571e-1,4.8542e-1,-1.4351e-1,9.5673e-1,-1.8836e-1,-8.6077e-7,9.4572e-1,-2.2657e-1,-1.3113e-6,4.6985e-1,5.1673e-1,2.4654e-1,4.6985e-1,5.1673e-1,-2.4655e-1,-1.6761e-1,3.9161e-2,-9.3701e-1,1.6762e-1,-3.9163e-2,-9.3701e-1,-1.7539e-6,6.0989e-7,-9.8291e-1,-2.1627e-6,1.3742e-6,-9.8196e-1,-1.0023e-5,1.1619e-6,-9.7758e-1,-3.2096e-1,-8.9459e-1,-6.6042e-2,3.2096e-1,8.9459e-1,-6.6042e-2,-3.7467e-1,-1.8443e-1,8.4751e-1,3.7468e-1,1.8443e-1,8.475e-1,3.7468e-1,1.8443e-1,8.475e-1,-3.7467e-1,-1.8443e-1,8.4751e-1,4.7733e-8,-1.9534e-6,-9.781e-1,-1.6384e-1,4.3208e-2,-9.3774e-1,1.6385e-1,-4.321e-2,-9.3774e-1,-1.9273e-1,-2.0136e-2,-9.224e-1,1.9273e-1,2.0141e-2,-9.224e-1,-1.9272e-1,-2.0145e-2,-9.224e-1,1.9273e-1,2.015e-2,-9.224e-1,-8.4422e-7,-8.6653e-7,-9.8276e-1,-1.3142e-6,-1.3712e-7,-9.8322e-1,-2.5745e-1,-2.0945e-1,8.467e-1,2.5746e-1,2.0945e-1,8.4669e-1];
|
238 |
+
const startPose = [3.7343e-1,2.5392e-2,-3.6897e-3,9.1467e-1,2.0899e-1,-1.0637,-1.6662,7.3143e-1,-8.8882e-1,2.9283e-1,3.852,2.7816e-1,4.5728e-1,4.1711,3.5562e-1,7.3643e-1,4.6469,4.5095e-1,5.4106e-1,4.4424,3.2156e-1,5.5217e-1,4.4007,4.9731e-1,5.3249e-1,4.5413,-1.9381e-1,6.4737e-1,4.3115,1.0057,8.8589e-2,3.682,1.3214,2.2347e-1,4.0642,-8.903e-1,0.0,3.0089,0.0,4.1466e-1,5.0355e-1,-9.374e-1,-1.4528,1.225,-6.3671e-1,-3.1384e-2,3.1669,-3.7173e-1,-6.7839e-2,2.8752,3.7637e-1,6.6035e-1,1.8958,-7.6142e-1,-1.062e-1,1.5319,-2.8707e-1,4.4212e-2,3.2461,9.468e-2,1.651e-1,3.5656,1.9719e-1,7.4468e-1,3.3334,-8.4051e-1,6.4904e-1,3.2906,7.3755e-1,1.7409e-1,-1.2108e-1,2.5089e-2,3.8499e-1,2.8025e-1,1.2745e-1,3.6488e-1,-1.5865e-2,-3.3239e-3,3.6296e-1,-1.1497e-2,-1.6055e-2,3.6115e-1,-5.9476e-3,-3.615e-2,3.6703e-1,-1.4265e-2,-3.2338e-2,3.5635e-1,-9.9516e-4,-2.7624e-2,4.116e-1,-6.9391e-2,-4.8794e-2,3.0963e-1,2.5622e-2,-1.1095e-2,2.3451e-1,9.2727e-2,6.2983e-3,5.5357e-1,-2.2211e-1,-3.8469e-2,3.7352e-1,-2.8061e-2,2.4014e-2,2.0644e-1,-7.8941e-2,7.6509e-2,4.9427e-1,2.346e-1,1.5348e-1,3.7234e-1,-3.8626e-2,1.9442e-2,3.7435e-1,-1.8714e-2,2.7618e-2,2.8971e-1,-7.6181e-2,-1.701e-2,6.4407e-1,-3.4401e-2,-1.2438e-2,3.7001e-1,-2.4745e-2,1.7678e-2,3.6711e-1,-2.0063e-2,7.1973e-3,7.4105e-1,-1.1856e-1,3.7614e-2,1.6907e-1,-2.2738e-1,6.3841e-2,8.9425e-3,-9.9831e-1,-5.7434e-2,-9.8963e-1,-1.1627e-1,-8.4324e-2,8.9335e-1,-4.2454e-1,-1.4729e-1,8.646e-1,-4.7384e-1,-1.6715e-1,7.5405e-1,-6.4569e-1,-1.2038e-1,8.5399e-1,-5.0816e-1,-1.117e-1,8.4038e-1,-4.8479e-1,-2.4236e-1,6.5666e-1,-7.256e-1,2.0567e-1,4.5273e-1,-6.8694e-1,-5.6846e-1,4.5016e-1,8.79e-1,-1.572e-1,4.6176e-1,3.8382e-1,7.9967e-1,9.7032e-1,-2.3754e-1,-4.5353e-2,-4.9521e-1,-8.6664e-1,6.0737e-2,-9.3292e-1,3.3144e-1,1.4074e-1,-8.5423e-1,-5.0399e-1,1.2763e-1,-9.9094e-1,8.114e-2,-1.0699e-1,-9.5551e-1,1.355e-1,2.6199e-1,-2.9873e-1,8.7383e-1,3.8365e-1,9.4078e-1,-3.2382e-1,-1.0032e-1,9.1878e-1,-3.7446e-1,-1.2497e-1,4.6267e-1,5.1188e-1,7.2382e-1,6.0684e-1,7.2977e-1,3.1492e-1,-2.146e-1,5.4182e-2,-9.752e-1,2.3719e-2,4.4674e-1,-8.9435e-1,-3.8452e-2,2.5434e-1,-9.6635e-1,-6.1361e-2,2.306e-1,-9.7111e-1,8.8725e-3,1.9328e-1,-9.811e-1,-5.2004e-1,-8.404e-1,-1.5259e-1,5.1074e-1,8.5799e-1,5.4759e-2,-6.713e-1,-4.3805e-1,5.9789e-1,6.3929e-1,-1.9434e-1,7.44e-1,6.3929e-1,-1.9434e-1,7.44e-1,-6.713e-1,-4.3805e-1,5.9789e-1,4.5352e-2,3.6296e-1,-9.307e-1,-2.144e-1,5.4166e-2,-9.7524e-1,2.3728e-2,4.4659e-1,-8.9442e-1,-2.3929e-1,1.6321e-1,-9.5713e-1,1.3181e-1,4.3593e-1,-8.9027e-1,-2.3929e-1,1.6321e-1,-9.5713e-1,1.3181e-1,4.3593e-1,-8.9027e-1,3.2209e-3,3.0445e-1,-9.5252e-1,-1.6893e-2,2.79e-1,-9.6014e-1,-3.5985e-1,-6.3774e-1,6.8102e-1,3.5872e-1,-6.0504e-1,7.1081e-1];
|
239 |
+
const linkedJoints = [
|
240 |
+
[12, 0], // right foot
|
241 |
+
[16, 12], // right shin
|
242 |
+
[14, 16], // right leg
|
243 |
+
[15, 17], // left foot
|
244 |
+
[17, 13], // left shin
|
245 |
+
[13, 1], // left leg
|
246 |
+
[5, 7], // right shoulder
|
247 |
+
[7, 10], // right upper arm
|
248 |
+
[10, 20], // right lower arm
|
249 |
+
[6, 8], // left shoulder
|
250 |
+
[8, 9], // left upper arm
|
251 |
+
[9, 21], // left lower arm
|
252 |
+
[3, 18], // torso
|
253 |
+
[14, 15], // hip
|
254 |
+
];
|
255 |
+
const F2M = 0.3048;
|
256 |
+
const M2F = 1 / 0.3048;
|
257 |
+
const TAU = 2 * Math.PI;
|
258 |
+
const GREY = 0x607d8b;
|
259 |
+
|
260 |
+
function resetPose() {
|
261 |
+
for (let i = 0; i < condition.data.length; i++) {
|
262 |
+
condition.set((startPose[i] - poseAvg[i]) / poseStd[i], [0, i]);
|
263 |
+
}
|
264 |
+
}
|
265 |
+
|
266 |
+
function resetState() {
|
267 |
+
rootFacing = 0;
|
268 |
+
rootXYZ = [0, 0, 0];
|
269 |
+
controls.target.x = 0;
|
270 |
+
controls.target.z = 0;
|
271 |
+
target.position.x = 15;
|
272 |
+
target.position.z = 15;
|
273 |
+
speed = 1;
|
274 |
+
heading = 0;
|
275 |
+
resetPose();
|
276 |
+
|
277 |
+
if (guiParams.Task == "target") {
|
278 |
+
camera.position.set(30, 10, 30);
|
279 |
+
} else {
|
280 |
+
camera.position.set(-30, 10, 0);
|
281 |
+
}
|
282 |
+
}
|
283 |
+
|
284 |
+
// Make GUI before scene
|
285 |
+
const gui = new GUI({ autoPlace: false });
|
286 |
+
let guiParams = {
|
287 |
+
Task: "target",
|
288 |
+
Reset: false,
|
289 |
+
Pause: false,
|
290 |
+
};
|
291 |
+
gui
|
292 |
+
.add(guiParams, "Task", {
|
293 |
+
Target: "target",
|
294 |
+
Joystick: "joystick",
|
295 |
+
})
|
296 |
+
.setValue("joystick")
|
297 |
+
.onChange(() => {
|
298 |
+
resetState();
|
299 |
+
renderer.domElement.focus();
|
300 |
+
});
|
301 |
+
|
302 |
+
const resetCon = gui.add(guiParams, "Reset");
|
303 |
+
resetCon.onChange(() => {
|
304 |
+
resetState();
|
305 |
+
setTimeout(() => {
|
306 |
+
guiParams.Reset = false;
|
307 |
+
resetCon.updateDisplay();
|
308 |
+
}, 100);
|
309 |
+
});
|
310 |
+
gui.add(guiParams, "Pause");
|
311 |
+
document.getElementById("guiContainer").appendChild(gui.domElement);
|
312 |
+
|
313 |
+
// SpotLight
|
314 |
+
const spotLight = new THREE.SpotLight(0xffffff);
|
315 |
+
spotLight.position.set(100, 1000, 100);
|
316 |
+
spotLight.castShadow = true;
|
317 |
+
scene.add(spotLight);
|
318 |
+
|
319 |
+
// Ground
|
320 |
+
const groundTexture = loader.load("./static/grid.png");
|
321 |
+
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
|
322 |
+
groundTexture.repeat.set(50, 50);
|
323 |
+
groundTexture.anisotropy = 16;
|
324 |
+
groundTexture.encoding = THREE.sRGBEncoding;
|
325 |
+
const ground = new THREE.Mesh(
|
326 |
+
new THREE.PlaneBufferGeometry(400, 400),
|
327 |
+
new THREE.MeshLambertMaterial({ map: groundTexture })
|
328 |
+
);
|
329 |
+
ground.rotation.x = -Math.PI / 2;
|
330 |
+
ground.receiveShadow = true;
|
331 |
+
scene.add(ground);
|
332 |
+
|
333 |
+
// Target
|
334 |
+
const target = new THREE.Mesh(
|
335 |
+
new THREE.SphereBufferGeometry(0.15, 16, 16),
|
336 |
+
new THREE.MeshBasicMaterial({ color: 0xff0000 })
|
337 |
+
);
|
338 |
+
scene.add(target);
|
339 |
+
|
340 |
+
// Character
|
341 |
+
const jointGeom = new THREE.SphereBufferGeometry(0.07, 16, 16);
|
342 |
+
const jointMat = new THREE.MeshBasicMaterial({ color: 0x343837 });
|
343 |
+
const joints = [];
|
344 |
+
for (let i = 0; i < 22; i++) {
|
345 |
+
const sphere = new THREE.Mesh(jointGeom, jointMat);
|
346 |
+
scene.add(sphere);
|
347 |
+
joints.push(sphere);
|
348 |
+
}
|
349 |
+
|
350 |
+
const linkGeom = new THREE.CylinderBufferGeometry(0.06, 0.06, 1, 16);
|
351 |
+
const linkMat = new THREE.MeshBasicMaterial({ color: 0x3e82fc });
|
352 |
+
const links = [];
|
353 |
+
for (let i = 0; i < linkedJoints.length; i++) {
|
354 |
+
const cylinder = new THREE.Mesh(linkGeom, linkMat);
|
355 |
+
scene.add(cylinder);
|
356 |
+
links.push(cylinder);
|
357 |
+
}
|
358 |
+
|
359 |
+
const head = new THREE.Mesh(
|
360 |
+
new THREE.SphereBufferGeometry(0.125, 16, 16),
|
361 |
+
new THREE.MeshBasicMaterial({ color: 0x3e82fc })
|
362 |
+
);
|
363 |
+
scene.add(head);
|
364 |
+
|
365 |
+
resetState();
|
366 |
+
|
367 |
+
// Event Handlers
|
368 |
+
function setTarget(eventX, eventY) {
|
369 |
+
const canvas = renderer.domElement;
|
370 |
+
const bbox = canvas.getBoundingClientRect();
|
371 |
+
mouse.x = ((eventX - bbox.x) / canvas.clientWidth) * 2 - 1;
|
372 |
+
mouse.y = -((eventY - bbox.y) / canvas.clientHeight) * 2 + 1;
|
373 |
+
|
374 |
+
raycaster.setFromCamera(mouse, camera);
|
375 |
+
const intersects = raycaster.intersectObjects([ground]);
|
376 |
+
for (const intersect of intersects) {
|
377 |
+
target.position.x = intersect.point.x;
|
378 |
+
target.position.z = intersect.point.z;
|
379 |
+
}
|
380 |
+
if (guiParams.Task == "joystick") {
|
381 |
+
heading = Math.atan2(
|
382 |
+
target.position.z - rootXYZ[2],
|
383 |
+
target.position.x - rootXYZ[0]
|
384 |
+
);
|
385 |
+
}
|
386 |
+
}
|
387 |
+
|
388 |
+
function onWindowResize() {
|
389 |
+
camera.aspect = container.clientWidth / container.clientHeight;
|
390 |
+
camera.updateProjectionMatrix();
|
391 |
+
renderer.setSize(container.clientWidth, container.clientHeight);
|
392 |
+
}
|
393 |
+
function onMouseClick(event) {
|
394 |
+
event.preventDefault();
|
395 |
+
const x = event.clientX;
|
396 |
+
const y = event.clientY;
|
397 |
+
setTarget(x, y);
|
398 |
+
}
|
399 |
+
function onTouchStart(event) {
|
400 |
+
event.preventDefault();
|
401 |
+
const x = event.touches[0].clientX;
|
402 |
+
const y = event.touches[0].clientY;
|
403 |
+
setTarget(x, y);
|
404 |
+
}
|
405 |
+
|
406 |
+
// Start animation loop
|
407 |
+
window.addEventListener("resize", onWindowResize, false);
|
408 |
+
renderer.domElement.addEventListener("auxclick", onMouseClick, false);
|
409 |
+
renderer.domElement.addEventListener("touchstart", onTouchStart, false);
|
410 |
+
|
411 |
+
// 30 fps in milliseconds
|
412 |
+
const fpsInterval = 1000 / 30;
|
413 |
+
let startTime = performance.now();
|
414 |
+
|
415 |
+
const animate = async () => {
|
416 |
+
requestAnimationFrame(animate);
|
417 |
+
|
418 |
+
let endTime = performance.now();
|
419 |
+
let elapsedTime = endTime - startTime;
|
420 |
+
|
421 |
+
// if (gamepad.connected) {
|
422 |
+
// gamepad.update();
|
423 |
+
// }
|
424 |
+
|
425 |
+
if (!guiParams.Pause && elapsedTime > fpsInterval) {
|
426 |
+
startTime = endTime - (elapsedTime % fpsInterval);
|
427 |
+
|
428 |
+
// Get rotation matrix [a b; c d]
|
429 |
+
const a = Math.cos(rootFacing);
|
430 |
+
const b = Math.sin(rootFacing);
|
431 |
+
const c = -b;
|
432 |
+
const d = a;
|
433 |
+
|
434 |
+
// First calculate observation components
|
435 |
+
let taskVector = [0.0, 0.0];
|
436 |
+
if (guiParams.Task == "target") {
|
437 |
+
let targetDelta = [
|
438 |
+
target.position.x - rootXYZ[0],
|
439 |
+
target.position.z - rootXYZ[2],
|
440 |
+
];
|
441 |
+
let distance = Math.sqrt(targetDelta.reduce((a, c) => a + c * c, 0));
|
442 |
+
if (distance * M2F < 2.0) {
|
443 |
+
do {
|
444 |
+
target.position.x = (Math.random() * 80.0 - 40.0) * F2M;
|
445 |
+
target.position.z = (Math.random() * 80.0 - 40.0) * F2M;
|
446 |
+
targetDelta = [
|
447 |
+
target.position.x - rootXYZ[0],
|
448 |
+
target.position.z - rootXYZ[2],
|
449 |
+
];
|
450 |
+
distance = Math.sqrt(targetDelta.reduce((a, c) => a + c * c, 0));
|
451 |
+
} while (distance * M2F < 20.0);
|
452 |
+
}
|
453 |
+
taskVector[0] = (a * targetDelta[0] + c * targetDelta[1]) * M2F;
|
454 |
+
taskVector[1] = (b * targetDelta[0] + d * targetDelta[1]) * M2F;
|
455 |
+
} else if (guiParams.Task == "joystick") {
|
456 |
+
|
457 |
+
if (gamepad.connected) {
|
458 |
+
gamepad.update();
|
459 |
+
heading = Math.atan2(gamepad.lStick.x, gamepad.lStick.y);
|
460 |
+
speed = Math.min(Math.max(gamepad.lStick.length(), 0.2), 0.8);
|
461 |
+
}
|
462 |
+
|
463 |
+
target.position.x = rootXYZ[0] + (2 * speed + 0.6) * Math.cos(heading);
|
464 |
+
target.position.z = rootXYZ[2] + (2 * speed + 0.6) * Math.sin(heading);
|
465 |
+
const targetAngle = heading + rootFacing;
|
466 |
+
speed = Math.floor(speed * 10) / 10; // task vector needs discrete speeds
|
467 |
+
taskVector[0] = speed * Math.cos(targetAngle);
|
468 |
+
taskVector[1] = speed * Math.sin(targetAngle);
|
469 |
+
|
470 |
+
let dz = camera.position.z - controls.target.z;
|
471 |
+
let dx = camera.position.x - controls.target.x;
|
472 |
+
let cameraAngle = Math.atan2(dz, dx) + gamepad.rStick.x * 10 / 360 * Math.PI;
|
473 |
+
|
474 |
+
let cx = rootXYZ[0] + Math.cos(cameraAngle) * 30;
|
475 |
+
let cz = rootXYZ[2] + Math.sin(cameraAngle) * 30;
|
476 |
+
camera.position.set(cx, 10, cz);
|
477 |
+
|
478 |
+
controls.target.x = rootXYZ[0];
|
479 |
+
controls.target.z = rootXYZ[2];
|
480 |
+
} else {
|
481 |
+
console.log(`Oops, "${guiParams.Task}" if not a supported task.`);
|
482 |
+
}
|
483 |
+
|
484 |
+
// Get action from policy
|
485 |
+
let controllerInput = new onnx.Tensor(new Float32Array(269), "float32", [1, 269]);
|
486 |
+
for (let i = 0; i < condition.size; i++) {
|
487 |
+
// Controller input is denormalized
|
488 |
+
const c = condition.get([0, i]) * poseStd[i] + poseAvg[i];
|
489 |
+
controllerInput.set(c, [0, i]);
|
490 |
+
}
|
491 |
+
for (let i = 0; i < taskVector.length; i++) {
|
492 |
+
const c = taskVector[i] + 0.00001; // Make sure it's float
|
493 |
+
controllerInput.set(c, [0, condition.size + i]);
|
494 |
+
}
|
495 |
+
await onnxSessions[guiParams.Task]
|
496 |
+
.run([controllerInput])
|
497 |
+
.then((output) => {
|
498 |
+
action = output.values().next().value;
|
499 |
+
});
|
500 |
+
|
501 |
+
// Get next frame from decoder
|
502 |
+
await onnxSessions.mvae.run([action, condition]).then((output) => {
|
503 |
+
condition = output.values().next().value;
|
504 |
+
});
|
505 |
+
|
506 |
+
const pose = condition.data;
|
507 |
+
|
508 |
+
// Integrate root translation
|
509 |
+
// Denormalize and convert to meters for joint positions
|
510 |
+
const normPose = pose.slice(0, 69).map((p, i) => {
|
511 |
+
return (p * poseStd[i] + poseAvg[i]) * F2M;
|
512 |
+
});
|
513 |
+
// "Unconvert" root facing delta
|
514 |
+
normPose[2] = normPose[2] / F2M;
|
515 |
+
|
516 |
+
const gdx = normPose[0];
|
517 |
+
const gdz = normPose[1];
|
518 |
+
const ldx = a * gdx + b * gdz; // local frame
|
519 |
+
const ldz = c * gdx + d * gdz; // local frame
|
520 |
+
rootXYZ[0] += ldx;
|
521 |
+
rootXYZ[2] += ldz;
|
522 |
+
rootFacing = (rootFacing + normPose[2]) % TAU;
|
523 |
+
|
524 |
+
// Set joint positions
|
525 |
+
for (let i = 0; i < joints.length; i++) {
|
526 |
+
const j = (i + 1) * 3;
|
527 |
+
const k = j + 1;
|
528 |
+
const l = j + 2;
|
529 |
+
|
530 |
+
// Rotate joint positions to global frame
|
531 |
+
const gx = normPose[j];
|
532 |
+
const gz = normPose[l];
|
533 |
+
const lx = a * gx + b * gz;
|
534 |
+
const lz = c * gx + d * gz;
|
535 |
+
|
536 |
+
// Render needs denormalized conditions
|
537 |
+
joints[i].position.x = lx + rootXYZ[0];
|
538 |
+
joints[i].position.y = normPose[k];
|
539 |
+
joints[i].position.z = lz + rootXYZ[2];
|
540 |
+
}
|
541 |
+
|
542 |
+
// Set joint links
|
543 |
+
for (let i = 0; i < links.length; i++) {
|
544 |
+
const [j, k] = linkedJoints[i];
|
545 |
+
const [jx, jy, jz] = [
|
546 |
+
joints[j].position.x,
|
547 |
+
joints[j].position.y,
|
548 |
+
joints[j].position.z,
|
549 |
+
];
|
550 |
+
const [kx, ky, kz] = [
|
551 |
+
joints[k].position.x,
|
552 |
+
joints[k].position.y,
|
553 |
+
joints[k].position.z,
|
554 |
+
];
|
555 |
+
const position = [(kx + jx) / 2, (ky + jy) / 2, (kz + jz) / 2];
|
556 |
+
const delta = [kx - jx, ky - jy, kz - jz];
|
557 |
+
const length = Math.sqrt(delta.reduce((a, c) => a + c * c, 0));
|
558 |
+
const quaternion = [delta[2], 0, -delta[0], length + delta[1]];
|
559 |
+
const qnorm = Math.sqrt(quaternion.reduce((a, c) => a + c * c, 0));
|
560 |
+
|
561 |
+
links[i].scale.y = length;
|
562 |
+
links[i].position.x = position[0];
|
563 |
+
links[i].position.y = position[1];
|
564 |
+
links[i].position.z = position[2];
|
565 |
+
links[i].quaternion.x = quaternion[0] / qnorm;
|
566 |
+
links[i].quaternion.y = quaternion[1] / qnorm;
|
567 |
+
links[i].quaternion.z = quaternion[2] / qnorm;
|
568 |
+
links[i].quaternion.w = quaternion[3] / qnorm;
|
569 |
+
}
|
570 |
+
|
571 |
+
// Set head position
|
572 |
+
head.position.x = 1.75 * joints[4].position.x - 0.75 * joints[3].position.x;
|
573 |
+
head.position.y = 1.75 * joints[4].position.y - 0.75 * joints[3].position.y;
|
574 |
+
head.position.z = 1.75 * joints[4].position.z - 0.75 * joints[3].position.z;
|
575 |
+
|
576 |
+
// must be called after any manual changes to the camera
|
577 |
+
// or if enableDamping is true
|
578 |
+
controls.update();
|
579 |
+
renderer.render(scene, camera);
|
580 |
+
}
|
581 |
+
};
|
582 |
+
|
583 |
+
button.remove();
|
584 |
+
animate();
|
585 |
+
}
|
586 |
+
})();
|
style.css
DELETED
@@ -1,28 +0,0 @@
|
|
1 |
-
body {
|
2 |
-
padding: 2rem;
|
3 |
-
font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
|
4 |
-
}
|
5 |
-
|
6 |
-
h1 {
|
7 |
-
font-size: 16px;
|
8 |
-
margin-top: 0;
|
9 |
-
}
|
10 |
-
|
11 |
-
p {
|
12 |
-
color: rgb(107, 114, 128);
|
13 |
-
font-size: 15px;
|
14 |
-
margin-bottom: 10px;
|
15 |
-
margin-top: 5px;
|
16 |
-
}
|
17 |
-
|
18 |
-
.card {
|
19 |
-
max-width: 620px;
|
20 |
-
margin: 0 auto;
|
21 |
-
padding: 16px;
|
22 |
-
border: 1px solid lightgray;
|
23 |
-
border-radius: 16px;
|
24 |
-
}
|
25 |
-
|
26 |
-
.card p:last-child {
|
27 |
-
margin-bottom: 0;
|
28 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|