【UE4】水彩風マテリアルを作ってみた
はじめに
裏 Unreal Engine 4 (UE4) Advent Calendar 2016 8日目です。
我らがおぎまふさんやcom04さんなど、いろいろな方がトゥーン表現に挑戦されています。
最近ではMarketPlaceでもトゥーンなアセットが出てきたりしています。
いろいろ参考サイトをまとめていたのですが、com04さんの記事を見たほうが早いですね…
ですがやっぱり自分好みのものを作りたい…と思って探していたら参考になりそうなところを見つけました。
こちらのサイトではsoftImageですが、なんとかそれっぽくなりました。
マテリアルダメダメなので、練習ついでに作ってみました。
できたもの
水彩風マテリアルがだいたい出来た#UE4Study pic.twitter.com/yUPdarH34r
— てんちょー (@shop_0761) October 18, 2016
ズームアップした pic.twitter.com/pl1rVDxyAh
— てんちょー (@shop_0761) October 20, 2016
つくりかた
ここから先は、先程の参考サイトを見た前提でお話を進めていきますね。(さらっとでおkです)
考え方、手順は参考サイトと同じなので それをどうやって再現したか という感じで進めます。
とりあえず今回は
- BaseColor
- Specular
- Shadow
に当たる部分のマスクを愚直に作って色指定、その境目にNoiseを入れてなじませていきます。コンパイルが重いかも。
ついでに、各色をテクスチャではなく直で色指定しています。モデルによっては細かくマテリアルが分けてる 方が相性がいいです。処理負荷は気にしないことにします。
BaseColorのマスクを作る
BaseTextureを指定できますが、結局Desaturationしてしまうのでそのままでもいいかも。
Blurをかけます。
Blurノード
float4 output = 0; float weightSum = 0; float currentWeight = 1.0; for (int i = 0; i < 10; ++i) { output += Texture2DSample(Material.Texture2D_0, Material.Texture2D_0Sampler, texCoord + i * stride) * currentWeight; weightSum += currentWeight; } output /= weightSum; return output;
参考:
そして、ちょっとNoiseをのせたり。 もちろん、すでにあるNoiseノードでもいいかと思いますが今回はstylized RenderingのT_TexturedPaperを使用しています。
Specularのマスクを作る
こちらはおぎまふさんを見習ってLightVectorを擬似的に用意して、Specularの計算をします。
こうして出来た2つをDesaturationしてそれぞれマスクとしました。
ここまででとりあえず2色分塗ることが出来ました。
ShadowとEdgeのマスクを作る
ここで影色も塗らなきゃなりませんが、このままでは塗れないのでゴリ押しで解決します。
影色になる部分を一旦求めて、今の絵に黒で塗り直します。(いい方法が知りたい)
こうすると後からaddして色を乗せられます。
こちらはおぎまふさんのRimLightの実装をそのまま使ってますので関数の中身は割愛します。
水彩の参考サイトの完成絵を見るとエッジが2段あるように見える(実際は歪めたり、ノイズかけたり)のでRimLight_Rangeにちょっとaddして作ります。
NoiseありとなしのEdgeがあったほうがよかったので、分けて作ってます。
ついでにさっきのshadowマスクを使って、明るい方のEdgeと暗い方のEdgeを作り分けてます。
ここで影色も作ってます。
まとめる
最後にshadow側とBaseColor側をaddして完成です。 お好みでNormalMapも使えるようにswitchをつけたりしました。
こうすることでGraymanの胸のUnrealロゴが出せます。
余談
最初はこのマテリアルをPostProcessで実装していたのですが、マスクできるようになったけど色指定できない…ってなったのでやめました。
その時、最初に作っていた影色を少し淡くするPostProcessが出来たのでついでに載せておきます。
そしてさらにalweiさんのお手軽トゥーンと比較
— てんちょー (@shop_0761) October 8, 2016
影がキツくなくなった感 pic.twitter.com/C4bixB3Ii2
alweiさんのお手軽Toonのマテリアルにちょっと足すだけです。
全体
追加した部分
CustomDepthでマスクを作った結果を使ってなんかごにょごにょしました。
でこの結果を最後にaddして出力してます。
余談2
blurのコードを書いてるときに思いついたのですが、blurベースでedgeが取れそうだったのでやってみました。
このぐらいいけます。
ノードはこれだけ 面倒なSobelフィルタを作らなくても使えるかも。
Blurのコード
float3 output = 0; float ScreenMult_X = GetPostProcessInputSize(0).zw.x; float ScreenMult_Y = GetPostProcessInputSize(0).zw.y; output += 1.0 * SceneTextureLookup(TexCoord + float2(ScreenMult_X * BlurAmount * -1.0, 0.0), SceneTextureID, true); output += 1.0 * SceneTextureLookup(TexCoord + float2(ScreenMult_X * BlurAmount * 1.0, 0.0), SceneTextureID, true); output += 1.0 * SceneTextureLookup(TexCoord + float2(ScreenMult_X * BlurAmount, 0.0), SceneTextureID, true); output += 1.0 * SceneTextureLookup(TexCoord + float2(0.0, ScreenMult_Y * BlurAmount), SceneTextureID, true); output += 1.0 * SceneTextureLookup(TexCoord + float2(0.0, ScreenMult_Y * BlurAmount * -1.0), SceneTextureID, true); output += 1.0 * SceneTextureLookup(TexCoord + float2(0.0, ScreenMult_Y * BlurAmount * 1.0), SceneTextureID, true); output /= 6.0; return output;
SceneTextureIDを引数にすることで、任意のSceneTextureを指定できます。 outputは加算した分だけ割ります。
多分この順番通りでIDが振られてると思います 分からなかったらコードを読めばいいんだよ うん。
まとめ
なんとなくMaterialの演算が分かった気がします。もろもろの計算は試行錯誤の結果なので、「なんでこうなるの?」というより「色々やったらこれがよかった」って感じです。
作りたい絵を目指して、実際に手を動かしてみるとこの意味がわかるかと思います。すごい人になれば頭のなかで完成形をイメージしながらノードを組めるかと思いますが()
まずは作りたい絵を探しましょう!!
わからないこととかあれば、可能な限りお答えするのでTwitter(@shop_0761)等でご連絡ください。
明日は Epic社のおかずさん(@pafuhana1213)の「帰ってきたUE4のマーケットプレイスで購入したアセットを片っ端からレビューするマン」です。
鹿のレビューが懐かしい…