Three.jsは見た目上のオブジェクトを作成するものなので、オブジェクト同士を衝突させようと思ってもすり抜けてしまいます。そこで、Three.jsでオブジェクト同士の衝突を行うために物理エンジンのCannon.jsを使ってみます。
##考え方
見た目上の世界を作成しいるThree.jsと、物体が実際に衝突等を起すCannon.jsの世界がある。
Cannon.jsの世界の各オブジェクトの位置をThree.jsの各オブジェクトにコピーする。
すると、見た目上でも実際にオブジェクト同士が質感をもって動く。
##物理演算ワールド
Three.jsと同様にまずは物理演算の対象となる世界を作成します。
var world = new CANNON.World();
world.gravity.set(0, -10, 0); //重力を設定
world.broadphase = new CANNON.NaiveBroadphase(); //ぶつかっている可能性のあるオブジェクト同士を見つける
world.solver.iterations = 8; //反復計算回数
world.solver.tolerance = 0.1; //許容値
1行目に物理演算ワールドを作成します。
2行目で重力を設定しています。
3行目にぶつかっている可能性のあるオブジェクト同士を見つけています。物理演算は処理の重いものなので、全てを計算するのではなく、ぶつかっている可能性のあるものをピックアップし、その後実際に計算しています。
4行目は反復計算回数といって計算を何回行うかを決定します。しかし、ここでいう計算というのは正確なものではなく、ざっくりとしたものです。なので、その計算を複数回繰り返すことで誤差を小さくしていきます。大体5~10回すれば不正確さは収束するそうです。
5行目で誤差をどのくらいまで許容するかを決めています。
##オブジェクトを作る
ボックスと床を作成します。
var mass = 1;
var shape = new CANNON.Box(new CANNON.Vec3(5, 5, 5));
var phyBox = new CANNON.Body({mass, shape});
phyBox.angularVelocity.set(0, 5, 10); //角速度
phyBox.angularDamping = 0.1; //減衰率
world.add(phyBox);
始めに重さと形を設定し、その値をしようしてオブジェクトを作成しています。
angularVelocityは初期の角速度を設定します。
angularDampingでは減衰率を設定しています。時間が経つにつれ回転が遅くなっていきます。
var mass = 0;
var shape = new CANNON.Plane();
var phyPlane = newCANNON.Body({mass, shape});
phyPlane.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2); //X軸に90度回転
world.add(phyPlane);
床は動かないようにする必要があるため質量を0にします。こうすることで動かないオブジェクトが作成できます。
##物理演算ワールドの時間を進める
world.step(1 / 60);
時間を進めます。
ここでは60FPS(約0.016s)に設定しています。
##Cannon.jsの値をThree.jsにコピーする
box.position.copy(phyBox.position);
box.quaternion.copy(phyBox.quaternion);
positionとquaternionの値をコピーします。
quaternionは四元数と呼ばれるもので、ここでは回転を表しています。
Cannon.jsはThree.jsととても相性が良いので、普段Three.jsを使っている方でしたら、特に問題なく自然と使えると思います。