2019年12月16日月曜日

poleVectorの座標を正規化する

前回、ikHandle から poleVectorの座標を計算するプロシージャを作成しましたが、アニメーションを作成しているときに実行すると、あまり好ましい座標にならないため、アニメーション作成時には、また違った計算をしないといけません。
個人的に、この計算によって出た座標へ 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 件のコメント:

コメントを投稿