月別アーカイブ: 2013年12月

A Reconstruction Filter for Plausible Motion Blur について

テストを兼ねて実装してみました。

[参照]
A Reconstruction Filter for Plausible Motion Blur

ScatterとGatherについて

Blurを適用する際に考えられる方法として、自身のPixelのVelocityに従って、自身のPixelの色を他のPixelに拡散させる方法(Scatter)と、周辺のPixelの色とVelocityに従って、自身のPixelに周辺のPixelを重畳させる方法(Gather)の二つが考えられます。
Scatterの演算は、GPUの処理に置き換えれば、多数のPixelのBlending処理に置き換えられます。メモリの書き込み負荷が高いことが容易に想像がつきます。
一方で、Gatherの演算は、Blurの適用半径を大きくすれば、周辺の多数のPixelをSamplingしなければならず、メモリの読み込み負荷が高いです。また、Gather演算の場合は、SampleしたPixelのVelocityが小さかったり、向きが関係ない方向の場合は、対象PixelにBlurが届かず、Sampling処理自体が無駄になります。

本手法は、Gather手法ですが、周辺のPixelに対して一様にSamplingを行う代わりに、周辺に存在する、一番大きいVelocityを代表として、そのVelocityに基くSamplingを行うことで、Gather手法を用いつつも少ないSampling数で、大きなBlurの適用半径を実現するものです。

Tile Max と Neighbor Maxについて

上記で説明した、周辺に存在する、一番大きいVelocityを検出するために、この2つのバッファを作成します。まず、screen spaceにおけるVelocity Mapが存在するか、算出可能なことが前提です。
Tile Maxは、Blurの最大半径に相当する大きさを単位としてTileを作成し、それぞれのTile内で、Velocityが最大のVectorを保存します。従って、Tile Maxバッファの解像度は、(w,h)/size_of_a_tileとなります。
Neighbor Maxは、自身のTileと隣接する周辺8つのTileの中で、Velocityが最大のVectorを保存します。
後に、Gather演算を行う際に、該当するNeighbor Maxに格納されているVectorを参照すると、”周辺に存在する最も大きなVelocity”を取得することが出来ます。
本手法では、Neighbor Maxに格納されるVectorを”周辺で支配的に作用するVelocity”と見做し、BlurのReconstruction処理を、このベクトルに基いて行います。

Reconstruction処理について

Reconstruction処理では、Neighbor Maxに格納されているVectorに沿って、[-1,1]の範囲で直線上をサンプリングします。(ただし、Ghostingを避けるためにJitteringしています)
SamplingしたPixelと、基準となるPixelのZ値を考慮しつつ、互いにBlurで滲出する量を計算して最終結果としています。(詳細は論文参照のこと。pseudo code付きで解説されています。)

Samplingの際のアクセスパターンは、周辺のTileを共有するPixelで一様なので、Samplerのキャッシュヒットは大いに期待できます。
Blurの半径を大きくすれば、キャッシュのヒット率は低下すると思われますが、Sampleの数を増やせばヒット率が上昇すると思われます。各GPUの特性やそれぞれの状況に応じて調整できると思います。

考察

まず、Tile Max の算出には、Compute Shaderを用いるのが最も適切と思われます。Vectorの長さは常に正なので、uintキャストしてAtomicMaxのパターンです。
一方で、CSの使えない環境下では、PSでMipMapへの畳み込みを行う必要があると思います。
Neighbor Maxも同様の方法で求めることが出来ますが、周辺3×3のSamplingなので、1Threadで3×3ブロックをサンプリングして、比較したほうが速いです。
ここでは、PSを使うかCSを使うか迷うところなので、確かめるために実装してみました。しかし、Neighbor Maxを求めるための同機能のシェーダーコードをPS,CSに実装し、実行時間を比較をGTX680で行ってみましたが、有意な差は見出せませんでした。
したがって、どちらを使っても問題なさそうです。(使用したCSのnumthreadは[4x8x1]です。)

Blur

ちなみにこの論文の手法を元に改良した手法が既に発表されています。
[参照]
A Fast and Stable Feature-Aware Motion Blur Filter

広告

Weighted Blended Order-Independent Transparencyについて

要点だけですが。
例によって、詳しくはオリジナルを参照して下さい。

[参照]
Weighted Blended Order-Independent Transparency

3. Blended OIT

特殊なBufferやSortingを用いずに、幾つかの演算とRenderStateにあるBlendFunctionで、OITを実現する。

3.1. Meshkin’s Method

Pre-Multipliedの半透明オブジェクトの色とAlpha値を、それぞれ全て加算し、その背景となる不透明色と、最後に1度だけAlphaBlendを行う。
Alphaの値が小さく、色が似ている場合の結果は良好(SortしてAlphaBlendした場合に似てる)だが、Alphaの値が大きくなるにつれ、SortしてAlphaBlendした場合との結果の相違が顕著となる。(Eq.3)

3.2. Bavoil’s and Myer’s Method(2008)

上記 Meshkin’s Methodに“weighted average” オペレーターを導入。
(1-(Alphaの平均値))^(半透明の枚数)を、全体の透過度として計算。
半透明色は、Alphaの加重平均で計算し、算出した透過度を基に、 最後に1度だけ不透明色とAlphaBlendする。(Eq.4)

3.3. A New Blended OIT Method

上記の手法は、Alpha=0,Color=0の完全透明オブジェクトが、計算結果に寄与してしまうのが問題だった。
本手法では、(1-Alpha)の総乗を、全体の透過度として計算する。
半透明色は、上記手法と同じくAlphaの加重平均で計算し、算出した透過度を基に、最後に1度だけ不透明色とAlphaBlendする。(Eq.5)

3.4. Depth Weights Improve Occlusion

上記3.3で求められる、半透明オブジェクトのColorは、単純なAlphaによる加重平均なので、深度による順番に関わらず、Alphaの値が高いものが支配的である。
半透明色の計算に、単純なAlphaの加重平均だけではなく、深度値に基づくWeight関数を導入し、同等のAlpha値なら、視点により近いものの寄与度が高くなるように計算する。
具体的には、AlphaとWeight関数を乗じたもので加重平均をとり、半透明色とする。(Eq.6)
論文内ではWeight関数は4種類提案されている。(Eq.7,8,9.10 Fig.3参照)

考察

半透明Sortの手間を省いて、Poppingなどの目立つアーティファクトを回避できるので、有効な手段だと思います。少なくとも、算出される透過度(一番後ろにある、Opaqueの寄与度)の計算については、半透明オブジェクトのAlpha値を、不透明の確率関数的に捕らえた場合はこれで正しい結果になると思います。
半透明オブジェクトの色に関しては、本来Order DependentのものをIndependentにしているので、Approximationが含まれるのは仕方が無いと思います。
Weight関数は深度の関数となっているので、オブジェクトの位置関係が不変でも、カメラの位置が変わり、深度値が変化することで、計算結果が変化するので、静的な半透明オブジェクトの描画には不向きかもしれません。Weight関数をExponential Shadow Mappingの様に、exp()関数を用いれば、カメラとの相対的な位置の変化が起きても、一定の演算結果が得られると思われますが、本論文中では、FP16で扱いやすい範囲に重きを置いて議論されているようです。従って、ハードゥエアの性能や特性などに応じて、Weight関数に関しては考察の余地が残っているかもしれません。

Avoiding Texture Seams by Discarding Filter Tapsを読んでみた

[参照]
論文とsupplemental
Avoiding Texture Seams by Discarding Filter Taps

Traversal method(下記参照)
Eliminating Texture Waste: Borderless Realtime Ptex

概要

IntelのRobert Toth氏の論文です。趣旨としては、Texture,UV空間が非連続なエッジ上において、比較的低コストで、Texture Samplingの非連続性によるアーティファクトを回避する手法です。

前提条件

対象Primitive(ポリゴン)のUVの範囲外が、Samplerによってclampされる必要があります。従って、従来型のtexture atlas的な貼り方をされたモデルには、本手法は適用出来ないと思われます。
適用可能な例としては、realtime P-tex用のモデルの様に、quad mesh化された上に、Texture2DArrayでquadごとにTextureがアサインされたものになると思われます。
加えて、MSAAによるresolveによって、seamless化の代わりとなる演算(補間)を行うため、MSAAが必須となります。従って、MSAAのSubSampleの数によって、その品質が変わります。

アルゴリズム

通常は、Texture,UVが切り替わる境界エッジでは、互いに、エッジを共有する他方のPrimivieに貼られたTextureの情報を取得しないと、Primitiveの境界上でFilteringを伴うTexture Samplingを行うことは出来ません。(論文中ではこの手法をTraversal methodと呼んでいる)
しかし、本手法では他方となるPrimitiveのTextureの情報を取得しません。
まず、自身ののTextureの情報を格納する際に、BorderColorを0に設定し、Primitiveの範囲外の領域がサンプリングされた場合に0になるようにします。加えて、同解像度の1チャンネルテクスチャ(もしくは、空いているチャンネル)に1.0を格納しておき、こちらもBorderColorを0に設定しておきます。
TextureをSamplingする時は、Sampleした値を、1.0が格納されたTextureをSampleした値で除算することで、正規化を行います。このように計算することで、Sampling時のFilteringによって、UVがPrimitiveの範囲外となった領域の参照をDiscard(無効化)します。
一方、他方となるPrimitiveに貼られたTextureの情報は、自身が被覆しなかったSubSampleに、同様の計算を行った値が格納されていると仮定します。
最後にMSAAをResolveすることで、被覆したSubSampleの数に応じた補間が行われ、補間されたTextureのSampleが計算されるということになります。

計算式について

論文上の計算には、Texture境界で発生する複数のTextureを跨ぐFilteringを、MSAAのResolveに置き換えて考えるという大胆な近似が行われています。
しかし考え方を変えれば、単に、自身のPrimitiveに関する計算を、自身の範囲に限定して行っているに過ぎないと考えることも出来ると思います。しかし、当然そのままでは、全てのPrimitive境界で非連続なシェーディングとなりますが、MSAAがその非連続性を補間して、視覚的な不都合を解消していると考えられます。(逆にいえば、計算上の不都合は解決していないと言えると思います。)

考察

Traversal methodを使用する場合は、通常のSamplingに加えて、対象のQuadの上下左右の計4つを余分にSamplingしなくてはなりません。対して、Discard methodを用いる場合は、1点のみのSamplingで解決可能です。
Traversal methodは、Anisotropic Filteringに対しても正しく対応可能ですが、Discard methodはAnisotropic Filteringを使用した際に、異方性が大きくなると誤差が大きくなる可能性があります。
Discard methodは、補間をMSAAのResolveに頼っているので、Pixel境界にPrimitiveの境界が一致した際はMSAAの効かないのでseamが露呈するはずです。一方、Traversal methodはPrimitiveの位置の変化によって品質は変化しないと思われます。
Discard methodは、Texture Samplingのfilter kernelがMSAAに置き換わったと考えることが出来ると思います。従って、実際のfilter kernelとPixelのサイズが著しく異なる状況では、高品質を得るのは難しいかもしれません。
論文中の両手法の実行時間を比較した表では、GTX680/IrisPro5200両方とも、MSAAのSample数を増やしていくに従って、実行時間の差が縮まっていきます。(GTX680では、1xで2倍以上あった実行時間の差が、8xで37%に)
Discard methodを高品質で行うためには、MSAAのSample数がある程度必要なため、手法の変更によって大幅な実行時間の短縮を期待する場合は、注意が必要だと思われます。
Discard methodのレンダリング結果は、論文と一緒にポストしてある、supplementalに入っているムービーを見る限りでは、良好だと思います。本手法はMSAAを活用した手法ですが、奇しくもMSAAそのもの(レンダリングの計算としては正しくないが、結果は良好)の特性に通じるものがあると思います。