LightWaveで二次元キャラ系人物モデリング奮闘記 ―視線コントロール編―

最終更新:2017/01/13

視線コントロールには、一般には目の中心軸の延長線上に視線用ターゲット・オブジェクトを配置し、両目からそれを参照させてIKを用いて視線をコントロールする。IKを使いたい場合は目を球状のオブジェクトとしてモデリングする必要があり、扁平な顔が基本の二次元イラストやアニメ調の作風にはなかなか合わせにくい傾向がある。劇画調を目指している場合を除き、IKを使いたいがために眼球がちゃんとはまるようにするには、顔のモデリングに必要な工夫の労力が釣り合わないことが多い。

そこで、瞳の動きにはモーフを使いながら、擬似的にIKのような視線コントロールを実現する方法を考える。

瞳の後退モーフによるカメラ目線

カメラ目線を実現するには、MMDなどでよく使われている方法を使う。MMD方式のカメラ目線は簡単に言うと、目の位置を後退させて、三次元的に瞳の中心をずらすことによって擬似的にカメラ目線になっているように見せる。

これまでは白目を自己発光させて陰影が出ないように設定していたけど、まぶたに白目が透けてしまったりする問題があったため、自己発光度を0%に変更し、拡散レベルを400%という非常に大きい値にすることで陰影を極力落とす。

morph031

目を後退させると、眼窩の内側が見えてしまうので、内側を白に染めて目の後退がわかりにくいような仕組みを作る。内側を自己発光度の設定してある白に染めてしまうと、目を閉じても内側が透けて見えてしまう。上のサーフェース設定はその対策でもある。

morph032

逆に、瞳の中心は目を後退させることでライトの光線が届かなくなり、徐々に暗くなっていってしまうので、自己発光度を「40%」に設定する。拡散レベルは「60%」に設定し、自己発光度と拡散レベルの合計が100%になるように設定すると、自己発光度を設定していなかった場合と色合いがあまり変わらないようにできる。

morph033 morph034

目の後退によるカメラ目線の例が次の画像。白目と眼窩の内側の境界がわからないようにunReal Xtreme2のToon Tracerピクセルフィルター・プラグインの設定を変更しておく。

morph035

上の画像だけではカメラ目線になっているかどうかが少しわかりにくいので、俯瞰構図と仰視構図も示しておく。いずれもモーフ量は同じで、瞳の位置を後ろに下げただけ。カメラの位置を上下に動かしても瞳はカメラの方を向いているように見える。

morph041
俯瞰
morph042
仰視

エクスプレッションによる視線コントロール

眼を独立した球状オブジェクトとして作成しなかったので、視線の制御にIKを使えない。二次元キャラクターの目を球体として作成しようとする場合に発生しうる問題は以前にも述べたとおりで、瞳は水平、垂直の二軸のみで動くようにデザインしている。

モーフを使っている場合でも、グラフ編集に用意されていている「Channel Follower」モディファイヤを使用すれば、ターゲット・オブジェクトの特定のチャンネルの値の変動にモーフを連動させる簡易的な視線コントロールはできる。ただ、ターゲットの距離などを考慮して左右のモーフ量を個別に制御できないので、両目をひとつのターゲットで制御するのは容易くない。

morph030

ただし、Channel Followerをモーフのグラフ(エンベロープ)に適用する場合に限り、X、Y、Zの座標系チャンネルだけにしか追随させられない。H、P、Bの回転系チャンネルに追随させようとしても不可解な値が返されてしまい(特定のチャンネルだけまともな数値が出ることもあるけど、ほとんどの場合、0に限りなく近い極小の値になる)、サインカーブのような動きをさせることはできない。モーフは線形補間なので、ある意味当たり前と言えば当たり前なんだけど、Channel Followerで連動する要素に回転系のチャンネルを指定してもエラーも警告も出ないので、設定か計算の間違いだと勘違いしやすい。

そうかと言って、どこか一点を注視するような視線をモーフのスライダーだけで実現するのは楽ではない。アニメーションさせることを考えに入れたりすると、キーフレームごとにモーフ量を計算するか、その都度目分量で調整しなければならず、かなり労力がかかりそうなことは想像に難くない。

そこで、注視している場所を大雑把に指示するターゲット・オブジェクトを用意して、モーフ適用量を計算させる。視線コントロールの基本的な考え方は次の図のとおり。IKでも考え方そのものは同じ。

morph040

この図から、目の正面方向と注視点に対する方向がなす角度\thetaについてのタンジェントは次のとおりに求められる。

     \begin{align*} \tan \theta&=\frac{X_{sight} - X_{eye}}{Z_{sight} - Z_{eye}} \end{align*}

タンジェントの逆関数インバース・タンジェント(又はアークタンジェント)を用いて\thetaを求める。

     \begin{align*} \theta &= \tan^{-1} \frac{X_{sight} - X_{eye}}{Z_{sight} - Z_{eye}} \end{align*}

これをLightWaveで受け付けられるエクスプレッションに置き換える。プログラミング言語ではインバース・タンジェント(アークタンジェント)を「atan」などと記述することが多い。次の式は左目のエクスプレッションの例。名称は左右の区別がつきやすく、わかりやすければなんでもいい。

式の出力はラジアンではなく、関数電卓などで「DEG」と表される円周360°の角度なので、0^\circ \leq \theta \leq 90^\circの範囲の値をとる。必要であれば、これに定数を掛けて調整する。

atan(([Null_EyeSight.Position.X] - [Null_Eye_L.Position.X]) / ([Null_Eye_L.Position.Z] - [Null_EyeSight.Position.Z]))

エクスプレッションと、グラフで表されるチャンネルはそれぞれ独立していて、一義に定まる名称で識別されるエクスプレッションを複数のチャンネルに割り当てられるようになっている。そのため、最初は左目用のエクスプレッションを右目のチャンネルにも割り当ててしまったり、重複したエクスプレッションの除去に手間取ったり、インターフェースにとっつきにくさを感じるかもしれない。

同じく次の式は右目のエクスプレッションの例。右目のX座標は左目の正負反転なので、参照するチャンネルが異なるだけで式はほぼ同じ。両目とも瞳を顔の外側に動かすほうをモーフ量のプラスにしている場合は、全体をマイナスで正負を反転する。

atan(([Null_EyeSight.Position.X] - [Null_Eye_R.Position.X]) / ([Null_Eye_R.Position.Z] - [Null_EyeSight.Position.Z]))

それぞれの目のモーフにエクスプレッションを適用(アタッチ)し、両目のグラフを同時に表示させると次の画像のようになる。注視ターゲット・オブジェクトは-1m \leq X_{sight} \leq 1mの範囲で行ったり来たりさせているだけ。Z軸座標は目から約1m先に固定で、注視距離によって必要があれば移動させる。Z_{sight}を移動させるとグラフの振幅が変動する。

morph036

ターゲット・オブジェクトを注視させた場合と、スライダーで視線を手動設定した場合の比較。ターゲット・オブジェクトとは言うものの、上の式では精密に注視させることはできないので、あくまでも擬似的な制御。IKではないのでモーフ量と視線の角度を完全に同期させるにはエクスプレッションを更に作り込む必要がある。

morph038
両目ともモーフ適用量「100%」。視線は交わらずに平行になっている。
morph037
エクスプレッションで視線コントロールをしたもの。左目のモーフ量は「88.78%」、右目は「66.20%」。


今回は水平方向のモーフしか使っていないけど、同様に上下方向のモーフを作っておけば、理屈はまったく同じで瞳の上下運動も可能。

関連記事