見出し画像

【フリーの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では、節点モータは流体の抵抗を感じませんので、モータの回転力はいくつであっても流体の動きは変わりません。


この記事が気に入ったらサポートをしてみませんか?