2011年02月24日

武器リグの作成

110223b.jpg

 武器を持たせるためのリグを試行錯誤してみた。

 片手剣みたいなのは、武器を手のボーンの子にしてしまえばそれで済むのだけれど、問題は両手で扱うような武器の場合。
 腕を武器に固定するために片手のみ、もしくは両手共に武器の子にする必要が出てくるのだけれど、もともとのリグの場合、腕全体の動きは手首までのIKゴールで制御して、手自体は腕の子になっている状態なので、IKゴールを動かすコントローラを武器の子にしても固定されるのはIKゴールの位置だけで、手を武器に固定することが出来なかった。
110223c.jpg
 もともとのはこんな感じ。


 手を武器に固定するためにはまず、手が腕の子のままでは出来ないので、腕との親子付けを解除することにしたのだけれど、手のボーンは腕のIKの終端になっているので、元々の手のボーンはそのままIKの終端用にとっておいて、新しくボーンを作成して手のボーンにすることにした。
 で、基本的には付属のチュートリアルのパクリなのだけれど、まず腕のIKの終端のボーンに新しく作った手ボーンを位置合わせして、終端のボーンに位置コンストレイントをかける。これで、位置は腕に合わせて動くようになる。

 次に、武器を持たないときは腕の子のような動作をして欲しいので、前腕のボーンに方向コンストレイントをかける。これによって、手と前腕を親子付けしたのと同じ動作をするようになる。

 武器を持っている時は、腕に従わず武器と同じ回転をする必要があるので、武器に方向コンストレイントをかけたいのだけれど、武器モデルに直接繋いでしまうと使いまわしが聞かないので、武器用にダミーを作成して、これに方向コンストレイントをかけておく。逆の手も同じ武器ダミーにコンストレイントをかける。
 方向コンストレイントを1つではなく、前腕と武器で分けたのは"オフセット初期値を保持"をそれぞれに使いたかったからなのだけれど、他にいい方法があるような気がしないでもない。

 これだけでは、腕に従うか武器に従うかしか出来ないので、オイラーXYZを入れてFKでも動かせるようにしておく。
110223i.jpg

 最後に、腕のコントローラに0〜100のアトリビュートを追加して、実数スクリプトで2つの方向コンストレイントの重みと繋いで、0のときは片方が100でもう片方が0、100のときは片方が0でもう片方が100になるように設定する。このアトリビュートの値を変えることで、腕の子として動く状態と、武器と同じ動きをする状態を切り替えられるようにする。
110223e.jpg
 ただ、実際動かしてみたら、アトリビュートが0か100の時は良いのだけれど、間の中途半端な状態の時にどうも変な動きをしてしまう。出来れば、緩やかに切り替えが出来るようにしたかったのだけれど、解決策が思いつかないのでとりあえず保留。

110223d.jpg
           最終的にこんな感じ。

110223h.jpg
 実際に持たせる際は、まず武器モデルを読み込んで武器ダミーの子にする。
 そして、腕のコントローラを武器を握る位置まで動かして、アトリビュートを武器用に切り替える。切り替えると手の回転方向がおかしくなるので、FKで修正して正しく握れるようにする。で、腕のコントローラを武器ダミーにリンクコンストレイントで親子付けすれば、手がしっかり武器に固定された状態にできる。
 後は、IKゴールが離れないように武器ダミーにモーションを付けて、腕のコントローラは肘の方向にのみ意識してキーを打てば、武器を持ったモーションが作れる。

 ただ作った後で気づいたけれど、このリグの場合両手共に武器の子にするような方法なので、片方の腕が親で武器ともう片方の腕が子になるようにしたい場合、そのまま使うことができない。とりあえず今回は必要ないのでその辺は保留。



 それから前腕のツイストボーンに関して、もともとは手のボーンのオイラーXYZに実数スクリプトで繋いでいたのだけれど、今回手のボーンに方向コンストレイントが入ったため、以前と同じようにオイラーXYZに繋いだのでは方向コンストでの回転が考慮されず、正しく動かせなくなってしまった。
 で、元々手を親子付けしないリグの元ネタはチュートリアルなので、チュートリアルの読み飛ばしていた項目を読んでみたところ、解決策が書かれていた。詳細はチュートリアルの手首のツイストボーンの項目に書かれているのだけれど、どうやら行列を使うらしい。
 行列がなんなのかはいまいち理解できていないのだけれど、どうもワールド座標で移動や回転値を取り出せて、親の行列の逆値を掛け合わせることでローカル座標も出せるようで、オイラーXYZと方向コンストの2つのコントローラが入っていようが、FKだろうがIKだろうが値を参照できるっぽい、、、、ほとんど理解できていないと思う。
 とりあえずチュートリアルに書かれているスクリプトから必要なとこをコピペして、組んでみたのが↓。
------------------------------------------------------------
matParent = inverse Parent.transform ;
matTarget = Target.transform ;
matResult = matTarget * matParent ;
rotQuat = matResult.rotation ;
rotEuler = quatToEuler rotQuat order:3;
twist = rotEuler.z ;
twist = degToRad twist ;
------------------------------------------------------------
 これをツイストボーンのX回転に実数スクリプトで入れてある。
 今回は手のボーンのX回転を取り出したいので、"Parent"は手の親に当たる前腕ボーンにノードの割り当てで割り当てた変数で、"Target"は値を取り出したい手のボーンに割り当てた変数。
 で、最終的にdegtorad twist で、手のボーンのX回転がでるようになっている。

 汎用的にして恐らくこんな感じだろうっていう解説を入れると、
---------------------------------------------------------------------------------
matParent = inverse 親ノードを割り当てた変数.transform ;
matTarget = 値を取り出したいノードを割り当てた変数.transform ;
matResult = matTarget * matParent ;
rotQuat = matResult.rotation ;
rotEuler = quatToEuler rotQuat order:3;
twist = rotEuler.z ;
twist = degToRad twist ;
---------------------------------------------------------------------------------
1行目. 値を参照したいノードの親ノードの変換の逆値を取り出して変数matParentに格納。
2行目. 値を参照したいノードの変換を取り出して変数matTargetに格納。
3行目. 2つを掛け合わしてローカル変換を出す。
4行目. 行列値から回転値を取り出す。
5行目. YZX の順序で回転を評価する(1はXYZ、2はXZY、3はYZX、4はYXZ、5はZXY、6はZYX)
6行目. YZXの順序中、Xにあたるzの値を取得。
7行目. 度数をラジアンに変換。

5行目6行目は、取り出したい値の軸によって変える必要がある。
5行目の評価の順序がいまいち良く解らないのだけれど、実際に試したかぎりでは、X回転の場合はYZX順の、
 rotEuler = quatToEuler rotQuat order:3;
 twist = rotEuler.z ;
Y回転、Z回転の場合はXYZ順の
 rotEuler = quatToEuler rotQuat order:1;
 twist = rotEuler.z ;(Y回転の場合はrotEuler.y)
で評価したらまともに動いた。

 今から組みなおすのは面倒なので今回は放置するつもりだけれど、この行列を使ったスクリプトならIKで動くボーンからも値を取り出せるため、現在組んであるエクスポーズtmを使っている方法は間違いだと解った。次組むときはこの方法を使おう。

タグ:3DCG
posted by 縦横 at 01:33| Comment(4) | 女剣士 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
いつも更新楽しみにしています。
動画制作がんばって下さい。
Posted by 13番 at 2011年02月24日 04:49
ありがとうございます
がんばります
Posted by うぃるそん(縦横 at 2011年02月25日 01:42
大丈夫ですか?被災されてませんか、心配です。
Posted by wm at 2011年03月29日 20:17
すみません。更新が滞ってしまいました。
ご心配ありがとうございます。
私は関東の内陸住みなので、最初の揺れは大きかったものの特に被害はありませんでした。

近いうち更新を再開します。
Posted by 縦横 at 2011年03月29日 22:04
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。