エンジンを拡張してポストプロセスを実装する 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という描画パスについては後にご説明します。

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

続きを読む

エンジンを拡張してポストプロセスを実装する 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プロジェクトでVisual Studioのグラフィクス診断を使用する方法

ちょっと小ネタ。

Visual Studioには標準でグラフィクス診断という機能が備わっています。

その昔、DirectX SDKにはPixというツールが存在していました。

このツールはDirectXの描画が何をやっているか、どれくらい時間がかかっているかなどを調べるのに大変重宝するものでした。

現在、DirectX SDKVisual 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つの手段ですが、これはどうもプラグインを入れる必要があるので、プラグインなしでグラフィクスの調査をしたい場合はこの書き換えを行った上で診断してみましょう。

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

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

というわけで今回はここまで。

特定の位置にパターンを表示する方法

今回紹介するのは入力画像の特定条件にあるピクセルにのみ指定パターンを表示する方法です。

[Tile Sampler] ノードにはランダムに配置したパターンがグレースケールの白の部分にのみ表示されるようにする機能があります。

この記事ではその簡易バージョンを作る方法を提示します。

簡易バージョンなのでもう少しちゃんと作らないと実用的にはならないのですが、仕組みがわかっていれば [Tile Sampler] ノードから該当部分を抜き出すこともできるようになるんじゃないでしょうか?

まだ自分はできていませんが、そのうちやる予定。

この処理には [FX-Map] を使用します。

このノードはSDでは唯一ループ処理を行うことが出来るノードであり、今回のようにパターンを複数回散りばめるのには大変便利です。

特定パターンを複数表示するノードとしては先に紹介した [Tile Sampler] も含まれるタイル系やスプラッタ系がありますが、これらは内部で [FX-Map] を使用しています。

まずは準備をしましょう。以下のようにノードを作成します。

sd144.jpg

[Image Input 0] に入力された円が今回は散りばめるパターン、[Image Input 1]に入力された三角が表示位置を示す画像とします。

[FX-Map] ノードの [Color Mode] はグレースケールに変更しておきましょう。

次に入力パラメータを追加しておきます。以下のように作成します。

sd145.jpg

[tile_num_x/y] はXY座標のタイルの数で、この数値分画像が分割されます。

[gray_threshold] は [Image Input 1] の該当ピクセルがこの値以上の場合にパターンを表示するようにするためのしきい値です。

では、[FX-Map] を選択し、[Ctrl + E] で内部に入っていきましょう。

内部は以下のようにします。

sd146.jpg

最初から入っている [Quadrant] ノードの上に [Iterate] ノードを配置し、これをルートとします。

[Iterate] ノードがループ処理を行うノードで、このノードの [Iterations] パラメータで指定した回数だけ [Quadrant] ノードが実行されます。

[Iterate] ノードを複数繋げて多重ループも実現できるのですが、繰り返し回数を変数として取得できるのはその変数を使用したノードより手前直近の[Iterate]ノードのみです。

つまり、多重ループのそれぞれのループ回数は取得できません。

今回はそれでは困るので、1回のループで2重ループと同じ効果を出すようにします。

[Iterations] パラメータを空の関数とし、内部を以下のように作成します。

sd147.jpg

タイルのXYの整数を乗算して出力します。

例えばX=2、Y=2であれば4回ループとなります。タイル数分だけループするわけですね。

次に [Quadrant] ノードの処理を行います。

パラメータを変更するのは [Pattern] を [Input Image] に変更するだけです。

あとは各種パラメータの関数内部で処理を行うことにします。

まずはタイル上にパターンを配置しなければなりませんので、その処理を作成します。

[Branch Offset] のパラメータを関数化し、内部に入りましょう。

この関数は以下のように実装します。

sd148.jpg

(クリックで拡大)

ちょっと複雑でわかりにくいかもしれません。

まず左下のブロックはタイル1つ分の幅と高さを求めています。

タイルの分割数がXYともに2ならここで求められる値は(1/2, 1/2)=(0.5, 0.5)となります。

右下のブロックはパターンを左上ピッタリに配置する場合のオフセット値を求めています。

最後に上のブロックで繰り返し回数からXYのタイル座標を求め、それに見合った左上からのオフセット値を求めます。

これを右下のブロック(つまり左上のオフセット座標)に加算することで、繰り返し回数に依存したパターンのオフセット値を求めることが出来ます。

しかしこれだけでは大きなパターンが移動するだけです。サイズも適切なサイズに変更する必要があります。

この処理を [Pattern Size] パラメータ内に作成してもよいのですが、実はパターンサイズとして利用するパラメータは左下ブロックの結果と同等だったりします。

同じ計算を何度もやるのは面倒です。なので、この結果をローカル変数に設定します。

上の図の真ん中に [Set] ノードがあります。これは指定名(ここでは [pattern_size])のローカル変数を作成し、そこに値を格納しています。

この [Set] ノードで設定した値を使用するにはいくつかの条件が存在します。

1つ目の条件は、この値はこの関数を持ったパラメータが所属しているノード内でのみ有効です。

つまり、この場合は [Quadrant] ノードでのみ使用可能です。

使用する場合は [Get ~] ノードを使用しますが、同一関数内以外ではドロップダウンリストに表示されないのでて入力する必要があります。

2つ目の条件は [Set] ノードを利用したパラメータ以下のパラメータの関数内でしか使用できません。

今回の場合は [Branch Offset] 内部で使用しているため、この関数内部か、そこから下の [Quadrant] ノードのパラメータでしか利用できません。

つまり、[Color / Luminosity] パラメータの関数内では使用できないということです。

3つ目の条件としては [Set] ノードを有効にするには出力ノードとして設定したノードに対する処理の途中で挟む必要があるということです。

これについては後で説明します。

さて、ここで [pattern_size] というローカル変数にパターンサイズとして利用できる値が入力されましたので、[Pattern Size] パラメータの関数内でこれを使用しましょう。

[Pattern Size] パラメータを関数として、内部を以下のように設定します。

sd149.jpg

ここまで処理を作成すれば綺麗なタイル状に円が敷き詰められるはずです。

しかし、これからが本番。[Input Image 1] のイメージに従ってしきい値以上のグレーならパターンを表示するようにしましょう。

これを実現するにはタイル状に敷き詰められた各パターンの中心のピクセルを [Input Image 1] から取得し、この値がしきい値以上かどうかを確認、しきい値未満であれば [Pattern Size] を0にするという手法を取ります。

そのような加工をした結果が以下となります。

sd150.jpg

(クリックで拡大)

右上の部分がパターン中心のイメージのピクセルをサンプリングし、これがしきい値以上かどうかを調べている部分です。

しきい値以上であれば加工前の [pattern_size] 出力を選択し、しきい値未満であれば (0, 0) を選択します。

この選択結果を [pattern_size] に入力していますが、その後に [Sequence] ノードに繋げるようにしています。

なぜこのようにするのかというと、これまで通りに下部の加算部分を出力ノードとして選択してしまうと、その結果を求めるのに [pattern_size] への入力は通る必要がなく、SD内部で不要なノードとして無視されてしまうのです。

関数の出力には影響を与えないが処理されなければ困る、という今回のような場合には確実に処理が行われるようにするために [Sequence] ノードを使います。

このノードの入力ピンは上が [In]、下が [Last] となっていますが、出力されるのは [Last] ピンに入力された値です。

[In] に入力された値はこれ以降ではどこからも参照されませんが、処理だけは走ります。

これが [Set] ノードを使う条件の3つ目の回避方法です。活用していきましょう。

このようにノードを組み、[gray_threshold] を 0.5 に設定すると、三角形の形状で円が表示されるはずです。

円の数が少ないようでしたら [tile_num_x/y] の値を大きくしてあげましょう。

タイルの数がXYともに16の場合は以下のような結果となります。

sd151.jpg

最後に注意点を。

[Quadrant] ノードの [Pattern] はパラメータの関数化も出来ますし、関数内部で固定値 0 を出力すると [No Pattern] を選択されたように表示が消え、1 を出力すると [Input Image] が選択された状態となり円が表示されます。

パターンの表示/非表示はこちらでやるべきではないのか?

そう考えて [Pattern Size] を0にする方法でなく、[No Pattern] を利用した形で表示/非表示を切り替えられるようにしてみました。

しかし残念なことにこれはうまくいきませんでした。

なぜそうなっているのかはわからないのですが、どうやら [Pattern] の関数に対してはイメージのサンプリングが出来ないようです。

何か見落としてうまくいっていないだけなのかもしれませんが、私が試した際にはうまくいきませんでした。

注意しましょう。

Weighted Blended OITの実装

今回はWeighted Blended OITと呼ばれる技術をUE4のエンジンコードを改造して実装する話です。

エンジンコード改造となりますので文字多めです。

・OIT(Order Independent Transparency)とは?

OITとはOrder Independent Transparencyの略です。

順序に依存しない半透明、というような意味ですが、ほぼそのままの意味です。

知っての通り、半透明を描画する際には描画順序が重要になります。

大抵のシステムではメッシュ単位などでZソートを行い、画面の奥のメッシュから順番に描画していきます。

この手法はほとんどどんなシーンでも有効に働きますが、一部のシーンではうまくいきません。

わかりやすいのは半透明メッシュが入れ子構造になっている場合です。

半透明のグラスの中にやはり半透明のウィスキーが入っている、という場合、正しい描画順序はグラスの奥→ウィスキー→グラスの手前となります。

しかしメッシュ単位での描画となるとウィスキー→グラス、もしくはウィスキー入りグラス1回で描画、という事にもなります。

後者はどうしようもないとして、前者はグラスの奥側を正しく描画できないので、グラスの奥は描画しないなどの措置がとられるのではないかと思います。

ゲーム中のちょっとした小物くらいならそれでもいいかもしれません。

しかし、昨今のゲームは大変映像が綺麗になっていて、カットシーンなどでも高解像度です。

また、ゲームエンジンを利用した建築ビジュアライゼーションなども需要が出てきています。

このような状況で半透明の順番を正しく考えなければならない、そういうデザインを心がけなければならないというが難しくなってきているのは否定できません。

OITを実装しているゲームはほとんどないのが現状ですが、非常に高い優先度とはいえないまでもあったら欲しい機能と考えられているのではないでしょうか?

・Weighted Blended OITとは?

OITの実装としてはLinkListを利用したものが最も有名なのではないかと思います。

手前味噌ですが、私も以前実装したサンプルをアップしています。

DirectXの話 第110回

この手法は新生トゥームレイダーララ・クロフトの髪の毛の表現で使用されていましたが、やはり速度面で苦労していたようです。

正確に表現しようとするとこの手法は正確な半透明の順番を守ることが出来ます。また、トゥームレイダーでは順番を完全に正確に守らずに高速化を図っていたと記憶しています。

ある程度のスケーラビリティを持っていると言っても重いものは重い。

実装も比較的面倒ですし、このサンプルを作成した段階ではRadeonのドライバのバグで正常に描画されないこともありましたしね…

今回紹介するWeighted Blended OITは比較的軽く、実装も容易です。

Weighted Blended OITのペーパー

しかしかなり大胆に近似している手法であるため、正確な半透明表現はできませんし、使用の際には注意が必要です。

概要を簡単に説明してしまうと、半透明が重なった際に、その色が最終的な映像にどの程度影響を及ぼすかを重み付けして最後に正規化するという手法です。

と言ってもわかりにくいと思いますので、実例で解説します。

不透明メッシュ描画完了時、フレームバッファにはCsというカラーが描かれていたとします。

ここに(C1, A1)という半透明カラーが描画されたとしましょう。なお、Cはカラー、Aはアルファです。

それよりも手前に今度は(C2, A2)という半透明カラーが描画されます。

終結Cfは以下のような計算になります。

Cf = C2 * A2 + (C1 * A1 + Cs * (1-A1)) * (1 - A2) = C2 * A2 + C1 * A1 * (1 - A2) + Cs * (1 - A1) * (1 - A2)

アルファ値は0.0~1.0で、アルファ値同士の乗算(A1 * (1-A2)(1 - A1) * (1 - A2))は1.0を超えることはありません。

アルファ値に着目すると、最終結果により強い影響を与えるのはアルファの乗算結果が大きいカラーということになります。

つまり、A2が大きければC2の影響が大きくなり、A1が大きければC1の影響が大きくなります。

両方小さければCsの影響が大きくなります。

今度はA1 = 0.5A2 = 0.5とした場合の結果を計算してみましょう。

Cf = 0.5 * C2 + 0.25 * C1 + 0.25 * Cs

アルファ値が固定の場合、最後に描画されたC2の影響が大きくなります。

より一般的に考えると、深度が手前の半透明カラーの方が影響を与えやすいということです。

つまり、アルファ値が大きければ大きくなる、深度が近ければ大きくなる、という感じの関数 w(a, z) を作成し、これによって各半透明カラーの影響度を求める、というのがこの技術です。

弱点としてはあくまでも各カラー単体でのブレンドウェイトしか求められないため、前後関係などを正確に表現できるというわけではない点です。

そのため、画像処理ソフトで求められたブレンドの結果はこの技術で再現することはほぼ不可能です。

また、ウェイト関数によってはカメラの移動に対して結果が安定しません。

安定させようとすると今度は小さな距離の差がほとんど無視される結果になります。

入れ子構造の半透明ではまともな結果が得られないでしょう。

と、このように制約も大きな技術ではありますが、限定的な使用方法なら用途もあるんじゃないでしょうか?

…あるかなぁ?

それはともかく、続きからでソースコードの改変を行っていきます。

続きを読む

Substance Player

今日知った小ネタ。

Substance Playerというツールが有ります。

SubstanceマテリアルをViewingするためのツールなのですが、こちらから無料でDLすることが出来ます。

https://www.allegorithmic.com/download/download_free/6

このツールは.sbs, .sbsarを開くことが可能で、パラメータを変更することも可能です。

ただし保存はできません。パラメータを調整して保存する機能はありません。

もちろん、.sbsファイルのノードを変更することも出来ません。

しかし画像データとしてエクスポートは出来ます。

ライセンス的に問題がないSubstanceマテリアルであれば無料でテクスチャ画像が取得できるわけです。

さて、ここからが本題。

Substance DesignerではパラメータやPixel Processorの変数として時間を取得することが出来たりします。

[Get Float]ノードを関数内に配置し、プルダウンメニューから"$time"を選択するだけです。

しかしこの時間、SD上では確認する術はありません(少なくとも自分は見つけられませんでした)。

しかし、Substance Playerなら確認可能なのです。

そこで今回はいわゆるFlowMapを確認するためのSubstanceマテリアルを作成してみました。

以下からDLできるようにしています。

https://dl.dropboxusercontent.com/u/39588440/Substance/FlowMap.sbs

マテリアルの中身はこんな感じ。

sd140.jpg

下のPixelProcessorの中身はこんな感じです。

sd141.jpg

仕組みとしてはほんとに単純なFlowMapです。

入力画像とFlowMapは外部から与えることも可能ですが、デフォルトでは入力画像はチェッカー、FlowMapは回転するようにPixelProcessorで作成したものです。

では、これをSubstance Playerで読み込んでみます。

sd142.jpg

Substance Playerはこのようになっています。B2Mっぽい見た目ですね。

右側がパラメータで、入力画像とFlowMapは外部から読み込むことも出来ます。

下の方を見てください。

タイムラインと書かれている部分があるのがわかりますね?

この一番左の再生ボタンを押すと"$time"変数がタイムラインにそって変更されます。

これがPixelProcessorで使用されているので、FlowMapが正しく動くことになります。

また、テクスチャエクスポート時にタイムラインに沿って出力することが可能です。

sd143.jpg

[ビットマップでエクスポート]ボタンを押すとこのWindowが表示されます。

上の赤枠部分が時間に関するパラメータで、時間単位、開始・終了フレーム、FPSを指定することが出来ます。

これを利用することでプロシージャルなフリップブックアニメーションを作成することも出来るでしょう。

というわけで小ネタでした。