Three.jsの物理演算エンジンPhysi.jsを触ってみた. 

## Physi.jsとは

Three.jsを触り出して、少し経ったので物理シミュレーションをやってみたくなった。
少し調べてみたところ、[Physi.js](https://github.com/chandlerprall/Physijs)というJavaScriptライブラリに行き着いたので、触ってみたメモ.

JavaScriptによる3次元物理シミュレーションのライブラリには、[ammo.js](https://github.com/kripken/ammo.js/)([Bullet](http://bulletphysics.org/wordpress/)のJavaScript実装)があるが、Physi.jsはこれを利用したThree.jsのプラグインである。

特徴的なのは、WebWorkers APIを利用して、ammo.jsによる演算は、rendererが動作するスレッドと分離されている点。

## 取りあえず動かしてみよう.

https://github.com/chandlerprall/Physijs/wiki/Basic-Setup に組み込み方が書いてあるので、この通りにやってみる.

1. http://chandlerprall.github.io/Physijs からを落としてきて、htmlに`<script src="physijs.js">`タグを記述(もちろんthree.jsも読み込む).
 * ちなみにBowerを使っているのであれば、`bower install physijs --save`で簡単に入手できるが、ammo.jsの扱いに注意する必要あり(後述).
1. WebWorkersの設定を行う。`Physijs.scripts.worker`及び、`Physijs.scripts.ammo`にそれぞれphysijs_worker.jsとammo.jsのurlを指定する。
 * なお、URLを相対パスで記述する場合、physijs_worker.jsは、htmlからの相対パスで構わないが、ammo.jsはphysijs_worker.jsが配置されているディレクトリからの相対パスで記載する点に注意(WebWorkers APIのimportScripts()メソッドの仕様です).
1. `Three.scene`を使う代わりに、`Physijs.scene`を利用して、Three.jsの空間を作成する.
1. MeshもThree.Meshを使う代わりに、Physijs.BoxMeshやPhysijs.SphereMesh, Physijs.ConvexMeshを使ってMeshを作成する.
1. アニメーションの処理毎に`scene.simulate()`を実行することで、物理演算が実行される

ただ物体が落ちてきて床にぶつかるだけのサンプルのコードを後方に貼っておく.
実際、やってみるとすげぇ簡単。

http://javascript.g.hatena.ne.jp/edvakf/20111213/1323802428 等の記事で触れられているが、Physi.jsを使わずに生ammo.jsを利用することを考えるとかなり楽である.

## 付録
### 動かしたコード

```js:main.js
'use strict';

(function(THREE, Physijs){
    var initScene, render, renderer, scene, camera, box, light;

    Physijs.scripts.worker = 'bower_components/physijs/physijs_worker.js';
    Physijs.scripts.ammo = 'examples/js/ammo.js';

    initScene = function() {
      var ground, groundMaterial;
      var width = window.innerWidth, height = window.innerHeight;
      renderer = new THREE.WebGLRenderer({ antialias: true });
      renderer.shadowMapEnabled = true;
      renderer.setSize(width, height);
      document.getRootElementById('render_area').appendChild(renderer.domElement);

      // !Three.Sceneでない点に注意!
      scene = new Physijs.Scene();

      // Camera
      camera = new THREE.PerspectiveCamera( 35, width / height, 1, 1000);
      camera.position.set( 60, 50, 60 );
      camera.lookAt( scene.position );
      scene.add( camera );

      // Light
      light = new THREE.SpotLight(0xffffff, 5, 1000, Math.PI / 2, 1);
      light.position.set(0, 100, 80);
      light.castShadow = true;
      light.shadowMapWidth = 1024;
      light.shadowMapHeight = 1024;
      scene.add(light);

      // Box !Three.Meshでない点に注意!
      box = new Physijs.BoxMesh(
        new THREE.CubeGeometry( 5, 5, 5 ),
        new THREE.MeshBasicMaterial({ color: 0xff8020 })
      );
      box.position.set(0, 20, 0);
      box.castShadow = true;
      scene.add( box );

      // Ground
      groundMaterial = Physijs.createMaterial(new THREE.MeshBasicMaterial({ color: 0xffffff }), 0.8, 0.3);
      ground = new Physijs.BoxMesh(new THREE.CubeGeometry(100, 1, 100), groundMaterial, 0);
      ground.receiveShadow = true;
      scene.add(ground);

      render();
    };

     render = function() {
       scene.simulate();
       control.update();
       renderer.render(scene, camera);
       window.requestAnimationFrame(render);
     };

     initScene();
 })(THREE, Physijs);
```

```html:index.html
<!doctype html>
<html>
  <body>

    <div id="rendering"></div>
    <script src="bower_components/threejs/build/three.js"></script>
    <script src="bower_components/physijs/physi.js"></script>
    <script src="scripts/main.js"></script>
  </body>
</html>
```

### bower利用時の注意点

bowerでPhysi.jsを落とした場合、Physi.jsが依存するammo.jsパッケージもinstallされるが、このammo.jsを利用するとエラーとなるため、Physi.jsのExampleに同梱されていたものを利用している。
[このissue](https://github.com/chandlerprall/Physijs/issues/175)にも上がっているが、2014/7/17時点ではopenのままであるので注意されたし。