Particleがオブジェクトに衝突して、 衝突したオブジェクトにくっつく件です。
大雑把な流れとしては、
if( コリジョンした時 ) { // cube1のInverse Matrixを取得 float $invm[] =`getAttr cube1.worldInverseMatrix`; // collisionした時のParticleの位置取得 vector $p = position; // $pにmatrix $invmを掛け算 vector $newP = multMat( $p, $invm ); // この時の値を保存 collisionPosPP = $newP; } else if( コリジョンした以降のフレームでは ) { // cube1のMatrixを取得 float $m[] =`getAttr cube1.worldMatrix`; // 保存した値を取り出し vector $p = collisionPosPP; // $pにmatrix $mを掛け算 vector $newP = multMat( $p, $m ); // 値を入れる position = $newP; }と言う感じでしょうか。 めんどくさくなって来たので、とりあえずコードを載せます。
以下はRuntime after dynamicsのExpressionです。
// コリジョンした場合に0から始まる数字が入ります。 // コリジョンしていない時は-1が入ります。 int $gid = particleShape1.collisionGeometryIndex; // コリジョンした時 if( $gid!=-1 ) { // get collision shape string $geo = getCollisionShape($gid); // get inverse Matrix of collision shape float $m[] = `getAttr ($geo+".worldInverseMatrix")`; // multiply $p * $m vector $p = particleShape1.position; $p = multMat( $p, $m ); // set attribute particleShape1.collideGeoId = $gid; particleShape1.collisionPosPP = $p; particleShape1.traceDepthPP = 0; } // コリジョンした以降のフレーム else if( particleShape1.collideGeoId!=-1 ) { // get collision shape $gid = particleShape1.collideGeoId; $geo = getCollisionShape($gid); // get Matrix of collision shape float $m[] = `getAttr ($geo+".worldMatrix")`; // multiply $p * $m vector $p = particleShape1.collisionPosPP; $p = multMat( $p, $m ); particleShape1.position = $p; }float型のPar Particle Attribute「collideGeoId」と
vector型のPar Particle Attribute「collisionPosPP」を追加しておいてください。
まず、 最初のif文、コリジョンしたかどうかは
collisionGeometryIndex
と言うAttributeを見ると、-1ではない値が入るので分かります。次に9行目
getCollisionShape();
と言う関数でコリジョンしたShape名を取得するようにしています。これは、コリジョンしたオブジェクトのshape名を取得する関数で、 以下を作成しました。
この関数定義も Runtime after Expressionの最初の方にでも書いておきましょう。
proc string getCollisionShape( int $gid ) { string $gshape; string $aGeoConnect[] = `listConnections particleShape1.collisionGeometry`; string $aGeo[] = `listConnections -s 1 -d 0 -p 1 ($aGeoConnect[$gid]+".localGeometry")`; string $aAttr[] = stringToStringArray($aGeo[0], "."); $gshape = $aAttr[0]; return $gshape; }何をやっているのかと言うと、
Particleにコリジョンするオブジェクトは「Make Collide」でコリジョン設定していると思いますが、
その際、 オブジェクトのShapeは、Particleのアトリビュート「collisionGeometry」にコネクションされます。
そして、 「collisionGeometryIndex」で得られる番号が 「collisionGeometry」に接続されている配列番号に対応しており、
実際には、「particle <- geoConnector <- mesh 」と言うノード構成で接続されているので、
それをたどってShape名を取得するようにしています。
次に、16行目の以下の関数ですが、
$p = multMat( $p, $m );
これは、 引数vector型$pにmatrix配列$mを掛け算してvector値を返す関数で、
melコマンドとして以下があるのですが、
やけに処理が遅い上に、結果が変でした・・・
float[] pointMatrixMult ( float $point[], float $matrix[] )
なので、melで組んでます。
この関数も Runtime after Expressionの最初にでも書いておきましょう。
proc vector multMat( vector $p, float $mat[] ) { float $fp[4] = {$p.x,$p.y,$p.z,1}; float $result[4]; for( $i=0; $i<4; $i++ ){ $result[$i] = 0.0; for( $j=0; $j<4; $j++ ){ $result[$i] += $fp[$j] * $mat[$i+$j*4]; } } return <<$result[0],$result[1],$result[2]>>; }そんで、
collideGeoIdにcollisionGeometryIndex, collisionPosPPにinverseしたpositionを保存し、
21行目で
traceDepthPP = 0;
これは、コリジョン精度になりますが、0にする事でそれ以降コリジョンしなくなります。
で、これをやっておかないと、「collisionGeometryIndex」が常に-1以外になってしまい、
いつでもコリジョンしている状態になるので、これをやります。
コリジョン以降の処理については、
なんとなく分かるかと思うので説明は省略します。
最後に、
コリジョンオブジェクトについている、「geoConnector」ノードの
「Friction」は1にしておいてください。
1以下だと、Particleがコリジョン時に一瞬滑ります。
何でしょうかねぇ・・・
コリジョン時にExpressionの計算が聞いてない感じで・・・
では次回は変形しているオブジェクトへの対応についてか、
Rolling Ballについてか、その辺を書こうかなと。
0 件のコメント:
コメントを投稿