ぼっちプログラマのメモ

UE4とかVRとかについて書いたり書かなかったり。

UE4のポストプロセスマテリアルで色々してみた 基本編 - Unreal Engine 4 (UE4) Advent Calendar 2014


Unreal Engine 4 (UE4) Advent Calendar 2014 - Qiita
の二日目です。

記事名の通り、UE4のポストプロセスマテリアルについて雑多に色々書きます
今回は基本編です。この記事の内容をベースに色々してみたことを
来週に書きます。(記事が長くなり過ぎたので分割しました)

参考サイト

あなた「この記事を見なくても、この参考サイトを巡回すればいいんじゃね?」
わたし「…君のような勘のいいガキは嫌いだよ」



「そもそもポストプロセスマテリアルってなんやねん?」という方には、
@aizen76さんのこの記事がオススメです
UE4 ポストプロセスエフェクトについて - Let's Enjoy Unreal Engine

Hello PostMaterial World

まずは、最もシンプルなポストプロセスマテリアルを作ってみます。

M_SimplePostという名前のマテリアルを作成し、レベルに配置した
PostProcessVolumeのMisc/Blendablesに追加します
f:id:pafuhana1213:20141123231301j:plain

そして、M_SimplePostは以下のように設定します。処理内容をざっくり説明すると、
各画素に割り当てられたテクスチャ座標(Texcoord)を用いて、
レンダリング結果を保存したテクスチャ(SceneTexture:SceneColor)を参照し、
その値をそのまま出力に渡しています
https://dl.dropboxusercontent.com/u/30427841/1202/simplepost.jpg

なので、描画結果に変化はありません。
f:id:pafuhana1213:20141123233036j:plain

おまけ

f:id:pafuhana1213:20141123234132j:plain
TexCoordの値は左上(0,0)右上(1,0)左下(0,1)右下(1,1)になっています
その為TexCoordを出力に繋ぐと、結果は↑のようになります


皆大好きアウトライン(輪郭線)フィルタ

ポストマテリアルを触る理由の98割はアウトラインフィルタだと思います(超絶偏見)
ということで、早速作ってみましょう

アウトライン描画をポストプロセスで実現するには、エッジ検出をする必要があります
今回はエッジ検出手法の1つである、Prewittフィルタを実装してみましょう

※ エッジ検出手法には他にも、SobleフィルタやLaplacianフィルタがあります
  前者は@monsho1977さんのサイト、後者は@com04さんのサイト
  実装・解説されています

※ 輪郭線描画で、ポストプロセス以外の手法としては押出法があります
  こちらは、@com04さんのサイトで実装・解説されています

エッジ検出ってなんなのさ?

f:id:pafuhana1213:20141201230951j:plain
先ほどの結果画像からキャラクターの左目付近を拡大した画像です

かなり荒い画像ですが、キャラクターと背景の色が異なるので
判別できていると思います。

さらに細かく書くと、
キャラクターの輪郭線にあたる画素のRGB値と、その右側にある
背景画素のRGB値が大きく異なる
為、脳内で境界線を引く事ができています。
(逆に、肌と髪の毛の色は似ているので判断しづらいと思います)

つまり、エッジ処理を実現するためには、各画素毎に以下の処理をします

  1. 周辺の画素情報を取得
  2. 周辺画素と処理対象画素との変化量を計算
  3. 変化量が一定以上なら輪郭線と判断

そして、この処理を効率よく、かつ効果的にする手法として生み出されたのが
上で挙げた各フィルタ処理です。
Laplacianフィルタの場合だと、こんな感じの処理になります。
f:id:pafuhana1213:20141201233325j:plain
http://www.technotype.net/tutorial/tutorial.php?fileId=%7BImage+processing%7D§ionId=%7Bwhat-is-spatial-filter%7D


今回実装するPrewittフィルタは、水平方向と垂直方向の2回に分けて処理を行います
解説すると、さらに長くなるので解説サイトを置いておきます
ちなみに、Sobelフィルタも同様に、水平・垂直で2回処理を行います
f:id:pafuhana1213:20141202011300p:plain
☆PROJECT ASURA☆ [OpenGL] 『Prewittフィルタ』
edge detection (Sobel filter/Prewitt filter)

フィルタ処理の実装するぞい

誰得な解説が終わったので、早速実装に移ります
上で「RGBの変化が~」と説明しましたが、今回のフィルター処理では
RGB値ではなくデプス値を使用します。その方が綺麗にエッジ検出できるからです
f:id:pafuhana1213:20141201235340j:plain

今回は↓のような感じで、フィルターの各係数を渡せるマテリアル関数を作ります
我ながら超ベンリです。
https://dl.dropboxusercontent.com/u/30427841/1202/%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%83%BC.jpg

この関数の中身と、中で使用しているマテリアル関数は以下のとおりです
隣り合う画素情報の取得は、参考サイト様からの丸パクリです
@monsho1977さんのサイト
@com04さんのサイト

隣り合う画素のTexcoord取得

MF_GetOffsetPixel
https://dl.dropboxusercontent.com/u/30427841/1202/gettexcoord.jpg

隣り合う画素のデプス値取得

MF_GetOffsetPixelDepth
https://dl.dropboxusercontent.com/u/30427841/1202/depth.jpg

フィルター処理

MF_FilterFunctionDepth
https://dl.dropboxusercontent.com/u/30427841/1202/filter.jpg

Prewittフィルタ

https://dl.dropboxusercontent.com/u/30427841/1202/prewitt.jpg

↑の状態で適応した結果が↓です。こわいです
f:id:pafuhana1213:20141202011421j:plain
デプス値の変化量が多いほど、出力値が大きい=白色になっているのが
分かると思います。あとは、以下の処理を加えれば完成です

  • 真っ白な部分のみを抽出
  • 黒色の輪郭線にしたいので、白黒反転
  • 元々の描画結果に重畳

https://dl.dropboxusercontent.com/u/30427841/1202/pre.jpg

で、結果はこんな感じ。今度はかわいい
https://dl.dropboxusercontent.com/u/30427841/1202/result.jpg

ついでに、各フィルタでの比較(見栄え重視で、調整用パラメータ弄ってます)
https://dl.dropboxusercontent.com/u/30427841/1202/%E6%AF%94%E8%BC%83.jpg
Laplacianフィルタはエッジ検出し過ぎるので、輪郭線には向かないかもしれません…
SobelかPrewittはお好みでという所でしょうか?
調整用のパラメータ次第で幾らでも変わるので、色々と試して見て下さい

Tips

終わる前に紹介したいTipsを1つ

マテリアル関数の引数の順番指定について

今回作成したフィルター関数のように、引数(ピン)の順番を
指定したくなる時があります
そんな時は、Inputに指定したノードのSortPriorityの値を設定しましょう
この数値が低い順で、上からピンが配置されます。便利です
f:id:pafuhana1213:20141202020856j:plain

予告編

駆け足説明になりましたが、これで輪郭線が書けました!
Happy End!


…が、これは前座です!前座です!(大切なことなので


来週12/9に公開する記事では、さらに色々工夫することで
面白い画を作る方法について説明します!
f:id:pafuhana1213:20141202022557j:plain
少し前に流行った漫画風フィルターとか…
f:id:pafuhana1213:20141202022554j:plain
かま○たちの夜的な表現だったり!

お楽しみに!


明日12/3の担当は@kurosaurusさんで、
タイトルは「Bitmap2Materialで写真から簡単物理マテリアル」です


しゅごい…楽しみです!