もんしょの巣穴blog

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

[UE4] エンジンを拡張してポストプロセスを実装する おまけ

この記事はポストプロセスをエンジン改造で実装する際にハマった罠について書いています。
エンジン改造してまでポストプロセスの実装なんてしないよ、という方には不要かもしれません。

コンソールゲーム機ではフレームバッファの解像度をユーザが変更できる機能は通常存在しません。
処理落ち回避のために動的にフレームバッファの解像度を変更するゲームがあったりはしましたが、あまり存在していません。

しかし、PCゲームでは解像度を変更する機能は普通に存在しています。
ましてやUE4やUnityのようなゲームエンジンはエディタ上でゲームを動かせるため、エディタ上のゲームViewのサイズが変更されることも多くあります。

解像度が変更された場合、通常であればフレームバッファや、ポストプロセスなどで処理を行うためのオフスクリーンバッファは解像度に合わせて作り直されるのが一般的です。
UE4でも基本はそうなのですが、ある状態変化の場合はフレームバッファが作り直されません。
その状態というのは、解像度が小さくなった場合です。

まずはこの画像をご覧ください。

ue416.jpg

これはUE4のエディタを小さめにして使っていた場合の途中のレンダーターゲットです。
では次。

ue417.jpg

こちらはエディタを最大化した際のレンダーターゲットです。
当然ですが解像度は縦も横も上がっているので、フレームバッファやオフスクリーンバッファは作り直されています。

では最後。

ue418.jpg

エディタの最大化を解除して、最初と同じウィンドウサイズに変更した場合のレンダーターゲットです。
見ての通り、最大化したサイズのまま、描画される範囲だけが小さくなっています。

この動作はシッピングされたゲームでも同様の動作をするのかは不明ですが、少なくともエディタ上ではこのように動作します。

ポストプロセスを実装する際、フレームバッファとサイズの異なるバッファを使用することはよくあります。主に縮小バッファとして。
しかし、単純にバッファサイズのポリゴンを描画するような方法を取ってしまうと正常に描画されなかったり無駄なピクセルシェーダが動いてしまったりします。
なので、正しいサイズで、正しい範囲に描画を行わなければなりません。

今回ピクセルシェーダで実装したディフュージョンフィルタでは他のポストプロセスに習って DrawPostProcessPass() という命令を使用しています。
この命令は出力先のレンダーターゲットに対して適切なUV座標を持った板を描画してくれる命令です。
ここに適切な値を渡してやればバッファサイズがどんなに変わってもちゃんと描画されますが、適切でないとうまくいきません。
なので必要なパラメータを少し紹介します。

float X, Y, SizeX, SizeY
これはレンダーターゲットに対するViewportの左上座標とサイズです。単位はピクセル。

float U, V, SizeU, SizeV
これはポストプロセスを適用する元のバッファのUV値の左上座標とサイズです。こちらも単位はピクセル。

FIntPoint TargetSize
これはレンダーターゲットのバッファの縦横のサイズです。単位はピクセルで、与えるのは整数値です。

FIntPoint TextureSize
これは元のバッファの縦横のサイズです。単位はピクセル、整数値で与えます。

この関数は簡単なポストプロセスには比較的簡単に適用できるのですが、複数のサイズが異るバッファを使った場合はうまくいかない可能性も出てきます。
複数のテクスチャにおいて使用する正規化されたUV値が同一でOKならさほど問題はないです。ちなみに、ディフュージョンフィルタでは同一UV値でOKだったので正常動作しています。
比率がぜんぜん違うテクスチャを複数枚使う場合はこの命令を参考に自分たちの用途に見合った命令を作成しましょう。

というわけで、ちょっとしたおまけでした。
スポンサーサイト
  1. 2016/12/17(土) 00:16:32|
  2. UE4
  3. | トラックバック:0
  4. | コメント:0

[UE4] エンジンを拡張してポストプロセスを実装する CS編

この記事は裏UE4 Advecnt Calender 2016の15日目の記事です。

UE4のポストプロセスはマテリアルを利用して比較的簡単に拡張が可能です。
しかしながら、いくつかの問題点も存在しています。

問題の1つにCompute Shaderが使用できない、というものがあります。

Compute Shaderはラスタライザを使用せずにGPUの高速な演算機能を使用する手段で、DX11世代以降で追加されたシェーダです。
特にDX12やVulkanではグラフィクス処理と並列に処理を行うことが出来るコンピュートパイプと呼ばれるパイプラインが存在し、これを利用した非同期コンピュートはグラフィクス用途でもそれ以外の用途でも使用できます。
グラフィクス処理を行うパイプラインでも使用することは出来ますが、ここで使用する場合はコンテキストスイッチなどが発生するようで、場合によってはラスタライザを経由するより処理速度が落ちます。

しかし、Compute Shaderには共有メモリが存在します。

Pixel Shaderは各ピクセルごとに独立して処理が行われます。
そのため、テクスチャのサンプリングはそれぞれのピクセルごとに行われ、別々のピクセルで同一テクセルをサンプリングしたとしてもその情報を共有することは出来ません。

Compute Shaderは一連の処理を複数回行う際、複数の処理の束をグループとしてまとめることが出来ます。
グループ内の処理は基本的には独立しているのですが、グループ単位で少ないながらも共有メモリが使用でき、また、グループ内の処理の同期をとることが出来ます。
これを利用することで、別々のピクセルでの処理に同一テクセルを大量にサンプリングされる場面で共有メモリを介して高速化することが可能です。

今回は以前ポストプロセスマテリアルで実装したSymmetric Nearest Neighbourフィルタをエンジンを改造してCompute Shaderで実装しました。
ただ、大変残念なお知らせですが、普通にPixel Shader使うより遅いです。
コンテキストスイッチが発生してるなどで処理速度が遅くなっている可能性が高いですが、まだ何が原因かは調べていません。
余裕があったら調べようとは思いますが、わかっているのはPixel Shaderでの実装より倍遅かったです。
メモリ帯域が狭いGPUの場合は共有メモリによる高速化が効いてくるはずですが、GTX1070ではさほど効果がないようです。

ue415.jpg

PostProcessSNNが今回実装したCS版SNNで、その下の "M_SNN_Filter" がポストプロセスマテリアルで実装したPixel Shader版のSNNです。
SNNCopyという描画パスについては後にご説明します。

では、続きからで実際の実装方法を見ていきましょう。

[[UE4] エンジンを拡張してポストプロセスを実装する CS編]の続きを読む
  1. 2016/12/15(木) 00:04:42|
  2. UE4
  3. | トラックバック:0
  4. | コメント:0

[UE4] エンジンを拡張してポストプロセスを実装する PS編

この記事はUE4 Advent Calendar 2016の15日目の記事です。

UE4ではポストプロセスの作成にポストプロセスマテリアルを使用します。
通常のマテリアルと同様にマテリアルエディタで作成でき、マテリアルインスタンスも使用できます。
ポストプロセスのパラメータをランタイムで変更する場合はパラメータコレクションを利用する必要がありますが、BPを利用すればレベルごとの設定などもそれほど難しくなく便利です。

しかしいくつかの問題点が存在します。
そのうちの1つで、個人的に最も大きいのがオフスクリーンバッファを使用できないことです。

ポストプロセスを本格的に作成する場合、複数の画像をコンポジットする必要が出てきます。
ポストプロセスマテリアルでもG-Bufferとして保存されている画像はコンポジットすることが出来ますが、それらから生成した複数の画像をコンポジットするということが出来ません。
なのでポストプロセスマテリアル内でそれらすべての画像の加工からコンポジットまで行う必要があります。
それで実装可能であれば問題ないのでは?と思う方もおられるかもしれませんが、加工が重い処理の場合は速度的にどうなの?とか、クオリティは保てるの?などの疑問も出てきます。

それらを解決する方法としてエンジン側にポストプロセスを作成、埋め込むという方法があります。
もちろんエンジン改造となるので改造コストは安くないですし、特に改造後のエンジンバージョンアップに対応するコストが馬鹿になりません。
ただ、ポストプロセス部分は割と独立してる感のある部分なので、既存のポストプロセスの順番を入れ替えるよりマージコストは低いのではないかと思います。

というわけで、今回は以前ポストプロセスマテリアルで実装したディフュージョンフィルタを、エンジン改造によってよりクオリティの高いものにする実験を行いました。
ディフュージョンフィルタは以下のようなパスで実装されます。

ue411.jpg

元の画像の色を2乗して、このバッファをガウスブラー、2乗カラー画像とブラー画像をスクリーンブレンドし、最後に元画像との間で色の最大値を取ります。

ポストプロセスマテリアルの実装ではカラーの2乗~比較(明)までの処理が1パスで処理されていました。
問題点を上げるとするなら、ガウスブラーを行う前にかならずサンプリングしたテクセルを2乗する必要があるという点です。
2乗した画像が別に存在するなら、ただそれをガウスブラーすればいいだけなのですが、ポストプロセスマテリアルでは1パスですべての処理を終わらせなければならないのでこのような実装になります。

また、ガウスブラーの実装にも問題があります。
ガウスブラーのGPU実装はX軸方向のガウスフィルタとY軸方向のガウスフィルタを別パスで、つまり2パスで行うことが多いです。
この方が高速で、且つ綺麗にブラー出来ます。
ポストプロセスマテリアルではこの手法は使えないので、ボックスブラーよろしくボックス状にテクセルをサンプリングしてガウスブラーを掛けなければなりません。
綺麗にしようと思うとサンプリング数がかなり増加して速度に問題が発生します。

最後の問題点は縮小バッファが使えないことです。
ガウスブラーは画面をぼかしてしまうので、低解像度でもさほど問題ない場合があります。
カラーの2乗を行う際に縮小バッファに描画し、これをガウスブラーするのであればより高速ですが、ポストプロセスマテリアルではそのようなことが不可能です。

今回の実装はボカシの綺麗さだけではなく、速度的にも解像度によっては有利です。
こちらは比較的高解像度での処理速度比較です。

ue412.jpg

DiffusionPow2~Diffusionまでが今回入れた処理です。
2乗カラーをガウスブラーしてダウンサンプルしてガウスブラー…という感じでガウスブラーを3回行った結果をぼかし画像として使用しています。
合計が0.57msでその下にあるポストプロセスマテリアルでの実装より少しだけ高速です。
ただし、解像度が低い場合はポストプロセスマテリアル実装のほうが高速です。
もちろん、クオリティはエンジン改造のほうが高いですね。

というわけで、続きからこの実装方法について書いていきます。
なお、.usf, .h, .cppファイルをそれぞれ1つずつ追加している点にご注意ください。
追加してプロジェクトに登録する方法は書いていません。

[[UE4] エンジンを拡張してポストプロセスを実装する PS編]の続きを読む
  1. 2016/12/15(木) 00:04:29|
  2. UE4
  3. | トラックバック:0
  4. | コメント:0

[UE4] UE4プロジェクトでVisual Studioのグラフィクス診断を使用する方法

ちょっと小ネタ。

Visual Studioには標準でグラフィクス診断という機能が備わっています。
その昔、DirectX SDKにはPixというツールが存在していました。
このツールはDirectXの描画が何をやっているか、どれくらい時間がかかっているかなどを調べるのに大変重宝するものでした。
現在、DirectX SDKはVisual Studioに統合されており、Pixもなくなってしまいました。
その代わりにVisual Studioが標準で診断機能を追加しているというわけです。

グラフィクス診断そのものの使い方はここでは述べませんが、Visual Studio 2015でグラフィクス診断をするには、C++プロジェクトをビルド後、[デバッグ] → [グラフィックス] → [グラフィックス デバッグの開始] を選択します。
通常はこれでグラフィクス診断が起動し、PrintScreenボタンでそのフレームの診断が可能です。
しかし、いつのバージョンからかはわかりませんが、UE4ではグラフィクス診断を起動すると以下のウィンドウが表示されてアプリが停止します。

ue410.jpg

これはデバイス作成時の設定が原因となっているようで、現状ではこのままグラフィクス診断を使用できません。
使用するにはエンジンコードを書き換える必要があります。
書き換え自体は非常に簡単で、以下のように修正します。

Engine/Source/Runtime/Windows/D3D11RHI/Private/Windows/WindowsD3D11Device.cpp (338)
// Add special check to support HMDs, which do not have associated outputs.
// To reject the software emulation, unless the cvar wants it.
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb205075(v=vs.85).aspx#WARP_new_for_Win8
// Before we tested for no output devices but that failed where a laptop had a Intel (with output) and NVidia (with no output)
//const bool bSkipHmdGraphicsAdapter = bIsMicrosoft && CVarExplicitAdapterValue < 0 && !bUseHmdGraphicsAdapter;
const bool bSkipHmdGraphicsAdapter = false;

この bSkipHmdGraphicsAdapter が false になっていればOKです。
これをビルドして、ここからC++プロジェクトを作ればグラフィクス診断が行なえます。

なお、この修正方法はUE4.14にて有効な手法です。
他のバージョンでは少々異なるかもしれませんが、大抵はこのソースファイルを調べれば対応できるでしょう。

RenderDocを使うというのも1つの手段ですが、これはどうもプラグインを入れる必要があるので、プラグインなしでグラフィクスの調査をしたい場合はこの書き換えを行った上で診断してみましょう。

  1. 2016/11/23(水) 23:38:55|
  2. UE4
  3. | トラックバック:0
  4. | コメント:0

[SD] PBRユーティリティ

TL上で少し話題になったPBR対応テクスチャがSubstanceDesignerで作れるかどうかという話。
実はPBR対応のテクスチャを作成するためのユーティリティがSDにはいくつか存在しています。
今回はそれらのノードの話を。

PBRに対応するとは?

そもそもPBR対応というのは、例えば石なら石として正しい色になっている、ということではありません。
石と言っても種類は色々ありますし、同種の石でも成分に違いは出ます。
同じ花崗岩でも瑞牆と小川山では色味の違いは出ますし、表面の凹凸も変わってきます。同じ山でも場所が違えば違ってきます。
どうしても瑞牆の花崗岩を再現したい!というのであれば、瑞牆に行って岩の写真を撮影するしかありません。

ではPBR的に正しいテクスチャとは何かというと、アルベドであれば黒の下限と白の上限です。
RGBすべての成分が0、RGBすべての成分が1という黒と白は現実には存在しません。
前者はすべての光を完全に吸収するのでブラックホール化何かでしょう。
後者は拡散反射なのに光を完全に反射します。ホワイトホール?いや、まあ、普通にないですね。

また、金属であれば純金属はその反射率がすでに求められています。
純度100%でなければ変化はするかもしれませんが、基本的には求められている反射率で問題ないはずです。

つまり、PBR的に正しいということと、特定の物体(瑞牆の阿修羅岩とか)の色が正しいというのは別の問題だということです。
特定物体の完全に正しい色がほしい、というのであればフォトスキャンするしかありませんが、そこまで特定の何かがないのであれば物理的に間違ってない値を使って目合わせでもいいんじゃないかな、と思っています。

もしも特定物体の正しい色がほしいのだ!という方はポリフォニーの内村氏が今年のCEDECで解説してた色彩工学の資料をお読みください。

http://d65.xyz/cedec2016

では、各ノードを解説していきます。
これらのノードは[Material Filters]->[PBR Utilities]の中にあります。

BaseColor/Metallic/Roughness converter

sd152.jpg

SDでは通常、BaseColor/Metallic/Roughness のパラメータでマテリアルを作成します。
しかしそれとは別に Diffuse/Specular/Glossiness のパラメータでマテリアルを作成するシステムも有ります。
このノードは通常の BaseColor/Metallic/Roughness で作成されたマテリアルを別のマテリアル表現に変換してくれます。
どのような種類があるかというとこんな感じ。

sd157.jpg

Diffuse…以外にも、VrayやArnoldといったレンダラにも対応しています。
あまり使う機会はないかもしれませんが、今までBaseColor方式で作っていたマテリアルを急遽別のシステムに出さなきゃいけないという場合には重宝するかもです。

PBR Albedo Safe Color

sd153.jpg

上でも書きましたが、PBRにおいてアルベドの黒と白は完全な黒と白にはなりません。
このノードはそのような黒や白を妥当は範囲にクランプしてくれるノードです。
例えば全て0の真っ黒を繋げるとこうなります。

sd158.jpg

グレーっぽくなっているのがわかりますよね。
なお、入力ピンの下の方はMetallicです。完全金属の場合はBaseColorは素通りされます。
そのような場合は本来何を入力しても真っ暗にしたほうが良かったのでは?と思ったり思わなかったり。
パラメータでDiffuseモデルにも変更ができます。

また、Torleranceパラメータで許容誤差を変動させることが出来ます。
このパラメータが0なら50 sRGBに、逆に1なら誤差とを大きく持って30 sRGBくらいまではクリッピングされません。
まあ、非金属のマテリアルを作って、その際にBaseColorに自身が持てないような場所に使う機能という感じでしょうかね。

PBR BaseColor/Metallic Validate

sd154.jpg

このノードも前者と同じようなノードですが、こちらはBaseColorをクリップしたりしません。
このノードの場合はBaseColorにミスがある部分が赤くなります。PBR的に正しい場合は緑です。

sd159.jpg

[Level]ノードでレベルを変更した結果として溝の部分が白飛びしています。
これがPBRのミスです。
この結果を利用して赤くなっている部分のベースカラーをマスキングすることも可能です。
目合わせでマテリアルを作っている場合は最後にこのノードを通して問題ないかだけは調べておく方がいいと思います。

PBR Dielectric F0

sd155.jpg

非金属物体の一部を選択してフレネル反射係数 f0 を取得します。
f0が求まるとIORなんかも求められますが、[Custom IOR] を利用すればIORから係数を求めることが出来ます。
何に使うの?と言われると、まあ、ちょっと困るねw

選択できる物体はこんな感じです。

sd160.jpg


PBR Metal Reflectance

sd156.jpg

最後はこちら。金属の反射率を金属の種類に応じて取得できるノードです。
今まではDONTNODのチャートを利用していたのですが、こちらを使ったほうが簡単でしょう。
何が選べるかは以下のようになっています。

sd161.jpg

代表的な金属は網羅されているかと。

というわけで今回はここまで。
  1. 2016/09/02(金) 02:06:12|
  2. Substance Designer
  3. | トラックバック:0
  4. | コメント:0
次のページ

プロフィール

Author:monsho
ゲームプログラマ?

最近の記事

最近のコメント

最近のトラックバック

月別アーカイブ

カテゴリー

ブロとも申請フォーム

この人とブロともになる

ブログ内検索

RSSフィード

リンク

このブログをリンクに追加する

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。