belinghy commited on
Commit
c89fc88
1 Parent(s): 18405a5

Add controller support

Browse files
Files changed (4) hide show
  1. README.md +1 -1
  2. index.html +4 -3
  3. static/demo.min.js +586 -1
  4. style.css +0 -28
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- title: Character Animation Motion Vaes
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: 800px;
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
- <li>Left-drag to rotate, right-drag to pan, and scroll to zoom</li>
86
- <li>Place target or change direction: <em>Ctrl-click</em> or <em>Cmd-click</em></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
- }