2019年12月9日月曜日

poleVectorの座標を計算する

骨にIK(ikRPsolver)を設定すると、ikHandle にある PoleVector のアトリビュートが有効になり、IKハンドルを選択すると、ジョイントに輪っかと白い矢印が表示されます。
この、poleVector の方向は、ジョイントが3個以上のスケルトンでは、プリファードアングルとかで制御できるのですが、上のように2個のジョイントからなる骨では、向きを制御することが不可能のようです。



この骨も、Z軸に出てほしかったのですが、X軸の方を向いてしまっています。
法則性が分かればよいのですが、なんかバラバラなんですよねー。
スクリプトで組んでいると、同じ角度のはずなのに、1個目と2個目で向きが違っている場合があったりして困ります。

目で見て確認するというのも効率が悪いので、poleVector の座標を計算して求めるのが良いでしょう。
汎用的に使えるよう複数の骨で構成されたIKにも対応させたいので、そこもふまえてスクリプトを作ります。

global proc vector tryCalcPV(
    string $HDL )                       ///< ikHandle 名
/**************************************************************************//**
    @brief
        pole vector の位置を骨格の長さで計算する
    @return
        poleVector の座標を返す。
 ******************************************************************************/
{
    // ジョイント名の取得
    string $sj =`ikHandle -q -sj $HDL`;
    string $ee =`ikHandle -q -ee $HDL`;
    
    // 開始ジョイントの座標取得
    vector $sp =`xform -q -ws -t $sj`;
    
    
    
    //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    //
    // 骨格の長さを計算
    //------------------------------------------------------------------------------
    // 変数の初期化
    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;
        
    }
    
    
    //------------------------------------------------------------------------------
    // poleVector の座標を取得
    vector $pv =`getAttr ($HDL+".pv")`;
    
    // 計算用の要素を計算
    vector $ep = $sp + $pv;
     float $rate = $length / mag($pv);
    
    return ((1.0 - $rate) * $sp + $rate * $ep);
    
}

単に poleVector の方向を出しているのではなく、骨の長さを計算してpoleVector の方向へ加えています。
使い方としては、

{
    vector $p = tryCalcPV("ikHandle1");
    move ($p.x) ($p.y) ($p.z) "locator1";
}

のように、ikHandle 名を渡すと座標が返ってくるので、何かオブジェクトをその座標へ移動さて poleVectorConstraint をします。

ikHandle の poleVector 座標を計算するスクリプトなので ikHandle を設定していないと計算できません。
poleVectorオブジェクトがコンストレイントされていたらIKを設定している骨の長さへ正規化できることになります。

ikHandle からは poleVector constraint も調べられるので、PVオブジェクトを見つけたら一気に移動までさせても良いのかな。


0 件のコメント:

コメントを投稿