WOW-Engine + PV3Dによる3次元物理演算

3Dの物理演算コンテンツのデモを作ることがあったので覚書。
物理演算のライブラリは数あれど、何も分からなかったのでとりあえず3D対応を謳っていたWOW-Engineを選択。
調べていく中で分かりましたが、物理演算系ライブラリは基本内部計算のみ、表示部分は自前か他のライブラリを使用する必要があるため、 例えばよく知られたBox2Dのような2次元物理演算のライブラリを利用して、3Dでの物理表現を実装することも可能です。
比較なんぞしていないですが、表現によってはそちらの方が動作が軽かったりしそうですね。
ここでは導入方法と実装の考え方をざっくりと。
3Dエンジン部分はPapervision3Dを使用しました。

【導入方法】
まず公式サイトからファイルを入手します。
そのままパブリッシュしようとすると、DListNode云々と怒られるので、ここからpolygonalクラスというのを入手して配置する必要があります。データ構造を扱いやすくするライブラリだそうです。

【実装】
まず各クラスの処理を簡略化したものがこちら。WOW-Engine + PV3D による3D物理演算コンテンツ概略図

WOW-EngineとPapervisionで全く同じ舞台を作ってやります。
Physics側では何も表示されませんが、物体が壁に当たると跳ね返ったりします。
View3D側では物体が表示されますが壁に当たっても素通りしてしまいます。
物理演算が適用された舞台をディスプレイに表示するため、毎フレームrenderとstep(WOW側のrender) を実行すると同時に、PV3Dのオブジェクトの座標をWOW-Engineの座標と同期させてやるわけです。

ポイントとしては主にWOW-Engine側、初期設定はこんな感じ。

//WOWインスタンス化。引数はフレームレートに対してどのくらいの間隔で計算を行うか。
wow = new WOWEngine(1);
//衝突判定設定?値が大きいと細かい衝突が無視される。 wow.STANDARD=100、SELECTIVE=200、SIMPLE=300。
wow.collisionResponseMode = wow.STANDARD;
//常に働く力(ここではY:重力を設定)
wow.addMasslessForce(new WVector(0, -4, 0));
//力の加速度(重力加速度を適用)
wow.damping = .98;

WOWオブジェクトは空間に設置されてた壁(バウンドエリア)と、動くものを分ける必要があります。

//バウンドエリアの設定(PV3Dで作る立方体と同じ大きさ・座標にする)
var ba:WBoundArea = new WBoundArea(900, 900, 900);
ba.setPosition(0, 0, 0);
//弾力
ba.elasticity = 2;
//摩擦
ba.friction = 1;
wow.setBoundArea(ba);

//この箱の中で動く球を作成(x座標、y座標、z座標、半径、固定物か否か、質量、弾力、摩擦)
var sphere:WSphere = new WSphere(0, 450, 0, 60, false, 0.5, 0.7, 0);
//初速度を設定(x,y,z方向への初期速度)
sphere.velocity = new WVector(Math.random()*100-50, Math.random()*100-50, Math.random()*100-50);
//空間に生成
wow.addParticle(sphere);

View3D側で同じ状態をPV3Dで作るとこんな感じ。

//WOWのバウンドエリアに対応する球
var ba:Cube = new Cube(materialList, 900, 900, 900, 4, 4, 4);
addChild(ba);

//箱の中で動く球
var ball:Sphere = new Sphere(material, 60, 8, 8);
addChild(ball);

View3D側、毎フレームWOW-Engineの座標をトレースする処理。

//動かすものの数が多いときはそれぞれ配列に格納して回しましょう。
//WOW-Engineの座標はpx,py,pzなのに注意。
for(var i:uint=0; i<pvObjArray.length; i++) {
	pvObjArray[i].x = _physics.wowObjArray[i].px;
	pvObjArray[i].y = _physics.wowObjArray[i].py;
	pvObjArray[i].z = _physics.wowObjArray[i].pz;
}
render.renderScene(scene, camera, viewport);

 
【SWF】WOW-Engine + PV3D デモ
上記のスクリプトを使ったデモです。
箱の中に球を生成させランダムな方向に降らせています。一定個数で古いものから消すようにしますが、当然Physicsとview3Dの両方でオブジェクトを消す必要があります。
view3Dは普通にremoveChildで。
注意するのはphysics(WOW-Engine)側、消すときはremoveParticleというメソッドを使うのですが、生成する際のaddParticleの引数にはWParticle型を指定するのに対して、removeParticleはDListNode型を指定する必要があります。これはaddParticleをした際返り値として取得ができます。

//球オブジェクトを生み出す関数内
var sphere:WSphere = new WSphere(0, 450, 0, 60, false, 0.5, 0.7, 0);
sphere.velocity = new WVector(Math.random()*100-50, Math.random()*100-50, Math.random()*100-50);
//WOWエンジンにWSphereを追加した際の返り値を配列に保存
var p:DListNode = wow.addParticle(sphere);
DListNodeArray.push(p);
//古いオブジェクトから消す処理、DListNodeArrayに保存されたDListNodeをremoveParticleには使用する。
if (DListNodeArray.length > 10) {
	wow.removeParticle(DListNodeArray[0]);
	DListNodeArray.shift();
}

 
3次元と物理演算ということで身構える要素沢山ですが、このようなライブラリを使用すると驚くほど簡単にとりあえず動くレベルのものができました。
いろいろパラメーターがあるので気持ち良く動くまで試行錯誤です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です