fc2ブログ

スキニング考察

とある人とメールでやり取りをしていてちょっと話題になったので、
この機会にスキニング(softimageでいうところのエンヴェロープ設定)について、
自分の思うところを書き留めておくことに。

(すごく長い上に分かりにくいかもしれません。あらかじめ謝っておきます)

●ローポリにおけるスキニング
下のような簡単なメッシュがあり、2本の骨(デフォーマー)で間接を曲げたいとする。
110710a_skinning.jpg

おそらく、一番簡単なスキン設定は、下のような感じだろう。
110710a1_skinning.jpg

で、この間接を実際に曲げてみるとこんな感じ。
110710a2_skinning.jpg
メッシュはごくローポリで、ウェイトも0%か100%かしか使っていないが、ポリゴンが少なくてカクカクしていることを除けば、だいたい満足のいく変形結果が得られると思う。
「八」の字に頂点配置した間接構造が功を奏して、見た目の体積をほぼ維持したまま、間接を曲げることが出来ている。
自分的にはこれがローポリのスキニングの基本中の基本であり、非常に汎用性に富んだ構造だと認識している。


●ポリゴン数を増やしたケース
上記はローポリのモデルを想定したケースだったが、もう少しポリゴン数を使うタイプのモデルの場合。
110710b_skinning.jpg
モデルのクオリティを上げるべく間接部に頂点を足して、モデルのカクツキ軽減を試みる。
下のように、骨aと骨bの影響範囲のちょうど中間に追加された頂点には、それぞれの骨から50%ずつのウェイトを振るのが自然に思える。
110710b1_skinning.jpg

で、この時「こうなって欲しいな」という「理想」はこんな感じ。
うーむ、非常に良いね。こうなったら最高だね!
110710b2r2_skinning.jpg

ところが現実は非情!!
110710b2g_skinning.jpg
多分これは、スキニングした事のある人のほぼ100%が陥る絶対不可避の罠だと思う。
単純に理想の変形結果と違うということもあるし、間接部が「痩せて」あるいは「えぐれて」体積が減ってしまうことによる不自然さが致命的。実際、結構多くの人がここで悩んでいるのではないだろうか。


●なぜ、そうなってしまうのか
結論から言うと、この現象の解決策は「無い」。なぜならこれが計算上の「仕様」だから。
自分が今まで使用してきたLightWave、3dsMAX、Softimageのどのソフトでも、
骨でメッシュをスキニングして動かす機能を使用すると、必ずまったく同じ現象が発生する。
このことから、上記ソフトで使用されている頂点変換アルゴリズムが共通しており、
「正しい」計算結果としてこの現象が導かれていると類推できる。
自分はプログラマーでもないし、数学もまるで知識が無いのだけど、いくつかの簡単な実験を通じて
「なぜそうなるのか」という一定の法則性を推察することが出来た。

実は理屈は意外にシンプルなので、以下に簡単に解説する。
まず、問題の追加された頂点について、「仮に」骨a、骨bそれぞれに100%ウェイト設定した場合の変形結果を想定する。以下のようになるはず。
110710ca_skinning.jpg110710cb_skinning.jpg

でそれぞれの結果を重ねると以下のようになる。
(拡大推奨)
110710cc_skinning.jpg
上図のとおり、骨a、bに50%ずつ均等にウェイト設定した結果の頂点位置は、abそれぞれに100%設定した「結果位置の中間点」に来る。これ大事!
図を見れば一目瞭然だが、この計算方法だと、abに50%ずつウェイト設定した場合の「えぐれ」や「痩せ」は「必然」であることが分かると思う。
ちなみにウェイトを50%ずつではなく、25%:75%などのように比率を変えて設定しても問題は解決しない。
なぜなら、ウェイト比率の変更は頂点の結果位置を上図の赤い線分のうち、a寄りにするか、b寄りにするかを
変更する事しか出来ないからだ。そして赤い線の上に頂点がある以上、メッシュの体積の減少はどちらにしろ避けられない。

というわけでこのような頂点配置の場合、ウェイト値をいくらいじっても問題が解決しない。
これはもうスキニング計算の仕様なのであって、その仕様を理解した上で問題を「解決」ではなく「回避」する代替策を模索するのが正解に思える。

●回避策その1
一番シンプルな回避策として、「間接部に余計な頂点を配置しない」というドシンプルな方法がある。
つまり、間接以外のパーツについてはいくらでも頂点追加してディティールアップしても良いが、
間接部が「えぐれ」たりするような位置には絶対に頂点を配置しないことによって、そもそも問題を発生させないというアプローチだ。
スキニングのアルゴリズムの理屈が分かれば、いくらウェイト調整をしても絶対に思い通りにならない頂点配置が存在することが分かると思う。
そう、世の中には「存在しないほうがいい頂点」というのが存在するのだ。そして、そういう頂点を削除しつつモデルのクオリティを保つことはある程度可能である。
特にローポリなゲーム用モデルなどにおいてはこのアプローチが非常に有効である。
このブログに晒しているモデルなども基本的にはほぼこのアプローチによる問題の回避を行っている。

●回避策その2
こちらはもう少し贅沢かつ複雑な方法での回避策となる。
その根底は、「50%にするとへこんじゃうなら、100%にすれば良いじゃない」という考えであり、
つまり、下図のように中間地点の頂点を動かすためだけに骨をもう一つ増やすというやり方だ。
110710d1_skinning.jpg
上図のように、骨bの回転に50%追随する骨cを作成して、そこに中間地点の頂点のウェイトを100%でふってしまう。
110710d2_skinning.jpg
結果、骨a,bに50%ずつウェイトを振ったときよりは良好な変形結果が得られる。
とくに強調したいのが間接外側の「痩せ」の軽減で、体積を維持しつつ綺麗に変形しているのが分かる。
肘、膝、指間接など、間接変形の結果の「痩せ」が発生しやすい部位では非常に有効なアプローチである。
ボーン数などのリソース量に余裕がある場合は、セットアップも比較的楽だし使い勝手がいい。
肩関節や尻周りなどにも活用を期待したいところだが、3次元回転を行う間接においては、
回転を正確に50%追随させることが難しく、特定の角度で不自然なフリップが発生しやすい。
これについては自分も解決できていないので、もし誰がいい解決策を知っていたらぜひこっそり教えてください。

●もっと頂点を増やした場合
さらにポリゴン数の多いモデルをスキニングするときには、難易度がさらに上がってしまう。
110710e1_skinning.jpg
仮に骨cを増やしたとしても、間接部の頂点がさらに増えると、下図のようにやはりいびつな変形になってしまう。
110710e2_skinning.jpg
拡大図
110710f1_skinning.jpg
中間地点の頂点には結局隣接する骨に50%ずつのウェイトが降られているため、そもそも最初の問題の再生産が起こってしまっている。
110710f2_skinning.jpg
無限のリソースがあるのなら上図のようにこれらの頂点にもそれぞれ100%のウェイトを振るための骨を作ってやれば良いが、はっきり言って効率悪いしきりがない。
個人的には「そんなところに頂点追加すんな!」ってことでこんな頂点は絶対追加しない。
下図のように、内側の「えぐれ」が発生するようなところの頂点そのものを削除してしまう。
110710f3_skinning.jpg

●他の回避策
映像用のハイポリモデルの場合、もっと根本的な解決法に近いアプローチもある。
3dsMAXでいうところのスキンモーフなどの、モーフと併用して間接を曲げる手法や、
ダブルクォータニオンによるスキニングなどだ。
ただ、スキンモーフはセットアップに時間と手間がかかるのと、ダブルクォータニオンも必ずしも
理想の変形結果にならないということもあり、現状ではベストの選択肢とは言えないかもしれない。

●まとめ
というわけで、考察の結果以下の様な仮説が提出できるのではないかと思っている。

ローポリでは構造上、体積が減少しない間接を構築することが可能。
ハイポリで同様の間接を作成すると、余計な頂点の存在のために体積の維持が難しくなる。
これはスキニング計算上の必然であり、いくらウェイト値を調整しても解決することは出来ない。
ボーンの追加や、モーフの併用、ダブルクォータニオンの導入など、異なるアプローチの導入が必要になる。

いろんな方法があるスキニングだが、ローポリとハイポリではこのようにアプローチが違うので、
用途に合った手法を選択すればより効率よく作業できるはず。



●最後に
ここまで読んでくれた方、どうもありがとうございます。ものすごい長いエントリーになってしまいました。
多分自己最長記録。
テキストだけだと説明するのが非常に難しいので画像を多用したのですが、分かりづらさは軽減されていないような気も…。

なお、このエントリーはあくまでJNYが経験上導き出した個人的な見解に過ぎません。
勘違いや見落とし、思い込みなどが混ざっている可能性が多分にあります。
ご指摘、補足、反論、感想などありましたらぜひコメントいただければと思います。
スポンサーサイト



コメントの投稿

非公開コメント

とても勉強になりました

大変興味深く拝見させて頂きました。
そしてツイートでこの記事について発言しました。

私はウエイト値を100%に振ってめり込ませるということをしていました。
でも、ここまで深く考えたことがなかったのでとても勉強になりました。

こちらからなにも意見など出せずもうしわけありませんが
丁寧な図解等ありがとうございました。

No title

Maximaさん、コメントありがとうございます。
多少なりともお役に立ったのであれば幸いです。

自分もどちらかというと100%で振ることが多いです。
少ないポリゴン数で作ることが多いのもありますが、
2~3万とか比較的ポリゴンを贅沢に使うモデルでも部分によっては良く使います。
まあ、実際には100%は大雑把過ぎるので90%:10%とか95%:5%みたいなのも織り交ぜますが。

承認待ちコメント

このコメントは管理者の承認待ちです
プロフィール

JNY

Author:JNY
某ゲーム会社勤務
趣味と修行をかねて個人製作中
Softimage & Unity

個人Twitter:
   @JNY_MTMR
ゲーム広報Twitter: 
   @polygonomicon

最新記事
最新コメント
月別アーカイブ
カテゴリ
カウンター
twitter

Twitter Updates

    follow me on Twitter
    リンク