
【フリーのJSライブラリ、LiquidFunによる流体シミュレーション vol.4】流体をかき回すギミックを加える~〔コード解説編〕~
「液体」をシミュレートできる希少なフリーソフトウェア、「LiquidFun(リキッド・ファン)」を使って流体シミュレートを試す記事です。GAS(Google Apps Script)の記事の合間に投稿しています。
LiquidFunの紹介記事はこちらです。
今回は、流体をかき混ぜるギミック(仕掛け)を系に加えてみました。
今回は、そのコード解説になります。
流体をかき回すサンプルのコード
サンプルコードの実装は、LiquidFunのサンプルコードを保存し、その一つを改変することで行います。
このシリーズでは、最も基本的なデモである、DamBreak(水柱崩壊)の中身を書き換えることで実装しています。
詳しい内容は以下を参照ください。
上記でご紹介している要領で、デモのコードを記したファイルのひとつ、以下の中身を書き換えます。
testDamBreak.js
こうすることで、複数のファイル群の相互の設定に手をわずらわされることなく、最小限の修正で済ましています。
今回は、上記ファイルの中身を以下のコードに書き換えました。
function TestDamBreak() {
//-----★カメラ★------
camera.position.x = 4;//def2
camera.position.y = 2;//def2
camera.position.z = 4;//def3
//-----★重力★------
world.SetGravity(new b2Vec2(0, -10));
var bd = new b2BodyDef();
var ground = world.CreateBody(bd);
//-----★底の形★------
var chainShape = new b2ChainShape();
chainShape.vertices.push(new b2Vec2(0, 0));
chainShape.vertices.push(new b2Vec2(4, 0));
//傾斜
chainShape.vertices.push(new b2Vec2(6, 1.3));
chainShape.vertices.push(new b2Vec2(6.5, 1.3));
chainShape.vertices.push(new b2Vec2(6.5, 0));
chainShape.vertices.push(new b2Vec2(8, 0));
chainShape.vertices.push(new b2Vec2(8, 4));
chainShape.vertices.push(new b2Vec2(0, 4));
chainShape.CreateLoop();
ground.CreateFixtureFromShape(chainShape, 0);
//-----★可動物体を生成★------
bd.type = b2_dynamicBody;
bd.allowSleep = false;
bd.position.Set(1.2, 1.2);
var body = world.CreateBody(bd);
//-----★長方形を生成★------
var b1 = new b2PolygonShape();
b1.SetAsBoxXYCenterAngle(0.05, 1, new b2Vec2(0, 0), 0);
//-----★可動物体を長方形として実体化★------
body.CreateFixtureFromShape(b1, 5);
//-----★モータ付き節点を生成★------
var jd = new b2RevoluteJointDef();
//-----★モータ付き節点のパラメータ設定★------
jd.motorSpeed = 5 * Math.PI;
jd.maxMotorTorque = 1e2;
jd.enableMotor = true;
//-----★モータ付き節点に可動物体を付与する★------
this.joint = jd.InitializeAndCreate(ground, body, new b2Vec2(1.2, 1.2));
//-----★★粒子系の生成★★------
var psd = new b2ParticleSystemDef();
psd.radius = 0.022;//粒子半径 def:0.025
psd.density = 1;//粒子密度
psd.dampingStrength = 0.2;//減衰率 def:0.2
psd.viscousStrength=0.3;//粘性 def:無し
var particleSystem = world.CreateParticleSystem(psd);
//-----★粒子団の生成★------
var pd = new b2ParticleGroupDef();
//-----★粒子団の形★------
var shape = new b2PolygonShape;
shape.SetAsBoxXYCenterAngle(1, 0.8, new b2Vec2(1.5, 1), 0);
pd.shape = shape;
//-----★粒子団の色★------
pd.color.Set(0, 0, 255, 255);//◆粒子の色:R・G・B・濃さ
//-----★粒子団の実体化★------
var group = particleSystem.CreateParticleGroup(pd);
//-----★タイマーの設定★------
this.time = 0;
}
//-----★パラメータの逐次変更★------
TestDamBreak.prototype.Step = function() {
world.Step(timeStep, velocityIterations, positionIterations);
this.time += 1 / 60;
this.joint.SetMotorSpeed(0.5 * Math.cos(this.time) * Math.PI);
}
保存したら、サンプルコードにあるメニュー画面から、DamBreakを立ち上げてみましょう。


棒が振り子の様に往復し、水をかき回して波が立つ様子がシミュレートされます。
往復回転する棒のコード
今回追加したのは、往復回転する棒です。以下にそのコードの解説を試みますが、LiquidFunのサンプルコードを流用したもので、細かい部分まで完全には理解ないまま修正した結果であり、一部推測を交えての解説となる旨、ご容赦ください。
可動物体を設定する
まず動く棒、つまり可動物体を設定します。その部分のコードは以下になります。
var bd = new b2BodyDef();
・・・
//-----★可動物体を生成★------
bd.type = b2_dynamicBody;
bd.allowSleep = false;
bd.position.Set(1.2, 1.2);
var body = world.CreateBody(bd);
//-----★長方形を生成★------
var b1 = new b2PolygonShape();
b1.SetAsBoxXYCenterAngle(0.05, 1, new b2Vec2(0, 0), 0);
//-----★可動物体を長方形として実体化★------
body.CreateFixtureFromShape(b1, 5);
上のコードの意味するところは以下です。可動物体が、以下の様な(回りくどい)手順で設定しているのが判ります。
①2次元物体のひな型を生成
var ひな型 = new b2BodyDef();
②ひな型のタイプを可動に設定
ひな型.type = b2_dynamicBody;
③ひな型の初期位置を設定
ひな型.position.Set(X座標, Y座標);
④ひな型から実物体を生成
var 実物体 = world.CreateBody(ひな型);
⑤実物体に形状を付与
実物体.CreateFixtureFromShape(形状※, 物体密度);
※形状は以下の手順で予め設定しておきます。
①形状を多角形として生成
var 形状 = new b2PolygonShape();
②形状を長方形として具体化
形状.SetAsBoxXYCenterAngle(横寸, 縦寸, new b2Vec2(中心X, 中心Y), 0);
モータ付き節点を設定する
次に、生成した可動物体をモータで回転させます。その部分のコードは以下になります。
//-----★モータ付き節点を生成★------
var jd = new b2RevoluteJointDef();
//-----★モータ付き節点のパラメータ設定★------
jd.motorSpeed = 5 * Math.PI※;
jd.maxMotorTorque = 1e2;
jd.enableMotor = true;
上のコードの意味するところは以下です。
①モータ付き節点のひな型を生成
var 節点 = new b2RevoluteJointDef();
②節点にモータを設定
節点.motorSpeed = 回転速度※;
節点.maxMotorTorque = 回転力;
節点.enableMotor =true;
※回転速度は、1秒当たりの角度(ラジアン)の様です。ラジアンとは、半周(180度)をπとする角度表示です。ここでは5xπとしていますが、これは、1秒当たり半回転x5倍、つまり2.5回転することを示します。
モータ付接点に物体を結び付ける
最後に、モータ付接点に物体を結び付けます。コードは以下です。
//-----★モータ付き節点に可動物体を付与する★------
this.joint = jd.InitializeAndCreate(ground, body, new b2Vec2(1.2, 1.2));
上のコードの意味するところは以下です。
①モータ付き節点に実物体を付け加えて実体化する
this.joint
=実物体.InitializeAndCreate(地面, 実物体, new b2Vec2(回転中心x、回転中心y));
節点は、2本の針を持つ時計の様なものです。針のそれぞれに物体を結びつけると、設定した角速度で、2本の針が成す相互の角度が変わります。
通常は、一方を地面(不動物)に、他方を可動物体に結び付けます。また、回転の中心の座標は、可動物体の中心座標にしておくと動きがイメージしやすいかと思います。
往復で回転する仕組み
節点が往復で回転する仕掛けは、節点のパラメータの内、回転速度をプラスにしたり、マイナスにしたりする事で対応しています。
この部分のコードは以下となります。
//-----★タイマーの設定★------
this.time = 0;
}
//-----★パラメータの逐次変更★------
TestDamBreak.prototype.Step = function() {
world.Step(timeStep, velocityIterations, positionIterations);
this.time += 1 / 60;
this.joint.SetMotorSpeed(0.5 * Math.cos(this.time) * Math.PI);
}
コードの意味する手順は以下です。
①メイン関数内でタイマーをゼロにしておく。
this.time = 0;
②関数名.prototype.Stepで、メイン関数内のパラメータを変化させる。
メイン関数名.prototype.Step= function() {
world.Step(timeStep, velocityIterations, positionIterations);
this.time += 時刻の刻み(秒);
this.joint.SetMotorSpeed(振幅x cos(time) );
}
ここではコサイン関数を使うことで、モータの回転速度が交互にプラス/マイナスに切り替わるようにし、結果として物体が往復で動いている様に見せています。
なお、Javascript版のLiquidFunでは、節点モータは流体の抵抗を感じませんので、モータの回転力はいくつであっても流体の動きは変わりません。
