2020年11月19日木曜日

jointOrientの値を計測する

  jointOrient は、Orient Joint ツールで設定できるとはいえ、全てのジョイントがワールド軸に沿って配置されているわけではありません。
  そんな場合、orientJoint の値を決めるのは、なかなか面倒な作業になります。

  MELで計算するのは大変なので、代替案的な値の取得方法なんかを紹介しようと思います。


  まず、問題になる現象を確認します。

  HumanIk ツールなんかでスケルトンを作り、Orient Joint を実行します。


  とりあえず "LeftHandIndex1" の階層を複製(Ctrl+D)して、階層を解除します。
  そして、複製したジョイント "LeftHandIndex5(?)" の Joint Orientを確認してみます。

複製元:LeftHandIndex1

複製:LeftHandIndex5

  階層化を解除することで、Joint Orient の値が変わっています。
  これは、親のジョイントが無くなったため Joint Orient に、親の回転分が加わった感じになっています。

  これを回避するには、トランスフォームノードを作成し、複製したジョイントの元の親ジョイントのワールド回転をセットしてから、複製したジョイントを回転させたトランスフォームノードへ階層化します。

  以上のことをスクリプトで書くと、こんな感じでしょうか。

{
    string $self ="LeftHandIndex1";
    string $parent = firstParentOf($self);
    
    vector $p =`xform -q -ws -t $self`;
    vector $r =`xform -q -ws -ro $parent`;
    
    string $dp[]=`duplicate $self`;
    
    string $grp =`group -em`;
    move ($p.x) ($p.y) ($p.z) $grp;
    rotate ($r.x) ($r.y) ($r.z) $grp;
    
    parent $dp[0] $grp;
    
}

  このスクリプトを実行すると、下のような階層構造になり、複製したジョイント LeftHandIndex5 の Joint Orient は、複製元 LeftHandIndex1 と同じ値になっているはずです。


  このことから、Joint Orient を正しく計測するためには、親のワールド回転値を持ったノードが必要だということが分かります。

  そして、Orient Joint ツールの Primary Axis や Secondary Axis を再現するために、Aim Object、Aim Target、Aim Vector を Locator で作成し、Aim Constraint を掛けて(主にAim Vectorを)操作します。


{
	// ジョイントの名称取得
    string $self ="LeftHandIndex1";
    string $parent = firstParentOf($self);
    string $childs[]=`listRelatives -c -typ "joint" $self`;
    
    // 座標
    vector $p0 =`xform -q -ws -t $self`;
    vector $p1 =`xform -q -ws -t $childs[0]`;
    vector $ro =`xform -q -ws -ro $parent`;
    
    //------------------------------------------------------------------------------
    // ノード作成
    string $axis =`group -em -name "axis"`;
    string $lct0[] =`spaceLocator -name "aimObject"`;
    string $lct1[] =`spaceLocator -name "aimTarget"`;
    string $lct2[] =`spaceLocator -name "aimVector"`;
    
    // 階層化
    parent $lct0[0] $axis;
    parent $lct1[0] $axis;
    parent $lct2[0] $axis;
    
    // 移動
    move ($p0.x) ($p0.y) ($p0.z) $axis;
    rotate ($ro.x) ($ro.y) ($ro.z) $axis;
    
    move ($p1.x) ($p1.y) ($p1.z) $lct1[0];
    
    //------------------------------------------------------------------------------
    // コンストレイント
    aimConstraint -aim 1 0 0 -u 0 0 1 -wut "object" -wuo $lct2[0] $lct1[0] $lct0[0];
    
}

  これは、こんな感じのスカートや髪の毛みたいな、軸に沿っていないようなものに特に有効です。


  希望の軸の角度になったかなと思ったところで、下のスクリプトを実行。

{
    float $ro[]=`getAttr "aimObject.r"`;
    setAttr ($joint+".jo") $ro[0] $ro[1] $ro[2];
    
}
  

  こんな感じで、aimObjectノードの回転値を編集したいジョイントの jointOrient へセットします。

  ただ、子階層がある場合、いったん子ジョイントの階層化を解除してから Joint Orientを編集しないと子階層が変な方向を向いてしまうので、面倒ではあります。

  階層構造に対応できるようツール化するのも手ですかね。



0 件のコメント:

コメントを投稿