個人的に、この計算によって出た座標へ poleVector を移動させることを「normalize(正規化)」って言っています。
正しいのかは知りませんが。
まず、ジョイント階層に Rotate-Plane Solver を設定して ikHandle と、PVコンストレイントをかけたロケータを、適当な位置へ移動させておきます。
これに前回のスクリプトを実行すると、こんな感じになります。
このPVの位置では、ikHandle が簡単に poleVector の線を越えてしまえて、フリップしてしまいます。
なので、PVの移動先はIKのスタートジョイントを中心にIKベクトルを90度回転させた位置へ移動させた方がアニメーションを作るときには都合が良いです。
こんな感じのスクリプト。
global proc vector tryMovePV( string $HDL, ///< ikHandle 名 string $axis ) ///< 回転させる軸 /**************************************************************************//** @brief pole vector の位置を正規化する @return poleVector の座標を返す。 ******************************************************************************/ { // ジョイント名の取得 string $sj =`ikHandle -q -sj $HDL`; string $ee =`ikHandle -q -ee $HDL`; // 開始ジョイントの座標取得 float $m[] =`xform -q -ws -m $sj`; vector $sp =<<$m[12], $m[13], $m[14]>>; vector $ep =`xform -q -ws -t $ee`; //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ // // 骨格の長さを計算 //------------------------------------------------------------------------------ // 変数の初期化 float $length = 0.0; string $self = $ee; // 階層分ループ while( true ) { // 親のジョイント名 string $parent = firstParentOf($self); // 自分の座標と親の座標を取得 vector $p0 =`xform -q -ws -t $self`; vector $p1 =`xform -q -ws -t $parent`; // 骨の長さを計算 $length += mag($p1 - $p0); // 終了判定 if(`plugNodeStripped $sj`==`plugNodeStripped $parent`) break; // 切り替え $self = $parent; } //------------------------------------------------------------------------------ // まず、ハンドルベクトルの延長線上のpv座標を計算 float $rate =($length / mag($ep - $sp)); vector $lenPos =((1.0 - $rate) * $sp) + ($rate * $ep); // 回転軸 $axis = tolower($axis); vector $rShaft; switch( $axis ) { case "x": $rShaft = <<$m[0], $m[1], $m[2]>> ; break; case "y": $rShaft = <<$m[4], $m[5], $m[6]>> ; break; case "z": $rShaft = <<$m[8], $m[9], $m[10]>>; break; } // $sp を中心に $rShaft で $lenPos を -90度回転させた座標を計算 float $PI = 3.141592654; vector $mov =`rot ($lenPos-$sp) $rShaft (-($PI/2))`; $mov += $sp; return $mov; }
前回作ったスクリプトに、けっこう似ていますが、終わりの部分が少し複雑になっています。
これをこんな感じで使います。
{ vector $p = tryMovePV("ikHandle1","x"); move ($p.x) ($p.y) ($p.z) "locator1"; }
引数の"x"は、このジョイントの Local Rotation Axis がこんな風になっているのためです。
ここは、作ったジョイントによって変わると思います。
実行すると poleVector は、こんな位置へ移動します。
これなら上と同じ位置へ ikHandle を移動させても、フリップはしません。
骨格の長さを計算する部分は結構使いまわせそうなので、リファクタリングしても良いかもしれないですね。
これをリグのサポート機能としてピッカーに追加しておくと、アニメータには結構喜ばれます。
リガーの仕事かは抜きにして・・・。
0 件のコメント:
コメントを投稿