穴日記

どうだ明るくなったろう

enokiで遊んでみた(Visual Studio 2017編)

これはレイトレアドベントカレンダー2019の記事です。
https://qiita.com/advent-calendar/2019/raytracing


https://enoki.readthedocs.io/en/master/

enokiというのは最近公開されたC++テンプレートライブラリで、SIMDやCUDAによるベクタライズを抽象的にサポートした算術ベクトルライブラリとなっており、自動微分も可能なものになっています。SIGGRAPH ASIA 2019で発表されたMitsuba2(https://rgl.epfl.ch/publications/NimierDavidVicini2019Mitsuba2)はenokiを全面的に採用しており、SIMDによる"wide"なレンダラを容易に記述できる、Differentiable Rendererを容易に記述できる、といった恩恵が得られると主張しています。

以下は上記オフィシャルページからのコピペですが、以下の様なsRGB Gammaのコードを

float srgb_gamma(float x) {
   if (x <= 0.0031308f)
      return x * 12.92f;
   else
      return std::pow(x * 1.055f, 1.f / 2.4f) - 0.055f;
}

以下のようにenokiスタイルに書き換えると

template <typename Value> Value srgb_gamma(Value x) {
   return enoki::select(
      x <= 0.0031308f,
      x * 12.92f,
      enoki::pow(x * 1.055f, 1.f / 2.4f) - 0.055f
   );
}

コンパイルターゲットをSSE4.2、AVX2、AVX512などに変えることで自動的にバックエンドでSIMD化されて高速なコードが生成されるという寸法です。
やってることとしては、各種オペレーターをオーバーロードしてSIMD intrinsicをラップしている感じではあるのですが、そういう典型的なコードを包括的に実装してくれています。
また、各種数学関数(powとか)のSIMD用実装も提供しているので、そのあたりも便利ですね。

で、CPU向けのSIMDラッパライブラリとして使う分には必要なヘッダをインクルードするだけで使えます。
ここから、GPU向け(CUDA向け)ライブラリとして使ったり、自動微分機能を使ったりするには、いくつかのcppファイルをコンパイルする必要がでてきます。
また、CUDAを実行するにはCUDA toolsetなんかもインストールする必要があります。

思想としては、上記のようなスタイルで抽象的にアルゴリズムを記述したら、あとはenokiがよしなにしてくれて、CPU SIMDからCUDA、自動微分まで何もかもサポートされる!というものです。
が、現実には、たとえばCUDAサポートしようと思うとCPU SIMDむけのenoki::Arrayとは別のenoki::CUDAArrayが用意されてたりして、完全にenokiレイヤで抽象化されてるわけでもないです。(まあ自前で抽象化してもいけそうではありますが)
一方で、SoAデータ構造をストレートに記述できたりするあたりは賢い感じします。(例えば、enoki::Array< enoki::Array, 3>でRGB x 16のSoAになる)

導入(SIMDライブラリ部分)

基本的にLinuxターゲットぽいんですけどgithubリポジトリをみるとWinビルドもテスト通っています。
なので、Win上でVisual Studio使ってみます。
最初はVS2019使ってみたんですけど、途中でビルドエラーが解決困難になったので、VS2017を使いました。

まず、ビルドにはcmakeが必要なので最新バージョンをインストールします。
githubからenokiの最新のリポをcloneして、以下コマンドを実行してみます。
https://github.com/mitsuba-renderer/enoki

cmake -G "Visual Studio 15 2017" -A "x64" -DENOKI_TEST=ON  .

こちらで生成されたソリューションファイルからRUN_TESTS選んでビルドして実行すると基本的なテストが一通り通るはずです。

そしたら、自前のプログラムから呼ぶことを考えます。
これも簡単で、単にenoki/includeフォルダにパス通して#include とかすればいいです。
バックエンド(SSEだとかAVXだとか)の指定はプロジェクトファイル側で適当に設定すれば自動で検出されます。
ちなみに、C++17が前提になっているので、その辺りの指定も必要です。
なんか細かい話として、iostreamヘッダをenokiヘッダより先にインクルードするとM_PIとかが死ぬとかあります。

あとはドキュメントを読むといいです。かなり丁寧に書いてあります。以下のような感じでベクタライズされたarrayを作って演算を記述するイメージです。

enoki::Array<float, 20> arr;

ちなみに、上記20幅のarray作ると以下のように適切な幅のSIMDレジスタで埋まるらしいです。すごいですね。
f:id:h013:20191209181124p:plain:w360

GPUと自動微分

CPUのSIMDバックエンド使うだけならヘッダインクルードするだけです。とても簡単ですね。
といっても、テンプレートを駆使しているため、MSVCだと挙動不審になることはあります。たぶんclangとかだともっとちゃんと?動くのかもしれない。

さて、GPUや自動微分もしてみたくなります。
まずCUDA toolsetをインストールします。そして、以下のようにcmakeコマンドを打ってみます。

cmake -G "Visual Studio 15 2017" -A "x64" -DENOKI_TEST=ON -DENOKI_CUDA=ON -DENOKI_AUTODIFF=ON -DENOKI_PYTHON=ON .

今度はCUDAとAUTODIFFをONにしてます。PYTHONというのは各種enoki機能のPythonバインダなのですが、なんか手元だとうまく動きませんでした。誰か動かしてみてください!

で、enoki-cudaとenoki-autodiffプロジェクトをlibビルドするわけですが、そのままだと通りませんでした。(コミット:dfc8e8978813659308ad86a09ffc89b5d431f734 )
そこで以下のような修正をしました。(気が向いたらプルリクエスト出すかもしれない)

  • include/enoki/autodiff.hの1436行目以降、ENOKI_IMPORTの位置をtemplateの直後に移動。
  • src/autodiff/autodiff.cppの1113行目以降、ENOKI_EXPORTの位置をtemplateの直後に移動。
  • src/python/common.hでlambda式の中でif constexpr使っている箇所があるが、VS2017だとconstexprとしてコンパイルされないっぽいのでlambda式をfree functionとして分離。

以上修正するとビルドが通るので、autodiff_nativeプロジェクト側でリンクすると、テストプロジェクトのビルドも成功し、テストも通りました。
このあたりはちょっと怪しくて、dllとかでも動くような感じもしつつ、うまくいかないような感じもしつつという感じです。VisualStudio版はまだちょっと発展途上って感じですね。

しかしまあ、これで自動微分もCUDAでの実行も普通に行えます。(テストプロジェクトのコードを参考にするといいですね)CUDAで実行するとプログラムが終了しきらないことがあるのですが、まあご愛敬ということで。以下のような自動微分コードが普通に動きます(しかもベクタライズされて)

DiffArray<DynamicArray<Packet<float>>> a(1.0f, 2.0f, 3.0f, 5.0f);
set_requires_gradient(a);

auto b = a * a;
forward(a);
std::cout << gradient(b) << std::endl;

上記の出力結果は、a^2の微分が2 * aなので、[2, 4, 6, 10]になります。

所感

SIMDラッパライブラリ的に使うのであればかなり容易に使えます。それだけでも価値が高いのではないかという気がします。
自動微分も、わりと簡単に利用できます。CUDAが絡んでくると、ちょっと面倒かも。でもそこまで大変ではないです。
Pythonバインド周りは諦めちゃいましたが、基本的にはpybind11使ってるだけっぽいし、ということはWin/VS2017でも問題なく動くはずです(理論的には)

今回は触れませんでしたが、SoA化とか、他の様々な機能も豊富です(ドキュメント読むといいでしょう)
C++のいい感じのベクタライズライブラリでちゃんとメンテもされてる最新のもの、という意味では割と未来があるのではないでしょうか。

おわり。

SIGGRAPH ASIA 2018のCourseに応募して採択されたので発表した話

これはレイトレアドベントカレンダー2018の記事です。でもレイトレの話じゃないです。ポエムです。

qiita.com

はじめに

コンピュータグラフィックスの国際学会であるSIGGRAPH。そのASIA版であるSIGGRAPH ASIAが2018年である今年は東京で開催されました。

sa2018.siggraph.org

東京開催ということで、もともと参加しようとは考えていたのですが、色々あってCourseに応募、採択されたので発表してきました。当日は、以下の内容を nikq (@nikq) | Twitterさんと話しました。

Practical HDR and Wide Color Techniques in Gran Turismo SPORT
http://www.polyphony.co.jp/publications/sa2018/

詳細はAbstractを参照してほしいですが、要するにGran Turismo SPORTというゲーム開発において得られた、HDRや広色域関係の知見を理論から実際の実装まで幅広く共有するという趣旨のCourseです。ここでいうHDRとは近年のTVが対応するようになったHDR出力のことです。

SIGGRAPH (ASIA)のCourseに応募しました、という話はインターネットでもあまりない(特に日本語)ので、一連の経緯や何をしたかを簡単にまとめることにしました。皆もどんどんCourse発表しましょう。

応募までの経緯

さて、最初はSIGGRAPH ASIAで何か発表しようとは全く考えていませんでした。しかし、技師長 (@gishicho) | Twitter さんが所用で飛行機にのったときSIGGRAPH ASIAのお偉いさんと偶然会って何かCourse出してよとお願いされたらしく、我々にお鉢が回ってきました。このようなCourse発表は会社としてのアピールにもなるしいい経験にもなるだろうということで、@nikqさんと自分の二人で何か考えて出そうということになり、応募することになりました。

ところで、Courseとはなんなのでしょうか。これは、本家SIGGRAPHでも盛んに行われているのですが、業界の専門家が1〜複数人集まってなんらかのテーマに基づいて1〜3時間くらいの時間で(場合によってはもっと長い時間かけて)講義、講演の形式で発表を行う、というものです。有名なところでいうと物理ベースレンダリングについての幅広い知見を共有するためのCourse、Physically Based Shading in Theory and Practice(https://blog.selfshadow.com/publications/s2017-shading-course/)やリアルタイムレンダリング(ゲーム業界)における知見を共有するためのCourse、Advances in Real-Time Rendering in 3D Graphics and Games(http://advances.realtimerendering.com/)などがあります。

SIGGRAPHといえばTechnical Paper、すなわち技術論文の発表が有名です。しかし、Course形式による教育的な講演も大変充実しているのが特徴です。(ほかにもTalkなどもありますね)SIGGRAPH ASIAでも本家に比べれば小規模ながら、Course発表枠が設けられています。

以上、Technical Paperはともかく、Courseなら発表できんじゃね?という軽い気持ちから応募することになったのでした。

応募方法

さて、応募することになったわけですが、どうすればいいのでしょうか。実際、応募したことある人なんて周りにはいなかったので応募する方法を探るところからはじめました。

一応SIGGRAPH ASIA 2018のウェブサイトには応募要項(https://sa2018.siggraph.org/jp/submitters/courses)が載っているのですが、これが微妙に分かりづらい。しょうがないのでSIGGRAPH 2018の方のCourseの応募要項も読み合せつつ情報を集めるのでした。

まあその辺りの情報をちゃんと読めばそんなに難しいことは無いです、実は。

まず、一番最初にやることはSubmission Siteへのアカウント登録です。Submission SiteというのはTech PaperやCourseの応募(Submit)をする人が基本的には全員登録するウェブサイトです。ここから各種情報の登録を進めることになります。

んで、締め切りまでにこれこれこういう内容でCourseしたいです、というのをSubmitすることになります。ここでポイントなのは、Tech PaperにSubmitする場合は当然Paperを書き上げ、それをSubmitするわけですが、Courseの場合は発表内容が完全には出来上がってなくてもSubmitできます。
具体的には、タイトル、講演者情報、発表概要、シラバス(概要よりももうちょっと詳しい講演計画)、発表する意義、コースノートが必要になります。

このうち、コースノートが実際の発表に使うスライドや何らかの英語文書(論文の体裁のこともある)なわけですが、実はこれは最終的に使用するものでなくても何とかなります。といっても、まったく何でもいいわけでは無く、我々は以前@nikqさんが作成していたそれなりにちゃんとした英語の発表スライドを流用して使用しました。あくまで、最終的な発表に使うものである必要が無かった、というだけでショボイものでいいわけではありません。

また、シラバスはかなりちゃんと作りました。Chapter 1ではこういう話をして、Chapter 2ではこういう話をして、というような発表概要を箇条書きで仕立てたものです。まあこれも最終的な発表内容とは違ってよいんですけど、きちんとしたものである必要はあるようです。

ともかく、こういった情報をまとめてSubmitすれば応募完了、となります。
ちなみに、2018/7/13が締め切りだったようです(その日に応募した)

採択

Submitしたら採択を待つのみです。採択通知は2018/9/4に来ました。ほんとはもうちょっと早く来る予定だったぽいですが、若干遅れました。内容は、Conditionally Acceptedです。Tech Paperもそうですが、文句なしのAccept!というのはなかなか難しくて、大抵はConditionally Acceptedです。(Courseの実情は詳しくは知りませんが)これは、その名の通り条件付き採択と呼ばれるもので、「基本的には採択してやるし、発表させてやるが、レビュアーの意見をちゃんと反映させる条件を満たすこと」という意味です。

レビュアーという言葉が出てきました。SIGGRAPH ASIAにおいてTech Paperは誰にでも発表させるというわけにはいきません。品質を維持する必要があるからです。そこで、SIGGRAPH ASIAでは応募されたTech Paperは5人の業界のエキスパートによってレビュー(審査)されます。レビューを行うのはレビュアーと呼ばれます。レビュアーはPaperに点数とコメントを付けて返却します。そして、一定以上の点数を受けたPaperのみがめでたく(Conditionally) Acceptedとなるわけです。本家SIGGRAPHも似たような仕組みがあります。細かい仕組みは微妙に異なりますが、学会という枠組みではよく行われていることです。

この、レビューシステムがCourseにおいても存在します。3名の匿名のレビュアーに我々の応募内容が送信されます。応募者はやはり匿名になっており、レビュアーは点数とコメントを付けて返却するわけです。我々のレビュースコアはそれなりに良く、コメントも全体的に評価高かったものの、コースノートの不備を指摘されてやや点数を落とされました。コースノートは最終発表とは違っても良い、というようなことを書きましたが、さすがに不完全すぎたようです。そりゃそうだって感じですね。本気で高いスコアで通すなら、もっときちんとオーガナイズされたコースノートを提出するべきでしょう。

採択から発表まで

採択されたら採択承諾をして最終バージョンを提出しないといけません。これがPublishされるバージョンになります。

とりあえず、レビュアーコメントを大まかに反映させます。実はタイトルに関する指摘があり、修正したものが最終的なバージョンだったりします。しかし一番大変なのはコースノートの提出です。今度のバージョンはPublishされるので不完全なものではだめです。

しかしながら、最終提出の期限はかなり厳しいです。採択通知が来たのが9/4だったわけですが、最終提出期限は9/18です。14日じゃコースノートを完全なものにするのなんて不可能です。(そもそも、発表資料を作ったのが発表一か月前とかです)フルタイムで本業をやってる我々からすると厳しいスケジュールです(もちろん、ちゃんとすごいコースノートを提出してる人もいる)

しょうがないので、コースノートはExtended Abstractのようなものにしました。これは、他のCourse発表者もしばしば行っているテクニック(?)なのですが、PublishされるコースノートはAbstractとシラバスを足したような簡素なものにしておくというものです。これならPublishされてもそんなに恥ずかしくないですね。表紙には、発表終了後にスライドなどをアップロードするウェブサイトのURLを貼っておけば完璧です。

ちなみに、他の例としてはコースノートとして発表スライドを全部付ける、というようなものもあります。これも結構よくある手法です。2ページ程度のテクニカルレポート風のものを付ける人たちもいます。
一番すごいのは、何十ページ(100ページ以上のことも)ある英語論文の体裁でCourseの内容を詳細に記述したものを付けている人たちもいます。すごいですね。

また、Copy Rightsに関する処理とかもあります。ウェブ上でフォームを埋めていくだけなのですが、こんなの知らんかったわって感じだし世の中には知らないことがたくさんありますね。でも言われてみれば世間の論文とかって表紙にCopy Rightsが記述されてますよね。あれをジェネレートする処理です。ジェネレートした文書をコピペします。

発表

雑務が終わったらいよいよ発表準備です。仕事その他を色々やってた結果、発表一か月半くらい前から準備する感じになりました。具体的には、スライド作成と発表原稿作成、さらにはその発表の練習です。

まずスライドを作るわけですが、当然全部英語です。さらに、発表時間は40分です。我々はCourseのなかでも、1時間45分の時間が割り当てられたShort Courseでした。これを二人で50分、40分、くらいの分担でやることになったので自分の分は40分というわけです。
40分の発表というのはそれだけでもそれなりに大変なものですが、全部英語ということでさらに大変なうえに、発表のレベルはSIGGRAPHSIGGRAPH ASIAです。本場のSIGGRAPHのCourseなんかを聞いたことのある人は分かると思いますが、3,40分の発表でも大抵非常に内容が濃いです。また、論理展開や図もちゃんとしてます。というようなことを意識しつつスライドを書いていくわけです。

スライド自体は、1か月くらいである程度形にまとまったのですが、そしたらこんどは口頭発表の準備です。もちろん、全部英語で発表します。これに関しては、最初からある程度割り切って、英語原稿を事前に全部用意して基本的にはそれを読み上げるような形にしました。
もちろん、理想的には原稿は全部頭に入れてスラスラと話せるほうが良いでしょう。しかし、大学時代に教わったことの一つとして、ノンネイティブが英語発表するときは原稿に頼った方が良い、というものがあったのでそうしました。原稿が無いと途中で発表に詰まった時にかなりやばいことになります。というわけで事前に原稿を全部用意しました。
といっても、PC画面をずっとにらめっこするわけではなく多少なりとも聴衆に意識を向けるようにはしました。

で、原稿も出来てきたら事前の発表練習です。発表練習はやりすぎるということはないでしょう。しかし、最後の方はいろいろな進行がかなりシビアになってしまい、あまり発表練習できませんでした。英会話の先生に2回ほど聞いてもらった+自宅で一人でブツブツ発表練習+社内で1回通し練習、程度のものです。これはもう少し回数があっても良かったかも。
自宅では10回以上通しで読み上げ練習していたのですが、これはかなり有効だったようには思います。

本番

まあそんなこんなで本番です。本番の前に、発表者には準備部屋が与えられます。他の人たちがどういうスケジュールだったかは知らないのですが、我々は初日の午前発表だったため、準備部屋は前日割り当てられました。

会場である東京国際フォーラムに行き、適当に受付に聞きつつ割り当てられた部屋に行きます。発表会場とは別の部屋なのですが、1時間ほど割り当てられており、発表者はPCをモニタにつないだりできます。今思うと、別の発表会場のモニタで正しく映像が出たからと言って本番の発表会場で正しく出るとは限らないわけで、なんの意味があったのだろうかという気もしますが、前日に発表会場の雰囲気を知っておくのは当日の緊張を和らげるだろうし、まあ行ってよかったとは思います。(実際、前日まで資料作成や発表準備していたので、時間は少しでも惜しかった)

で、いよいよ当日です。当日は9時発表だったので8時に現地入りしてチケットを貰って発表会場に入りました。運営がグダグダで、発表直前になるまで会場を空けないというダメっぷりだったうえにそもそも参加登録受付に長蛇の列ができてて9時の段階でチケットを受け取れた人があまり多くなかったようです。それでも、時間とともに徐々に参加者は増えていったようです。Pixarの偉い人やHoudiniの偉い人も参加してたらしく、発表をほめていた(伝聞)らしいので良かった良かった。

以下のウェブサイトで発表スライド等は公開です。

http://www.polyphony.co.jp/publications/sa2018/

まとめ

超大変でした。SIGGRAPHとかでめちゃくちゃ立派なCourseしてる人たち、本当に頭が下がります。すごいです。英語力の分を差し引いても、とても大変です。しかし、英語スライドつくって英語発表するというのはいい経験になったような気がします。みんなも挑戦してみると良いのではないでしょうか。おわり。

Blue-noise Dithered Samplingの実験をしてみた

これはレイトレ合宿4!?アドベントカレンダー記事です。

Blue-noise Dithered Sampling

先日開催されたSIGGRAPH2016には私も参加しましたが、興味深いものの実装が大変そうなものから何の役に立つのかわからない技術まで様々な知見を得ることができました。
その中でも割とさくっと実装できそうで、かつ効果もありそうな発表があり、それがBlue-noise Dithered Samplingです。これは、Roll the Diceというトークの中の発表の一つで、Arnoldという有名なレイトレーシング(パストレーシング)ベースのオフライン商用レンダラを開発しているSolid Angle社による成果ということになっています。
今回は、この発表を元に適当に実装して簡単な実験をしてみました。

実装は以下に置いてあります。

github.com

Blue-noise 

ブルーノイズについてはあまり深くは説明しませんが、以下の図のように各点間の距離がなんとなく等しくなるように平面上に散らばっている点群の性質をブルーノイズと呼んだりします。

f:id:h013:20160822172701p:plain(http://www.geometry.caltech.edu/BlueNoise/より)

二次元平面からのサンプリングはコンピュータグラフィックスにおいて様々な箇所で頻出の問題です。完全にランダムに行えば、それはホワイトノイズになります。周波数領域で周波数に偏りが無い(=ランダム)だからです。ブルーノイズの場合、低周波成分が小さく、高周波成分が大きい、といった特性を持っています。人の網膜細胞もこのパターンらしいです。

さて、ブルーノイズはもともと画像の二値化などのディザリング処理において良くつかわれていました。今回の手法は、このアイディアをサンプリングに応用することでいい感じにディザリングされたレンダリング画像を少ないサンプル数で得る、という手法になります。

実装概要

まず、解きたいレンダリングの問題が何次元の積分なのかについて考えます。例えば、モーションブラーであれば時間方向に積分するため1次元の積分になり、アンビエントオクルージョンであれば半球上で積分するため2次元の積分になります。
このように、解きたい積分がd次元のとき、d次元分の乱数列([0, 1)の範囲)を生成します。2次元の場合、(0.3152, 0.8611)みたいな感じになりますね。普通のレンダリングの場合、このような乱数列を各ピクセルごとに独立に複数回数生成してモンテカルロ積分のサンプルの生成に利用することで画像を得ます。

しかし、今回の場合は全ピクセルで同一の乱数列を使うとします。そして、それぞれの乱数列をピクセルごとに事前に決めておいたd次元の値([0, 1)の範囲)でオフセットします。もし、事前に決めておいた値が以下の図のように完全にランダムなら、結局各ピクセルごとに独立の乱数列を生成するのとほとんど変わりません。

f:id:h013:20160822174126p:plain(128x128、[0, 1)の範囲の乱数列)

しかし、このオフセット値を以下の図のようにブルーノイズを用いればレンダリング結果はディザリングされたものになり、より望ましくなります。

f:id:h013:20160822173929p:plain

これが今回の手法の要旨です。

ブルーノイズオフセットの生成

さて、それではブルーノイズオフセット値はどのようにして得るのでしょうか。これは、論文に詳しく解説されていますが、焼きなまし法による最適化によって得るようです。
まず、与えられたサイズのオフセットマスク画像をd次元、[0, 1)の範囲の乱数列で初期化します。そして、あるオフセット値と別のオフセット値の間で定義されるエネルギー関数の総和を最小化するように、適当に選んだ二つのオフセット値を入れ替える、ということを反復的に行えば良いらしいです。最小化したい式は以下のようになります。

f:id:h013:20160822174528p:plain

https://www.solidangle.com/research/dither_abstract.pdfより)

ここでpi, qiはマスク上の位置で、ps, qsは各サンプル、dはオフセットの次元です。分母のσは定数になります。

で、これを実装するわけですけど今回自分は焼きなまし法は特につかわず(パラメータチューニングとか面倒だし)エネルギー関数を事前に計算しておいて、適当にオフセット値を入れ替え、再計算したエネルギー関数が減少していれば入れ替えを採用、減少してなければ入れ替えは棄却、ということを指定された回数繰り返すようにしました。
さらに、エネルギー計算の再計算も自分以外の全オフセット値に対して実行していると重いため、自分の周囲にのみ着目するような近似計算にして高速化を行ってみました。

わりと適当でしたが、それなりにうまく生成されているように見えたので良しとします。(若干品質が低いような気もする)

実際のレンダリング

レンダリングするときは、既に解説したようにブルーノイズディザリングしたいモンテカルロ積分のサンプル生成にブルーノイズでオフセットした値を投入するだけです。
今回の実験ではモーションブラー(1次元)とアンビエントオクルージョン(2次元)の二つについて試してみました。

結果

それでは結果です。画像は全て512x512でレンダリングしています。オフセットマスクのサイズは128x128です。

以下はモーションブラーの結果です。

f:id:h013:20160822175355p:plain(ランダムオフセット / 1spp(1 sample per pixel))

f:id:h013:20160822175459p:plain(ブルーノイズ / 1spp)

ブルーノイズの方はランダムに比べてノイズが均等に分布していることがわかります。
ただ、サンプル数を1から9sppに上げると両者の差は小さくなりました。f:id:h013:20160822175650p:plain(ランダムオフセット / 9spp)

f:id:h013:20160822175720p:plain(ブルーノイズ / 9spp)

ちなみに、リファレンスとして256サンプリングすると以下のようになります。

f:id:h013:20160822175746p:plain

次に二次元の積分アンビエントオクルージョンの結果です。

f:id:h013:20160822175830p:plain(ランダムオフセット / 1spp)

f:id:h013:20160822175850p:plain(ブルーノイズ / 1spp)

モーションブラーほどではありませんが、ブルーノイズの方が良い結果を得られています。しかし、やはりサンプル数を増やすと以下のように、結果は似たようなものになりました。

f:id:h013:20160822180128p:plain(ランダムオフセット / 9spp)

f:id:h013:20160822180155p:plain(ブルーノイズ / 9spp)

ちなみに以下はリファレンスです。

f:id:h013:20160822180254p:plain

アンビエントオクルージョンも設定によってはブルーノイズの方がかなり良い結果を出すこともあります。例えば以下。

f:id:h013:20160822190029p:plain(ランダムオフセット / 1spp)

f:id:h013:20160822190047p:plain(ブルーノイズ / 1spp)

f:id:h013:20160822190105p:plain(リファレンス)

まとめ

どうも高次元の積分になると効果が薄まっていくようです。この手のサンプリング手法は大体そういう傾向がありますね(Low Descrepancy Sequenceとか)。また、サンプル数を増やすと割とすぐ似たような結果になってしまいました。なんかバグってる可能性もありますが、元の論文のアブストの結果画像も1sppで比較してるのが多く、9sppで比較してるのはボリュームレンダリングだけだったので相性みたいなのがあるのかもしれません。

また、マスク画像のサイズも、今回は適当に128x128と決めましたが結果に影響あるかもしれません。

しかし、1sppで比較した時は間違いなく単純なランダムよりはいい結果になっています。オフラインで長時間レンダリングできるシチュエーションだとちょっと微妙かもしれませんが、むしろリアルタイムレンダリングで、サンプル数を出来る限り減らしたいような状況で活きてくる手法かもしれません。

おわり。