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 件のコメント:
コメントを投稿