みなさん、いつもアンリアルエンジンのご活用ありがとうございます!
この記事はUnreal Engine 4 (UE4) 其の弐 Advent Calendar 2015 10日目の記事です。
#はじめに#
先日のUnreal Fest 2015 Yokohamaにて講演させていただいたUE4でNPR(Youtubeビデオ、Slideshareスライド)の内容をちょこちょこブラッシュアップしていたのですが、CGWORLDさんにご興味を持っていただけ、本日12/10発売のCGWORLD vol.209に掲載してていただきました!
誌面では実際にレンダリングされた画像の高解像度の掲載が難しかったり、アルゴリズムのお話まですることは難しい面がありますので、ここで詳しいアルゴリズムの紹介や画像の掲載をさせていただきます。
ここで使われているマテリアル等に関してはUnreal Engine公式フォーラムの方にアップしてありますので、そちらも参照してみてください。
アンリアルエンジン4でノンフォトリアル描画しよう!
ちなみに、添付画像はすべて実際にキャプチャした解像度のままの画像になっていますが、Qiita上で表示時に横幅合わせで縮小されている場合があります。クリックすると元の解像度の画像に飛べますが、Chromeの拡張でPageExpand等入れてあるとマウスカーソルのホバーで元の解像度(元の解像度がスクリーンより大きい場合はスクリーンの最大解像度)で表示できます。
#サプライズゲスト!#
そしてさらにサプライズ!!今回の解説にあたってスーパーゲストにお越しいただきました!!
フリーランスでモデリング等活動されている蝋燭さん(https://twitter.com/Rousokuc)のご制作された女の子のモデルをお借りする事ができましたのでご紹介させていただきます!
(トゥーンシェーダーの適用例。オリジナルのシーンでは背景が黒だったのですが、今回は輪郭線もご覧いただきたかったので空バックに変更させていただいています。)
(オリジナル。こちらも素敵です。)
蝋燭さんはフリーランスでモデル製作のお仕事も受けできるそうなので、今回の記事で蝋燭さんのモデルが気になった方はぜひコンタクトしてみて下さい。
今回の記事の後半で蝋燭さんのモデルにトゥーンシェーダーを適用してみた際の情報やパラメータは後半で説明させていただきます。
#解説いきまーす#
まずは、今回のトゥーンシェーダーの基本部分から紹介させていただきます。
それでは早速説明に入ります。今回のトゥーンシェーダーですが、基本的にはUE4のポストプロセスマテリアルで実現されています。
トゥーンシェーダーの実現には、リアルタイム系だと
- ライト情報を元にしたテクスチャルックアップによるセル塗り
- 裏面の法線方向押し出しによる輪郭線描画
の2つのアプローチの組み合わせが多かったかと思いますが、今回はポストプロセスで行いますが、理由はこの後の解説の中でおいおい解説できればと思います。
とりあえず適用例を2点ほど。
1つ目はUE4の4.8から標準キャラクタとして登場したマネキン(もしくはグレイマン)が数体いるシーンに今回のトゥーンシェーダーを適用してみた例です。2つ目はUE4マネキンと中野シスターズの「鷺宮なか」ちゃんがいるシーンに水彩画調のポストプロセスを適用した例ですが、基本的にはトゥーンシェーダーの処理を適用しているのですが、追加で画用紙の凹凸に応じて凹部分の彩度を上げ、凸部分の彩度を下げる処理をしつつ、輪郭線の太さを凹凸に応じて変化せています。結構単純な処理を追加しただけですが、それっぽく見えていませんか?画用紙の凹凸画像はUE4のラーニングタブにあるサンプル「スタイライズレンダリング」のものを流用しています。
中野シスターズを公開いただいたガミング様と関係者の皆様に感謝と御礼を申し上げたいと思います。ありがとうございました!
ポストプロセスを使った理由の解説がまだでしたね。実はUE4の1つ前の世代であるUE3後期にはトゥーンシェーダーの作品が結構リリースされていたのですが、国内タイトルでは輪郭線のアルゴリズムとして裏面法線押し出しが採用される場合が多かったかと思います。なのですが国外では有名なタイトルとして「ボーダーランズ」シリーズがあるのですが輪郭線はポストプロセスを使いつつ、稜線はテクスチャへの描き込みというアプローチでトゥーン表現を行っていたようです。
ただ、ポストプロセスでの輪郭線抽出アルゴリズムは有名なところだとSobel Edge検出等が有名なのですが、注目点の周囲8ピクセルの参照等あり結構な描画(テクスチャ参照)コストがかかります。
で、アンリアルフェスでも説明させていただきましたが、このピクセル参照数を抑える事でポストプロセスマテリアルのパフォーマンスを上げる事ができます。
ではどう端折るかというと、ポリゴンの周りで輪郭線を描くべきポイントがどこになるか考えてみます。独立したポリゴン以外の場合、ポリゴンの輪郭線が出るポイントはポリゴンが傾いている方向の端になります。
と、いうことは?注目しているピクセルの法線方向にズラした1ピクセルを参照して、その深度差が大きいところに輪郭線を描けばいけるんじゃない?と試したところなかなか良好な結果が得られたので、アンリアルフェスにて発表させていただきました。
稜線もほぼ同じで、輪郭線の時と同じように面の法線を元に、今度は法線の逆方向にずらした1ピクセルの法線と注目しているピクセルの法線の差が大きい時(シェーダーの中では内積値を使っています)に稜線を描けばよいのではと実装してみたところこちらもまぁまぁ良好な結果が得られました。
とはいえいろいろなモデルで検証してみると問題点も見えてきました。アンリアフフェスで公開したバージョンは
- 視線に平行に近い面、床・壁・天井等の面に意図しない段状の模様が出てしまう
- 稜線がそれほどクッキリとは出ない
という問題がありました。床等に段状の模様が出る点は、視線に並行した面上の注目点と比較対象のピクセルがすぐ隣のピクセルであったとしても深度差が大きくなってしまうので、同じ面上であるにもかかわらず輪郭線を描かなければならない程の差があると認識されてしまう事が原因でした。これは法線や深度から同じ面上と思われる比較先のピクセルの深度を導き出せるハズなので、この導き出された予想深度との差が大きいかどうかで判断するという方法が考えられました。しかしながら、シーンはパースがかかっていたり深度情報もリニアではなかったりするので計算が面倒なので、他の方法もないかと考えてみたところ、解法を思いつきました。
凄く傾いたシーソーを想像してみてください。支点が注目しているピクセルで、沈み込んだ方の片側が、注目点から法線方向にずらした比較先です。シーソーの傾きが大きいと支点の高さと沈み込んだ高さにかなりの差が出ます。ですが、もう片側との差を合わせると平均化されて支点と同じ高さになります。
そう、注目点から法線方向にズラしたポイントとの深度差と、注目点から法線の逆方向にズラしたポイントとの深度差、両方を足し合わせるとどちらも同じ面の上であった場合ほぼゼロになります。これがゼロではなく大きな差がある場合に輪郭線とすることで床等の段状の模様を消す事に成功しました!
稜線も実は同様に、注目点の法線方向と法線の逆方向との法線の差を合成することで山・谷両方の線を描く事もできるようになりました。
以上で輪郭線・稜線はかなり良好な結果が得られるようになりました!現在はこの2ポイントサンプリングのアプローチが実装されています。
また、このアプローチの良い点として、法線に線の太さ的な係数を掛けてあげることで、線を太くする効果も得られます。
輪郭線のアルゴリズムの違い。
実はUE3の時代にもトゥーンシェーダーのサンプルを公開していました。
この時のアルゴリズムは今まで説明していた深度差から輪郭線を描くものではなく、法線が側面を向いている面を暗く描くというものでしたが、それなりにメリットもありまして、ポストプロセスではなく普通のサーフェース用のマテリアル内で完結できるので高速かつ他の描画と相性が良く、さらにノーマルマップ内にも線を描くことができるというものがありました。今回のポストプロセスでのトゥーンでは同様のアプローチも使えるようにしてあります。
輪郭線の描画アルゴリズム比較
輪郭線なし
法線が側面を向いている面を暗く描画
深度差の大きい境界に線を描画
ノーマルマップによる凹凸にも輪郭線や稜線を描ける、以下のアンリアルのロゴマークはポリゴンではなくノーマルマップで描かれています。
ノーマルマップによるロゴの凹凸表現(なので、深度差はありません)
ワイヤーフレーム表示にするとロゴの部分はただの板ポリしかないことがわかります
法線表示モード
側面向きの面を暗く+稜線の描画
輪郭線の太さの違いも法線を元にしているので面の向きで変化が出せるのと、さらに法線方向にずらした方向のサンプリングをすることで、線の太さも柔軟に変化させることが可能です。
輪郭線なし
輪郭線を普通に描画
輪郭線を太く描画
#NPRマテリアル群のパラメータ
そろそろ、パラメータの調整方法をご紹介しましょう。
今回のNPRアルゴリズム、主なアセットは以下になります。
種類 | アセット名 | 説明 |
---|---|---|
マテリアルパラメータコレクション | NPR_ParamCollection | 今回のNPRマテリアル群のための共通パラメータを保持しています |
ポストプロセスマテリアル | PP_NPR | 今回のNPRを実現しているポストプロセスマテリアルです |
マテリアル | M_CharacterBase | キャラクタの肌等、明るさや影の出方を調整したいメッシュにこのM_CharacterBaseを継承したマテリアルインスタンスを利用します |
ブループリント | BP_DirectionalLightForCharacter | DirectionalLightを継承したブループリントで、DirectionalLightと置き換えて利用することで、マテリアルパラメータコレクションのCharacterLightVectorのキャラ用のライト方向としてこのDirectionalLightの方向を自動的に設定します |
###NPR_ParamCollectionの詳細
パラメータ名 | 値の説明 |
---|---|
DebugWipe | デバッグ用、0.0~1.0でポストプロセスマテリアル効果のかかる領域を調整します |
LightIntensityStepping | セル塗りの塗り分け段階 |
LightIntensityBias | 明るさの底上げをします(「マチネファイトシーン」のような暗めのシーンの底上げに有用) |
FresnelFunc_ContransDark | 側面を向いた法線の検出にはFresnelノードを使っているのですが、詳しくはマテリアルでフレネルを使用する方法の「Fresnel Vector Ops」を参照してください |
FresnelFunc_ContrastBright | 側面を向いた法線の検出にはFresnelノードを使っているのですが、詳しくはマテリアルでフレネルを使用する方法の「Fresnel Vector Ops」を参照してください |
EdgeLineThickness | 輪郭線の太さです |
CreaseLineThickness | 稜線の太さです |
FlankLine | 法線が側面方向を向いた部分のカラーにこの係数を掛けます(0.0で真っ暗~1.0で効果がなし、より大きな数字を設定すると光ります) |
EdgeLine | 輪郭線となる部分の元のカラーにこの係数を掛けます(0.0で真っ暗~1.0で効果がなし、より大きな数字を設定すると光ります) |
CreaseLine | 稜線となる部分の元のカラーにこの係数を掛けます(0.0で真っ暗~1.0で効果がなし、より大きな数字を設定すると光ります) |
LineColor | ラインのカラーを上乗せする事ができます、アルファ値0.0~1.0で掛かり具合を調整 |
CharacterLightVector | 後述のM_CharacterBase等から参照されるライトの方向です |
CharacterLightColor | 後述のM_CharacterBase等から参照される(予定の)ライトの色です |
アメコミ調の線をガッチリ描く場合はFlankLine,EdgeLine,CreaseLineをゼロにして線を黒く、そして線を太めに、またFresnelFunc_ContransDarkをほぼゼロにすると陰が力強い黒になりますが、やりすぎると床面等にも黒い影響が出るので程々に。
逆に柔らかい線にした場合は、FlankLineを1.0にして影響をなくし、EdgeLineとCreaseLineを0.3等にすると元の色を暗くした線が描かれます。さらにLineColor等で茶色っぽい線を乗せてみるのも良いでしょう。
###PP_NPRの詳細
基本的には、PP_NPRからマテリアルインスタンスを作成してシーンに配置した(もしくはされている)ポストプロセスボリュームのBlendablesに設定します。マテリアルインスタンス内で設定できるパラメータの詳細はこちらです。
パラメータ名 | 値の説明 |
---|---|
DebugMonochrome | チェックを入れるとモノクロ表示になります |
DrawCanvas | チェックを入れると水彩画調の表現になり、CanvasTextureが指定できるようになります |
TwoPointSampling | (開発用)チェックを外すと、前段で説明した2点参照ではなく、1点参照版になり速度は早くなりますが輪郭線の検出クオリティが落ちます |
UseCharacterLight | (開発用)セル塗りをカッチリさせる設定テスト版 |
UseScreenTone | (開発用)テスト中のスクリーントーン機能 |
CanvasTexture | (DrawCanvasにチェックが入っている場合のみ現れます)水彩画調の場合に画用紙やキャンバスを模したテクスチャを指定します(スタイライズデモのT_TexturedPaperを設定してみてください) |
###M_CharacterBaseの詳細
パラメータ名 | 値の説明 |
---|---|
TweakNormalToCamera | 法線をカメラの方向に補正させます |
TweakNormalToLight | 法線をNPR_ParamCollectionのCharacterLightVectorの方向に補正させます |
TweakNormalToUp | 法線を上方に補正させます |
TweakNormalToView | 法線をビューの方向に補正させます |
UseEmissiveTexture | エミッシブのテクスチャを使う場合にチェックします |
UseLinearColorTexture | チェックするとカラーテクスチャはリニア扱いになり、チェックを外すとカラーテクスチャはSRGB扱いになります |
UseNormalTexture | ノーマルマップテクスチャを使う場合にチェックします |
UseSpecularTexture | スペキュラマップテクスチャを使う場合にチェックします |
SubsurfaceColor | シェーディングモデルをSubsurfaceにした場合にSubsurfaceの色を指定します |
DiffuseBase | ディフューズテクスチャをBaseColorとして出力する割合を指定します(光源計算が適用されます) |
DiffuseEmissive | ディフューズテクスチャをエミッシブ(自己発光)として出力する割合を指定します(光源計算やシャドウ計算が適用されませんので影を落とされたくない肌等に有用です) |
DiffuseSaturation | ディフューズカラーの彩度を調整します |
Metaric | マテリアルのMetaricです |
Roughness | マテリアルのRoughnessです |
DiffuseTexture | ディフューズテクスチャ |
NormalTexture | (UseNormalTextureにチェックが入っている場合のみ現れます) |
EmissiveTexture | (UseEmissiveTextureにチェックが入っている場合のみ現れます) |
SpecularTexture | (UseSpecularTextureにチェックが入っている場合のみ現れます) |
セルの塗り分けが細かく出て欲しい場合はDiffuseBaseを1.0に近くして、DiffuseEmissiveをゼロに。
肌等で塗り分けを抑えたり影が落ちるのを抑えたい場合は、DiffuseBaseをほぼゼロに近づけて、DiffuseEmissiveを上げる。
とすると今回の可愛い系のモデルの良さを引き出せると思います。
###BP_DirectionalLightForCharacterの詳細
コンテンツブラウザでBP_DirectionalLightForCharacterを選択状態にして、シーンにある平行光源、DirectionalLightを右クリックしてBP_DirectionalLightForCharacterに置換することで自動的にライトの方向をNPR_ParamCollectionのCharacterLightVectorに設定され、M_CharacterBaseマテリアル内でライトの向きを考慮した計算ができるようになります。
#M_CharacterBaseを継承したマテリアルインスタンスとBP_DirectionalLightForCharacterを使ってみたハッカドールさん。
こちら見ていただくとわかると思うのですが、線の色も変える事が可能です。
また、肌と髪の毛はM_CharacterBaseでシェーディングモデルをSubsurfaceにしてSubsurfaceColorに肌の場合は赤っぽい色を入れ、髪の毛のSubsurfaceColorには、髪のベースの色と少し異なる色を入れることで色味の変化を出しています。さらに肌にはセルの塗り分けと影が落ちないよう、DiffuseBaseをほぼゼロにしつつ、DiffuseEmissiveを0.9等しています。
あと、PostprocessでAmbient Occlusionが設定されていると塗り分け部分がザラつくので、塗り分けを綺麗に出したい場合はAmbient OcclusionのIntensityを0.0にするのもオススメです。
ハッカドールを公開いただいたDeNA様と関係者の皆様に感謝と御礼を申し上げたいと思います。ありがとうございました!
マチネファイトシーン
オリジナル
トゥーン化
水彩調
水彩調、手前の人の手のモーションブラーとシーン全体のNPR化両方がきちんと適用されていますね。
Infiltratorデモにも適用
DOF(Depth of Field、深度によるボケ)とも問題なく併用できています。
別の角度から、人のディテイルもですが、機械のディテイルにも線が描画されていて、ノーマルマップでの凹凸にも線が描画されています。
水彩画調
トゥーン適用イメージ
ハイエンドCG(オリジナル)
輪郭線抽出+セル塗り
ベースカラー(ほぼアルベドテクスチャのまんま)
ベースカラー×(輪郭抽出+セル塗り)+半透明
水彩調
InfinityBladeのアセット集のテストステージ
オリジナル
トゥーン
水彩画調
#いよいよ蝋燭さんの女の子
さて、それではお待たせしました。蝋燭さん(https://twitter.com/Rousokuc)のモデルに今回のトゥーンシェーダーを適用してみた事例をご紹介させていただきます。
オリジナルのシーンも勿論素敵なのですが、元々のモデルが素敵なのもあって今回の事例もとても味わい深いものがあるのではと思います。
上記はオリジナルのシーンと同じ状態のブルームやDOFが掛かっていて少し柔らかい画になってしまっているので、ブルームやDOFをOFFにして、トゥーン化のみの素の状態の画像も何枚か載せさせていただきますね。
素の状態でも(ブルームやDOFでぼけてしまわずに)綺麗に描かれているのがご確認いただけるかと思います。
今回のトゥーンシェーダーのポストプロセスでセルアニメ調の表現ももちろん可能です。そして、蝋燭さんの事例からも感じていただけたのではと思うのですが、このような画がリアルタイムに実現できるので、アニメ作品全編をセルアニメ調とはまた違った、例えば全編が手描きのイラストのようなアニメというものも実現できるものと思っています。
セルアニメとはまた違った、全編手描き風アニメーション作品があったら見てみたくなりませんか?(短編のアニメーション作品では時々ありますけど長編の商業作品として)
しかもリアルタイムレンダリングしていますのでVRコンテンツ化も可能だったりします!(実は蝋燭さんのモデルをお借りした流れで、GTX 770でOculus Rift DK2で75fps出る所まで調整できていまして、そのプロジェクトは蝋燭さんにお送りしてあります。蝋燭さんとVRプロジェクトを立ち上げてみるのも面白いかもしれませんね。僕は実際にVR体験しましたが、普通のモニタで覗いている状態とは全然違うレベルの臨場感・存在感を感じる事ができます。ぜひみなさんの作品でもVR体験してみてください。)
#最後に#
アンリアル・エンジンがアニメーション作品に新たな潮流を生み出すことのお役に立てたらこんなに嬉しいことはありません。
ぜひ皆さんの作品に適用してみてください!そして、作品ができましたらぜひお知らせください。:)
明日12/11は@shsnow23さんの「UE4用mrubyプラグインを作ってみる。」です。