{"id":87,"date":"2011-03-08T23:35:20","date_gmt":"2011-03-09T05:35:20","guid":{"rendered":"http:\/\/timothypoon.com\/blog\/?p=87"},"modified":"2011-04-20T11:05:44","modified_gmt":"2011-04-20T17:05:44","slug":"using-three-js-and-jiglibjs-together","status":"publish","type":"post","link":"https:\/\/timothypoon.com\/blog\/2011\/03\/08\/using-three-js-and-jiglibjs-together\/","title":{"rendered":"Using Three.js and JigLibJS Together"},"content":{"rendered":"<p>For whatever reason, one of my projects at my current employer led me to a need for doing some 3D work in HTML5&#8217;s canvas element. After a few hack-ish, amateur attempts at repurposing what I&#8217;d done for <a title=\"Using WebSockets With PHP | if then else\" href=\"http:\/\/timothypoon.com\/blog\/2010\/05\/03\/using-websockets-with-php\/\">Mega Hovertank Wars<\/a>, I decided to use something with a community behind it and found <a title=\"mrdoob\/three.js - GitHub\" href=\"https:\/\/github.com\/mrdoob\/three.js\/\">three.js<\/a> from <a title=\"Mr.doob | Disturb (HTML5)\" href=\"http:\/\/mrdoob.com\/\">Mr.doob<\/a>, a man you may have heard of through his work on Arcade Fire&#8217;s HTML5 experiment &#8220;<a title=\"The Wilderness Downtown\" href=\"http:\/\/www.thewildernessdowntown.com\/\">The Wilderness Downtown<\/a>.&#8221; There are plenty of other options out there (including <a title=\"SceneJS - WebGL Scene Graph Library\" href=\"http:\/\/scenejs.org\/\">some<\/a> <a title=\"OneGeek\/WebGLU - GitHub\" href=\"https:\/\/github.com\/OneGeek\/WebGLU\">that<\/a> <a title=\"Canvas 3d JS Library\" href=\"http:\/\/www.c3dl.org\/\">use<\/a> WebGL rather than a pure canvas renderer), but I think after perusing its examples and reading <a title=\"Seb Lee-Delisle\" href=\"http:\/\/sebleedelisle.com\/\">Seb Lee-Delisle&#8217;s blog<\/a>, I&#8217;d settled on three.js.<\/p>\n<p>By modifying the geometry_cube.html example, I arrived at this:<\/p>\n<p><a href=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-1.jpg\"><img decoding=\"async\" class=\"aligncenter size-large wp-image-88\" title=\"Altering the geometry_cube.html three.js example\" src=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-1-1024x527.jpg\" alt=\"Altering the geometry_cube.html three.js example\" width=\"100%\" srcset=\"https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-1-1024x527.jpg 1024w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-1-300x154.jpg 300w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-1.jpg 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>All I did was change the face materials of the starting cube and used that materials array to color the 5 flaps below (along with changing some <em>Camera()<\/em> and <em>Cube()<\/em> dimension and position parameters, but those are pretty obvious):<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/>30<br \/>31<br \/><\/div><\/td><td><div class=\"javascript codecolorer\">camera <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">Camera<\/span><span class=\"br0\">&#40;<\/span> <span class=\"nu0\">45<\/span><span class=\"sy0\">,<\/span> window.<span class=\"me1\">innerWidth<\/span> <span class=\"sy0\">\/<\/span> window.<span class=\"me1\">innerHeight<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">3000<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\ncamera.<span class=\"me1\">position<\/span>.<span class=\"me1\">y<\/span> <span class=\"sy0\">=<\/span> <span class=\"nu0\">50<\/span><span class=\"sy0\">;<\/span><br \/>\ncamera.<span class=\"me1\">position<\/span>.<span class=\"me1\">z<\/span> <span class=\"sy0\">=<\/span> <span class=\"nu0\">1500<\/span><span class=\"sy0\">;<\/span><br \/>\ncamera.<span class=\"me1\">target<\/span>.<span class=\"me1\">position<\/span>.<span class=\"me1\">y<\/span> <span class=\"sy0\">=<\/span> <span class=\"nu0\">50<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\nscene <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">Scene<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"co1\">\/\/ Cube<\/span><br \/>\n<br \/>\n<span class=\"kw1\">var<\/span> materials <span class=\"sy0\">=<\/span> <span class=\"br0\">&#91;<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><br \/>\nmaterials.<span class=\"me1\">push<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#91;<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">MeshBasicMaterial<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#123;<\/span> color<span class=\"sy0\">:<\/span> 0x0000ff <span class=\"br0\">&#125;<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Left side<\/span><br \/>\nmaterials.<span class=\"me1\">push<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#91;<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">MeshBasicMaterial<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#123;<\/span> color<span class=\"sy0\">:<\/span> 0x666666 <span class=\"br0\">&#125;<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Right side<\/span><br \/>\nmaterials.<span class=\"me1\">push<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#91;<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">MeshBasicMaterial<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#123;<\/span> color<span class=\"sy0\">:<\/span> 0xff0000 <span class=\"br0\">&#125;<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Top side<\/span><br \/>\nmaterials.<span class=\"me1\">push<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#91;<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">MeshBasicMaterial<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#123;<\/span> color<span class=\"sy0\">:<\/span> 0x00ff00 <span class=\"br0\">&#125;<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Bottom side<\/span><br \/>\nmaterials.<span class=\"me1\">push<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#91;<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">MeshBasicMaterial<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#123;<\/span> color<span class=\"sy0\">:<\/span> 0xcccccc <span class=\"br0\">&#125;<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Front side<\/span><br \/>\nmaterials.<span class=\"me1\">push<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#91;<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">MeshBasicMaterial<\/span><span class=\"br0\">&#40;<\/span> <span class=\"br0\">&#123;<\/span> color<span class=\"sy0\">:<\/span> 0x000000 <span class=\"br0\">&#125;<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span> &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Back side<\/span><br \/>\n<br \/>\ncube <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">Mesh<\/span><span class=\"br0\">&#40;<\/span> <span class=\"kw1\">new<\/span> Cube<span class=\"br0\">&#40;<\/span> <span class=\"nu0\">925<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">460<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">10<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> materials <span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">MeshFaceMaterial<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\ncube.<span class=\"me1\">position<\/span>.<span class=\"me1\">y<\/span> <span class=\"sy0\">=<\/span> <span class=\"nu0\">150<\/span><span class=\"sy0\">;<\/span><br \/>\ncube.<span class=\"me1\">overdraw<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\nscene.<span class=\"me1\">addObject<\/span><span class=\"br0\">&#40;<\/span> cube <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"co1\">\/\/ Flap<\/span><br \/>\n<span class=\"kw1\">for<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> i <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> offset.<span class=\"me1\">length<\/span><span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">Mesh<\/span><span class=\"br0\">&#40;<\/span> <span class=\"kw1\">new<\/span> Cube<span class=\"br0\">&#40;<\/span> <span class=\"nu0\">160<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">160<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">10<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> materials <span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">MeshFaceMaterial<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">autoUpdateMatrix<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">false<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">overdraw<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">position<\/span>.<span class=\"me1\">y<\/span> <span class=\"sy0\">=<\/span> flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">originalY<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">&#40;<\/span>i <span class=\"sy0\">%<\/span> <span class=\"nu0\">2<\/span> <span class=\"sy0\">==<\/span> <span class=\"nu0\">1<\/span> <span class=\"sy0\">?<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">210<\/span> <span class=\"sy0\">:<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">250<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">position<\/span>.<span class=\"me1\">x<\/span> <span class=\"sy0\">=<\/span> offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; scene.<span class=\"me1\">addObject<\/span><span class=\"br0\">&#40;<\/span>flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>That was the simple part. The only true oddity is setting the <strong>autoUpdateMatrix<\/strong> attribute of each square to <strong>false<\/strong>. This is because if you don&#8217;t do this, you can&#8217;t manually modify each square&#8217;s matrix later on. Also, if you notice, when you drag around on the example, the cube spins, and I wanted to incorporate that into the &#8220;flaps&#8221; animations.<\/p>\n<h2>Relative Animation<\/h2>\n<p>Well, that&#8217;s what I&#8217;m calling it anyways. What it really means is that I based the &#8220;flapping&#8221; intensity on the difference between the main panel&#8217;s <strong>targetRotation<\/strong> and current rotation (<strong>cube.rotation.y<\/strong>).<\/p>\n<p>The physics I was hoping to achieve was something that looked like there is a rope between the panel and the squares and they flail in the wind behind the panel as it rotates. Something like this:<\/p>\n<p><a href=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-2.jpg\"><img decoding=\"async\" src=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-2-1024x527.jpg\" alt=\"\" title=\"Flailing squares attached to the bottom of the panel\" width=\"100%\" class=\"aligncenter size-large wp-image-89\" srcset=\"https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-2-1024x527.jpg 1024w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-2-300x154.jpg 300w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-2.jpg 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>It looks pretty good considering the code is based mostly on basic advanced math.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> cval <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">cos<\/span><span class=\"br0\">&#40;<\/span>cube.<span class=\"me1\">rotation<\/span>.<span class=\"me1\">y<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> sval <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">sin<\/span><span class=\"br0\">&#40;<\/span>cube.<span class=\"me1\">rotation<\/span>.<span class=\"me1\">y<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> rot <span class=\"sy0\">=<\/span> <span class=\"br0\">&#40;<\/span>targetRotation <span class=\"sy0\">-<\/span> cube.<span class=\"me1\">rotation<\/span>.<span class=\"me1\">y<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"nu0\">0.6<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> dir <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">Vector3<\/span><span class=\"br0\">&#40;<\/span>cval<span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"sy0\">-<\/span>sval<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">for<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> i <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> flap.<span class=\"me1\">length<\/span><span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> nrot <span class=\"sy0\">=<\/span> rot <span class=\"sy0\">*<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">abs<\/span><span class=\"br0\">&#40;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">\/<\/span> <span class=\"nu0\">382.5<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>nrot <span class=\"sy0\">&gt;<\/span> PI2<span class=\"br0\">&#41;<\/span> nrot <span class=\"sy0\">=<\/span>PI2<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">else<\/span> <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>nrot <span class=\"sy0\">&lt;<\/span> <span class=\"sy0\">-<\/span>PI2<span class=\"br0\">&#41;<\/span> nrot <span class=\"sy0\">=<\/span> <span class=\"sy0\">-<\/span>PI2<span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">position<\/span>.<span class=\"me1\">x<\/span> <span class=\"sy0\">=<\/span> offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">*<\/span> cval<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">position<\/span>.<span class=\"me1\">z<\/span> <span class=\"sy0\">=<\/span> <span class=\"sy0\">-<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">*<\/span> sval<span class=\"sy0\">;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">!=<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">position<\/span>.<span class=\"me1\">y<\/span> <span class=\"sy0\">=<\/span> <span class=\"br0\">&#40;<\/span>flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">originalY<\/span> <span class=\"sy0\">+<\/span> <span class=\"nu0\">80<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">-<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">abs<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">cos<\/span><span class=\"br0\">&#40;<\/span>nrot<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"nu0\">80<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">var<\/span> rval <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">sin<\/span><span class=\"br0\">&#40;<\/span>nrot<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">originalY<\/span><span class=\"sy0\">;<\/span><span class=\"co1\">\/\/ flap[i].originalY for trailing, flap[i].height\/2 (or 80) for hinge<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">position<\/span>.<span class=\"me1\">x<\/span> <span class=\"sy0\">+=<\/span> rval <span class=\"sy0\">*<\/span> sval <span class=\"sy0\">*<\/span> <span class=\"sy0\">-<\/span><span class=\"br0\">&#40;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">\/<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">abs<\/span><span class=\"br0\">&#40;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">position<\/span>.<span class=\"me1\">z<\/span> <span class=\"sy0\">+=<\/span> rval <span class=\"sy0\">*<\/span> cval <span class=\"sy0\">*<\/span> <span class=\"sy0\">-<\/span><span class=\"br0\">&#40;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">\/<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">abs<\/span><span class=\"br0\">&#40;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; alignCube<span class=\"br0\">&#40;<\/span>flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir.<span class=\"me1\">normalize<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">&lt;<\/span> <span class=\"nu0\">0<\/span> <span class=\"sy0\">?<\/span> <span class=\"nu0\">1<\/span> <span class=\"sy0\">:<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> nrot<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>The first key is that in the lines where I&#8217;m setting each flap&#8217;s <strong>position.y<\/strong>, <strong>position.x<\/strong> and <strong>position.z<\/strong> values, that is to give the &#8220;roped&#8221; effect. All I&#8217;m really doing is adding to each position coordinate as if it were rotating on a hinge. Simple math!<\/p>\n<p>The second key is that you are determining the vector pointing along the front face of the panel at any given point of the rotation by taking the <em>Math.cos()<\/em> and <em>Math.sin()<\/em> values of the current rotational value of the panel. This allows us to find the axis we need to rotate each square.<\/p>\n<h2>3D Rotation Along An Arbitrary Axis<\/h2>\n<p>However, doing this was harder than I thought it would be. After some quick Googling, however, I found <a href=\"http:\/\/stackoverflow.com\/questions\/3809788\/3d-rotation-with-axis-angle\" title=\"javascript - 3D rotation with Axis &amp; Angle - Stack Overflow\">an extremely helpful Stack Overflow post<\/a> and simply adapted some of the help in the discussion for my own purposes:<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">function<\/span> alignCube<span class=\"br0\">&#40;<\/span>target<span class=\"sy0\">,<\/span> dir<span class=\"sy0\">,<\/span> rot<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> up <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">Vector3<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> angle <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">acos<\/span><span class=\"br0\">&#40;<\/span>up.<span class=\"me1\">dot<\/span><span class=\"br0\">&#40;<\/span>dir<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> axis <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">Vector3<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; axis.<span class=\"me1\">cross<\/span><span class=\"br0\">&#40;<\/span>up<span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; axis.<span class=\"me1\">normalize<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> position <span class=\"sy0\">=<\/span> THREE.<span class=\"me1\">Matrix4<\/span>.<span class=\"me1\">translationMatrix<\/span><span class=\"br0\">&#40;<\/span> target.<span class=\"me1\">position<\/span>.<span class=\"me1\">x<\/span><span class=\"sy0\">,<\/span> target.<span class=\"me1\">position<\/span>.<span class=\"me1\">y<\/span><span class=\"sy0\">,<\/span> target.<span class=\"me1\">position<\/span>.<span class=\"me1\">z<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> rotate <span class=\"sy0\">=<\/span> THREE.<span class=\"me1\">Matrix4<\/span>.<span class=\"me1\">rotationAxisAngleMatrix<\/span><span class=\"br0\">&#40;<\/span>axis<span class=\"sy0\">,<\/span> angle<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> revolve <span class=\"sy0\">=<\/span> THREE.<span class=\"me1\">Matrix4<\/span>.<span class=\"me1\">rotationAxisAngleMatrix<\/span><span class=\"br0\">&#40;<\/span>dir<span class=\"sy0\">,<\/span> rot<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> scale <span class=\"sy0\">=<\/span> THREE.<span class=\"me1\">Matrix4<\/span>.<span class=\"me1\">scaleMatrix<\/span><span class=\"br0\">&#40;<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; revolve.<span class=\"me1\">multiplySelf<\/span><span class=\"br0\">&#40;<\/span>rotate<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; position.<span class=\"me1\">multiplySelf<\/span><span class=\"br0\">&#40;<\/span>revolve<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; target.<span class=\"me1\">matrix<\/span> <span class=\"sy0\">=<\/span> position<span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>To simplify, you want to find the axis and angle that will get the original vector to match the desired vector, <a href=\"http:\/\/en.wikipedia.org\/wiki\/Cross-multiplication\" title=\"Cross-multiplication - Wikipedia, the free encyclopedia\">cross-multiply<\/a> them, and <a href=\"http:\/\/en.wikipedia.org\/wiki\/Unit_vector\" title=\"Unit vector - Wikipedia, the free encyclopedia\">normalize<\/a>. That will allow you to form the rotation and revolution matrices which you can then multiply with the position matrix (the ordering of which is important, i.e. (revolve x rotate) x position) which results in the final position and orientation matrix.<\/p>\n<h2>Integrating JigLibJS Physics<\/h2>\n<p>Unfortunately, this wasn&#8217;t as realistic as I&#8217;d hoped. I could have done more tweaking to avoid some faults against true physics (such as when you abruptly change directions but only to stop rotation, the squares don&#8217;t swing back and forth in a natural fashion), but the end goal for this little side project was much more grand to the point where it just made more sense to use real physics.<\/p>\n<p>Always interested by physics engines such as <a href=\"http:\/\/www.havok.com\/\" title=\"Havok - Home\">Havok<\/a>, a popular choice for video game developers, I started to browse. I first arrived at a port of the <a href=\"http:\/\/bulletphysics.org\/\" title=\"Game Physics Simulation\">Bullet Physics Library<\/a> for JavaScript by <a href=\"http:\/\/pl4n3.blogspot.com\/2010\/07\/bulletjs-javascript-physics-engine.html\" title=\"Pl4n3s world: bullet.js - Javascript Physics Engine\">Pl4n3<\/a>, but it was incredibly buggy. Object would collide and bounce and almost always freeze. I love the effort, but bullet.js was a definite no-go.<\/p>\n<p>Remembering a physics library called JigLib that was ported to Flash from Java, I hoped that someone had done the same for JavaScript, and luckily someone had! <a href=\"http:\/\/www.jiglibjs.org\/\" title=\"JigLibJS\">JigLibJS<\/a> was functional, actively developed, and&mdash;most importantly&mdash;stable.<\/p>\n<p>If you&#8217;re not aware (and I wasn&#8217;t prior to this little excursion, though in hindsight, it makes total sense), physics engines work by pretty much having you define objects from your rendered model world in the physics world. You then access the objects in the physics engine and take their position and orientations and apply them to the rendering engine, so this is what I did.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> system <span class=\"sy0\">=<\/span> jigLib.<span class=\"me1\">PhysicsSystem<\/span>.<span class=\"me1\">getInstance<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nsystem.<span class=\"me1\">setGravity<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,-<\/span><span class=\"nu0\">9.8<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><span class=\"co1\">\/\/-120<\/span><br \/>\nsystem.<span class=\"me1\">setSolverType<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'ACCUMULATED'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><span class=\"co1\">\/\/FAST, NORMAL, ACCUMULATED<\/span><br \/>\n<br \/>\n<span class=\"kw1\">var<\/span> ground <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> jigLib.<span class=\"me1\">JPlane<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">null<\/span><span class=\"sy0\">,<\/span><span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">1<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nground.<span class=\"me1\">set_friction<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">10<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nsystem.<span class=\"me1\">addBody<\/span><span class=\"br0\">&#40;<\/span>ground<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nground.<span class=\"me1\">moveTo<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,-<\/span><span class=\"nu0\">650<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\npanel <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> jigLib.<span class=\"me1\">JBox<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">null<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">925<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">10<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">460<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\npanel.<span class=\"me1\">set_mass<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">50<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\npanel.<span class=\"me1\">moveTo<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">150<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\npanel.<span class=\"me1\">set_movable<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">false<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nsystem.<span class=\"me1\">addBody<\/span><span class=\"br0\">&#40;<\/span>panel<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>JigLibJS is pretty intuitive. The first two lines are system-wide parameters in that everything works on a -9.8 units per second per second gravity and uses the accumulated solver type (it&#8217;s the most accurate but is also the slowest of the three).<\/p>\n<p>JigLibJS automatically considers <em>JPlane()<\/em> objects to be immovable and can thus easily be added to be ground and wall boundaries in the physics system. Other items like boxes are defined and moved about in a manner similar to three.js, so that was handy. One key line for the panel variable is the <em>set_movable(<strong>false<\/strong>)<\/em> so that it isn&#8217;t not going to move about under gravity or as other JigLibJS objects collide with it.<\/p>\n<p>I simply repeated that for each square that I wanted and voila, an accurate representation of my models in JigLibJS!<\/p>\n<h2>Putting three.js and JigLibJS Together<\/h2>\n<p>At this point it was really just taking one matrix (from JigLibJS) and setting the three.js matrix to it. The only weird thing is that I chose to orient the JigLibJS representation of the panel to the three.js representation while the squares went the other way around, i.e. from three.js to JigLibJS. This becomes clear later when I do the world constraints.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/><\/div><\/td><td><div class=\"javascript codecolorer\">cube.<span class=\"me1\">rotation<\/span>.<span class=\"me1\">y<\/span> <span class=\"sy0\">+=<\/span> <span class=\"br0\">&#40;<\/span> targetRotation <span class=\"sy0\">-<\/span> cube.<span class=\"me1\">rotation<\/span>.<span class=\"me1\">y<\/span> <span class=\"br0\">&#41;<\/span> <span class=\"sy0\">*<\/span> <span class=\"nu0\">0.05<\/span><span class=\"sy0\">;<\/span><br \/>\npanel.<span class=\"me1\">set_rotationY<\/span><span class=\"br0\">&#40;<\/span> cube.<span class=\"me1\">rotation<\/span>.<span class=\"me1\">y<\/span> <span class=\"sy0\">*<\/span> <span class=\"br0\">&#40;<\/span><span class=\"nu0\">180<\/span><span class=\"sy0\">\/<\/span><span class=\"kw4\">Math<\/span>.<span class=\"me1\">PI<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<br \/>\nnow <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> <span class=\"kw4\">Date<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">getTime<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nsystem.<span class=\"me1\">integrate<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#40;<\/span>now <span class=\"sy0\">-<\/span> then<span class=\"br0\">&#41;<\/span> <span class=\"sy0\">\/<\/span> <span class=\"nu0\">75<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><span class=\"co1\">\/\/400<\/span><br \/>\nthen <span class=\"sy0\">=<\/span> now<span class=\"sy0\">;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">for<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> i <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> offset.<span class=\"me1\">length<\/span><span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> pos <span class=\"sy0\">=<\/span> obj<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">get_currentState<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">position<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> dir <span class=\"sy0\">=<\/span> obj<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">get_currentState<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">get_orientation<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span>.<span class=\"me1\">glmatrix<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> position <span class=\"sy0\">=<\/span> THREE.<span class=\"me1\">Matrix4<\/span>.<span class=\"me1\">translationMatrix<\/span><span class=\"br0\">&#40;<\/span> pos<span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> pos<span class=\"br0\">&#91;<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> pos<span class=\"br0\">&#91;<\/span><span class=\"nu0\">2<\/span><span class=\"br0\">&#93;<\/span> <span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">var<\/span> rotate <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> THREE.<span class=\"me1\">Matrix4<\/span><span class=\"br0\">&#40;<\/span>dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">2<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">3<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">4<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">5<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">6<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">7<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">8<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">9<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">10<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">11<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">12<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">13<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">14<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> dir<span class=\"br0\">&#91;<\/span><span class=\"nu0\">15<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; position.<span class=\"me1\">multiplySelf<\/span><span class=\"br0\">&#40;<\/span>rotate<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">matrix<\/span> <span class=\"sy0\">=<\/span> position<span class=\"sy0\">;<\/span><br \/>\n&nbsp; &nbsp; flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">update<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw2\">false<\/span><span class=\"sy0\">,<\/span> <span class=\"kw2\">true<\/span><span class=\"sy0\">,<\/span> camera<span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>It&#8217;s very similar to the <em>alignCube()<\/em> function we had before, except the trouble of turning an axis and an angle into a matrix is done for us prior by JigLibJS. The result is some square falling from underneath the panel and laying there. Exciting, right?<\/p>\n<p><a href=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-3.jpg\"><img decoding=\"async\" src=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-3-1024x527.jpg\" alt=\"\" title=\"The blocks have fallen\" width=\"100%\" class=\"aligncenter size-large wp-image-92\" srcset=\"https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-3-1024x527.jpg 1024w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-3-300x154.jpg 300w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-3.jpg 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>But remember? I want them to hang like they&#8217;re on ropes, not fall straight to the ground!<\/p>\n<h2>JigLibJS Constraints<\/h2>\n<p>Luckily, JigLibJS has these things called constraints. The unfortunate thing is that they don&#8217;t work exactly as you would imagine. Whereas the <a href=\"http:\/\/www.jiglibjs.org\/JSDocDumps\/0.9.0.2\/symbols\/JConstraintMaxDistance.html\" title=\"JsDoc Reference - JConstraintMaxDistance\">JConstraintMaxDistance<\/a> seems like it should work (or even the <a href=\"http:\/\/www.jiglibjs.org\/JSDocDumps\/0.9.0.2\/symbols\/JConstraintPoint.html\" title=\"JsDoc Reference - JConstraintPoint\">JConstraintPoint<\/a>), they both have a slight&#8230;<em>elasticity<\/em> to their constraining action and it <a href=\"http:\/\/jiglibflash.2262522.n2.nabble.com\/Rope-constraint-td2821253.html\" title=\"jiglibflash - Rope constraint\">can&#8217;t really be avoided<\/a>. I even tried out the <a href=\"http:\/\/nehe.gamedev.net\/data\/lessons\/lesson.asp?lesson=40\" title=\"NeHe Productions: OpenGL Lesson #40\">spring simulation<\/a> solution, but, surprise surprise, it behaved more like a spring than a rope.<\/p>\n<p>Instead, I used <a href=\"http:\/\/www.jiglibjs.org\/JSDocDumps\/0.9.0.2\/symbols\/JConstraintWorldPoint.html\" title=\"JsDoc Reference - JConstraintWorldPoint\">JConstraintWorldPoint<\/a>. It still has a slight stretch to the constraint distance, but it holds pretty well so long as you don&#8217;t spin the panel too fast.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/><\/div><\/td><td><div class=\"javascript codecolorer\">con<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span> <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> jigLib.<span class=\"me1\">JConstraintWorldPoint<\/span><span class=\"br0\">&#40;<\/span>obj<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#91;<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">80<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#91;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">&#40;<\/span>i <span class=\"sy0\">%<\/span> <span class=\"nu0\">2<\/span> <span class=\"sy0\">==<\/span> <span class=\"nu0\">1<\/span> <span class=\"sy0\">?<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">130<\/span> <span class=\"sy0\">:<\/span> <span class=\"sy0\">-<\/span><span class=\"nu0\">170<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\nsystem.<span class=\"me1\">addConstraint<\/span><span class=\"br0\">&#40;<\/span>con<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>This little piece of code was simply added into the loop I had going for when I was creating each square in JigLibJS. It simply adds the constraint to the physics system.<\/p>\n<p>However, since these constraints are simply bound to a point in the world (this is where using JConstraintMaxDistance would have been much simpler), you have to manually move each point that each square is bound to. Luckily, I&#8217;d previous solved this little puzzle back when I was doing relative animation.<\/p>\n<div class=\"codecolorer-container javascript railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/><\/div><\/td><td><div class=\"javascript codecolorer\"><span class=\"kw1\">var<\/span> cval <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">cos<\/span><span class=\"br0\">&#40;<\/span>cube.<span class=\"me1\">rotation<\/span>.<span class=\"me1\">y<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">var<\/span> sval <span class=\"sy0\">=<\/span> <span class=\"kw4\">Math<\/span>.<span class=\"me1\">sin<\/span><span class=\"br0\">&#40;<\/span>cube.<span class=\"me1\">rotation<\/span>.<span class=\"me1\">y<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"kw1\">for<\/span><span class=\"br0\">&#40;<\/span><span class=\"kw1\">var<\/span> i <span class=\"sy0\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">;<\/span> i <span class=\"sy0\">&lt;<\/span> offset.<span class=\"me1\">length<\/span><span class=\"sy0\">;<\/span> i<span class=\"sy0\">++<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; con<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">set_worldPosition<\/span><span class=\"br0\">&#40;<\/span><span class=\"br0\">&#91;<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy0\">*<\/span>cval<span class=\"sy0\">,<\/span> flap<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span>.<span class=\"me1\">originalY<\/span><span class=\"sy0\">+<\/span><span class=\"nu0\">80<\/span><span class=\"sy0\">,<\/span> <span class=\"sy0\">-<\/span>offset<span class=\"br0\">&#91;<\/span>i<span class=\"br0\">&#93;<\/span><span class=\"sy0\">*<\/span>sval<span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"br0\">&#93;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy0\">;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>That takes place within the animation loop and simply iterates over each constraint and moves it according to the orientation of the three.js representation of the panel. If it all goes according to plan, it should look something like this when spun.<\/p>\n<p><a href=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-4.jpg\"><img decoding=\"async\" src=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-4-1024x527.jpg\" alt=\"\" title=\"Physics-enabled spinning!\" width=\"100%\" class=\"aligncenter size-large wp-image-93\" srcset=\"https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-4-1024x527.jpg 1024w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-4-300x154.jpg 300w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2011\/03\/three-js-and-jiglibjs-4.jpg 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/p>\n<p>Yeah, it doesn&#8217;t look like they&#8217;re on ropes, but hey, it&#8217;s a lot closer than I was a few days ago.<\/p>\n<p><a href=\"http:\/\/timothypoon.com\/blog\/demos\/three-js-and-jiglibjs\/\" title=\"three.js and JigLibJS Demo\">View the demo<\/a> (requires an HTML5-capable browser). You can use the up and down arrow keys to move the camera and click the squares to add and remove their respective JigLibJS constraints. The panel also auto-aligns every five seconds, so don&#8217;t freak out when things move without you doing anything.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For whatever reason, one of my projects at my current employer led me to a need for doing some 3D work in HTML5&#8217;s canvas element. After a few hack-ish, amateur attempts at repurposing what I&#8217;d done for Mega Hovertank Wars, I decided to use something with a community behind it and found three.js from Mr.doob, a man you may have heard of through his work on Arcade Fire&#8217;s HTML5 experiment &#8220;The Wilderness Downtown.&#8221; There are plenty of other options out there (including some that use WebGL rather than a pure&#8230;<a class=\"read-more\" href=\"https:\/\/timothypoon.com\/blog\/2011\/03\/08\/using-three-js-and-jiglibjs-together\/\">read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[24,16,22,21,23,20],"class_list":["post-87","post","type-post","status-publish","format-standard","hentry","category-code","tag-3d-rendering","tag-html5","tag-html5-canvas","tag-jiglibjs","tag-physics-engine","tag-three-js","et-no-image","et-bg-layout-dark","et-white-bg"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p462yg-1p","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/87","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/comments?post=87"}],"version-history":[{"count":1,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/87\/revisions"}],"predecessor-version":[{"id":126,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/87\/revisions\/126"}],"wp:attachment":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/media?parent=87"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/categories?post=87"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/tags?post=87"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}