以前投稿した、「Maya CardStick」の解説を書いてみようと思います。
ムービーでは、Deformしているオブジェクトにも対応しているのですが、
話しが長くなるので、とりあえずは、Deformなしバージョンの解説から。
まず、カードと言うか飛んでる板状のものはParticle Instancerで作成してます。
Particleは飛んでいってコリジョンした後、
コリジョンしたオブジェクトにくっつくわけですが、
まずは、
「コリジョンしたオブジェクトにくっつく」(変形しないオブジェクト篇)
と言う事をどうやってるか、からお話しようと思います。
■コリジョンの情報について
どうやったか、の前に
ParticleのAttributeにはコリジョンした際の情報が入るものがいくつかあり、
collisionWorldPosition:コリジョンしたWorld位置
collisionGeometryIndex:コリジョンオブジェクトごとに割り振られたID
collisionComponentId:衝突したFace番号
collideFaceU:衝突した位置のU座標
collideFaceV:衝突したした位置のV座標
等、情報が取得できます。
これらは、すべてParticleの粒毎のPer Particle Attributeで、
例えば、衝突したかどうかだけ知りたい場合は、
collisionGeometryIndex
を見ると、
衝突時に、0以上の値が入り、それ以外のフレームでは -1 が入るので、判定が可能です。
で、本題ですが、
「衝突したオブジェクトにくっ付ける」 と言うのを言い換えて
↓
「一粒一粒を、衝突した時にコリジョンしたオブジェクトの子供にする(親子付けする)」
(衝突後はダイナミクス無視で) 方法でやりました。
そんな事ができるのか?
いや、標準にはそんな機能はないので・・・
親子付けを自分で計算します・・・
では、親子付けをどうするか、ですが、
衝突した時のParticleの位置は、
その時の、collisionWorldPositionに入っているので分かります、
そのcollisionWorldPositionに
衝突したオブジェクトのInvert Matrixを掛け算します。
衝突したオブジェクトを仮にcube1として、仮のExpressionを書くと、
float $im[] =`getAttr cube1.worldInverseMatrix`; // cube1のInverse Matrixを取得 vector $p = collisionWorldPosition; // collisionした時のParticleのWorld位置取得 vector $newP = multMat( $p, $m ); // $pにmatrix $imを掛け算するとどうなるかと言うと、
Particleの粒を衝突したオブジェクトの子供にして、
衝突したオブジェクトのTranslate, Rotateはすべて0で、Scaleは1の状態
にもって行ったのと同じ状態が作れます。
左側が実際にcube1に赤いParticleが衝突した瞬間のフレームで、 左上のTranslate,Rotate,Scaleがその時のcube1の状態です。
右側が、左のcube1とParticleにcube1のworldInverseMatrix を掛け算した状態で、
cube1とParticleの相対的な位置関係が変わってないことがなんとなく分かると思います。
cube1は右の状態に今度はworldMatrixを掛けると左の状態に行けます。Particleも同様に右の状態にcube1のworldMatrixを掛けると左の状態に持っていけます。
で、
上記で計算したParticleの位置情報をCollision発生時に計算して保持しておきます。
衝突後のフレームでは、衝突したオブジェクトcube1のworldMatrixを
先ほど保存した位置情報に掛け算します。
すると、
実質Particleを衝突したオブジェクトの子供に出来る。
つまり、くっつけることができた。
と言う流れにすることができるのです。
解説が難しいですなぁ・・・
次回は、
実際のExpressionの説明を書いてみようかと。
カードの向きと、Deformしているオブジェクトにくっ付ける方法は
次の次の、またいつかで。