Vala プログラミング

WebGPU プログラミング

おなが@京都先端科学大

Babylon.js WebGPU Cloth Simulation (3)

前々回アップした、XPBD(extended position-based dynamics) による Cloth シミュレーションの解説です。今回はマウス操作について説明しています。

実行結果

cloth の上でマウスをクリックしドラッグすると、cloth が引っ張られた状態になります。

1 mouse down
 mesh 上をマウスでクリックして、クリックされた mesh の index や位置情報を取得する。mesh 情報の取得には、Babylon.js の raycast 機能を使用する。

 Scene の onPointerDown property は、scene 上をマウスでクリックすると、
IPointerEvent, PickingInfo, PointerEventTypes パラメータを持つコールバックを
起す。

   scene.onPointerDown = function (event, pickInfo){
       //console.log(“mouseDown pickInfo", pickInfo.hit);
            
      if (pickInfo.hit == true) {
         //console.log(“mouseDown pickInfo id", pickInfo.pickedMesh.id);
         //console.log(“mouseDown pickInfo faceId", pickInfo.faceId);
         gGrabber.start(pickInfo);
         camera.detachControl(canvas);
      }
   }

event が IPointerEvent に、pickInfo が PickingInfo に相当する。PointerEventTypes は使用していない。マウスクリックが起こると、function 内の処理が実行される。

 mesh の情報は、pickInfo から得られる。マウスをクリックすると、クリック位置から画面に垂直奥方向に ray が発せられる。そこに mesh があれば、pickInfo.hit が true になる。true の場合は、
 pickInfo.pickedMesh: ray が当たった mesh data
 pickInfo.faceId: ray が当たった mesh の face(triangle)番号
 pickInfo.pickedPoint: mesh 上で ray が当たった位置
などが得られる。
ray の情報も得られる。
 pickInfo.ray.origin:クリックした mouse の位置
 pickInfo.ray.direction:ray の方向ベクトル
ray の情報は、mesh が無い場合でも得られる。

 mouse down をしたとき、以下の処理を行う。

  1. クリックした位置(下図の {\bf{p}}_1)に対応する mesh 上の位置(下図の {\bf{p}})と、mesh index を取得し、その mesh point の position に設定する。
  2. mouse drag 中に mesh が移動しないように、カメラコントロールをオフにする。
  camera.detachControl(canvas)


 mesh の vertex point の position 設定は、以下のように行なっている。
・mesh 上の位置の取得

 {\bf{p}}_1 の座標(マウスポインターの座標)は ray.origin、
 {\bf{p}} の座標(対応する mesh 上の座標)は pickInfo.pickedPoint、
から得られる。 O はウィンドウの原点である。

・mesh index の取得
 mesh の拡大図

 {\bf{p}} のある triangle の face 番号は、pickInfo.faceId から得られる。
 {\bf{p}} と triangle の座標  {\bf{x}_1} ,  {\bf{x}_2} ,  {\bf{x}_3} との距離が最小となる index を見つけ、それを grabId とする。
これを行なっている部分が、Grabber.start(pickInfo) である。

 次に、 {\bf{p}} を uniform data、grabId を grabIdBuffer data として compute shader startGrab に送り、ここで grabId の point の invMass を 0(重力の影響を受けない)、position を  {\bf{p}} に設定する。
これを行なっている部分が、this.physicsObject.startGrab(pos) である。
this.physicsObject には、Cloth が設定されている。

2 mouse move
 mouse move した時の処理は、scene.onPointerMove で行う。
この場合は、pickInfo.hit は常に false の状態である。移動後の mesh point の座標は、ray 情報から得る。

mouse move した様子

drag したマウスポインターの座標 は、pickInfo.ray.origin から得られる。
マウスポインターの移動に対応した mesh point の座標  {\bf{p}} は、以下のようにする。
 {\bf{p}} = {\bf{p}}_1 + {\bf{d}}
 {\bf{d}} = pickInfo.ray.direction x distance
distance : mouse down 時の マウスポインターと mesh との距離(this.distance = pickInfo.distance)
これを行なっている部分が、Grabber.move(pickInfo) である。

次に、移動後の mesh point の座標  {\bf{p}} を、uniform data として compute shader moveGrabbed に送り、grabId の point の position を  {\bf{p}} に設定する。
これを行なっている部分が、Cloth.moveGrabbed(pos, vel) である。(vel は使用していない。)

また、Grabber.move(pickInfo)では、mesh point の速度(this.vel)の計算も行なっている。

3 mouse up
 drag を終了し mouse up を行うと、以下の処理をする。(scene.onPointerUP)

1 compute shader で、grab された mesh point の vel、invMass を設定する。      (this.physicsObject.endGrab(this,prevPos, this.vel) の部分)
 mouse move で計算した mesh point の速度 vel(this.vel) を uniform data として
 compute shader endGrab に送り、grabId の point の velocity を vel に設定
 する。
 また、grabId の point の invMass (0 に設定されている) を元の
 invMass (grabInvMass) に戻す。
 その後、grabId を初期値(-1)に戻す。
2 this,physicsObject を null にする。
3 カメラコントロールをオン(camera.attachControl true)にする。