今回はエンジンのシェーダコードを変更することでトゥーンシェーダを実装してみようと思います。
基礎編とか言ってますが、今のところ応用編を作成する予定はありません。
トゥーンシェーダは通常、ライトの影響を2値、もしくは3値に変換することで実装します。
よくある実装方法はルックアップテーブルをテクスチャ化し、これを利用する方法です。
ライトの影響は法線とライトベクトルの内積で求められ、-1.0~1.0の範囲を取ります。
これを0.0~1.0に圧縮、ルックアップテーブルテクスチャをサンプリングします。
この手法はトゥーンシェーダ以外でも割と使われるのですが、今回はこの方法を用いません。
テクスチャをサンプリングする場合はテクスチャをシェーダにバインドしてやる必要があるのですが、これを行うにはシェーダコード以外にC++コード側も修正する必要があります。
今回はシェーダコードのみの実装にするため、シェーダコード内で比較を用いて2値化します。
シェーダコードは当然GitHubのエンジンコード内に存在します。
なのでエンジンコードを持ってくること、ビルドする環境があることが条件になります。
エンジンコードはサブスクリプション契約をしていれば取得できます。
ビルド環境はWindowsならVisual Studio 2013があればOKです。
無料環境は現在、Visual Studio Community 2013が無料で使えるのでこれを持ってきます。
まあ、詳しい方法についてはヒストリアさんのブログを参照してください。
エンジンコードをビルドし実行すると、普通にUEを立ち上げたのと同じ状態になります。
ここで作成したプロジェクトはビルドしたエンジンに関連付けられるので、バージョン変更をしない限りはコード変更の影響を受けます。
では、コードを変更していきましょう。
直接ライティングを処理しているのは"DeferredLightingCommon.usf"というファイルです。
プロジェクト内では、"Engine/UE4/Shaders"内に存在します。
変更箇所は610行目付近で、以下の太字のように変更しましょう。
float3 SurfaceLightingSpec = SurfaceShading(ScreenSpaceData.GBuffer, LobeRoughness, LobeEnergy, L, V, N, float2(0, 1));
float NoLAndAttn = NoL * SurfaceAttenuation; if (ScreenSpaceData.GBuffer.ShadingModelID == SHADINGMODELID_DEFAULT_LIT) { NoLAndAttn = (NoLAndAttn > 0.2) ? 1.0 : 0.0; } LightAccumulator_Add(LightAccumulator, SurfaceLightingDiff, SurfaceLightingSpec, LightColor * NoLAndAttn); |
法線とライトベクトルの内積だけでなく、シャドウによる減衰分も含めて2値化します。
シャドウの減衰を考慮しないとトゥーンっぽくならないです。
変更をしたらプロジェクトを立ち上げ直すか、プロジェクトがすでに立ち上がっている場合はCtrl+Shift+"."のショートカットキーでシェーダのリビルドを行います。
これで変更が有効になるはずです。
で、結果がこれ。
見ての通り、陰影は2値化されています。
ただし、GIによる影響はありますし、スペキュラやリフレクションは別の処理なのでちょっと微妙かもしれません。
また、半透明マテリアルはまた別のライティング処理なのでやっぱりうまくいきません。
ここまでやったらあとはポストプロセスなどでアウトラインをつけてやればそれっぽくなるんじゃないでしょうか?