
2026/05/10 4:09
Web ブラウザ上で動作する Surfel ベースのグローバルライティング
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
本記事は、ハードウェアレイトレーシングへの依存を置かずにオープンウェブ上でリアルタイムな全球照明(global illumination)を実現する実践的な WebGPU パイプラインを提案しています。照明計算と画面解像度を分離することで、ピクセル数に関わらず約 50k のサーフェル(surfels)を効果的にシャドウ付けし、性能を約 60 フレーム毎秒に維持することを目標としています。中心的な成果は、13 を超えるコンピュートパスを含む大規模なレンダリングパイプラインです。このパイプラインは、空間的アクセラレーションの効率化のために Kajiya レンダリングに触発されたカメラ中心のカスケードグリッドを用い、WebGPU にレイトレーシングがネイティブとしてサポートされていないため、コンピュートシェーダーで BVH ライブラリを統合し、レイトレーシングクエリを実装しています。進化したノイズ抑制と時間的安定性は、8x8 の半球八分面(hemi-oct-square)グリッドによるサンプリングガイド、そして平均を追跡し「虫食い(fireflies)」のようなアーティファクトを抑制するための Multi-Scale Mean Estimator(MSME)アルゴリズムなどの技術を通じて確保されています。モメントシャドウマッピングを使用した放射状の深度アトラスは、滑らかな視覚機能の再構成によって光漏れを防いでいます。確立されたレンダラーに触発されているものの、このソリューションには依然として重大な制約が存在します:具体的には Chrome のストレージバッファ制限により、Firefox/Safari と互換性のないワークアラウンドが必要となり、シームレスなクロスプラットフォーム展開を妨げています。その結果、システムは静的拡散照明と単一の方向光源に限定されており、鏡面反射、透明性、環境遮蔽といった重要なエフェクトが除外されています。つまり、この強力ではあるが不完全なアプローチは、現時点では主要なウェブブラウザ全体で完全にリアルなレンダリングをサポートすることはできません。
本文
ブログ投稿:WebGPU を使って、サーフェルという面要素を用いたリアルタイムグローバルイラミネーションを計算することは可能でしょうか?
2026 年 1 月 29 日
上記は、インタラクティブな可視化のシリーズを通じて段階的に探っていく予定の内容の簡易的なイラストです。しかし、その道のりを下っていく前に、お_reader(読者)様へ一つ恳ねて申し上げます。選択をなさってください。
光の簡単な歴史
旅人の皆様、こんにちは!さあ、始めましょう。
もちろん最初はなにもなく、光さえありませんでした。そしてビッグバンから非常に短くも長く、おそらく 1 秒後くらいに、最初の光の粒子が創出されました。しかし残念ながら、彼らにとって、長い間、宇宙はエネルギーで満ちており、非常に高温高密度の状態であり、光子たちが思う存分移動することができず、すぐに電子と衝突して散乱してしまうという状況でした。まるで、これまでに見たことのある最も濃い霧の中でflashlight を照らすのに似ています。
その後、ある期間を経て物事は少しだけ冷えていきました。依然として高温でしたが、電子と陽子たちが外で飛び回っているのをやめ、友人となり、一緒に原子の中へと住みこむほどに「冷えた」のです。常に衝突し続けていた可哀想な光子たちには突然、移動する余地ができましたー霧も晴れました。そこで解放された光こそが、我々が観察できる最も古い光、マイクロ波背景放射(CMB)です。
さて、この光の一幕の後、宇宙は再び暗闇に沈んでしまいました。初期バナーからの光子たちは風になって消え去り、新たに光子を作るものはどこにもいませんでした。そこで宇宙は待ち続けたのです。誕生して 38 万年から 4 億年までの間のグローバルイラミネーションは、「easy peasy(簡単)」で、finalColor = vec4(0,0,0,0) という処理だけでした。
ついに、宇宙が誕生してから約 5 億年後に、水素の粒子たちが強く結びついて自己着火し、ヘリウム原子へと融合する際、超高エネルギーの光子が創出され、新しいタイプの「光源」である星が誕生しました。さて、これらの光子たちの挙動については、グローバルイラミネーションに関する論文を執筆する材料にはなりませんが、もし地球をこれらに照らされたとしたら、人間などいるはずもなく、不毛な凍結した荒廃地帯になっているでしょう。いいえ、このエネルギッシュな若者たちは、まず星の内部で約 10 万年ほど飛び回って落ち着き、宇宙という幼稚園での粒子相互作用によって可視光エネルギーレベルまで削られて初めて、星の表面に到達するのです。さて大人になった彼らは、光速で宇宙を自由に行き来できるようになりました。
まさにこれらの光子たちが、今回の投稿でコントロールしようとしているものです。多くの科学者(ハイサム『光学』、ニュートンの Corpuscles、イエンズ的光の波、プランクの量子、アインシュタインの光電効果)と芸術家(レオナルドの光の散乱の研究、モネ『睡蓮』シリーズにおける石の色の変化、ターナーの光の研究、ヴェルメールに伝わる機械的補助具など)にとって魅力的な主題であり、これらの光の使者たちは多くの興味深い性質を持っています(散乱、回折、屈折、重力レンズ効果など)。ただし、今回の探索においては、私たちは特に拡散反射に興味があります。あるいは、レオナルドが 15 世紀末にこう述べたとおり:
反射体が物体の色そのものや、それらがぶつかる場所の色と同じ色を持つことは非常に稀です。 例えば、球形の物体 d f g e が黄色で、その色を反射する物体 b c が青いとします。私は、この反射によって球形物体の一部が照らされる場合、b c が空気や太陽光に照らされている限り、その部分は緑色に着色されると言います。
(レオナルド・ダ・ヴィンチ『絵画論』より:色の反射)
もちろん、彼は正しかったのです。この現象は初めに画家レオン・バッティスタ・アルベルトィによって記述され、彼の絵画に関する処世書『De pictura』でこう述べられています:
反射線は、それらが反射される表面から発見した色を採用します。野外を歩く人々の顔が緑色がかって見えるときにこれを観察することができます。
そしてレオナルドこそがこれを科学化し、具体的な変数を分離して結果を予測しました。
(Blender でレンダリングされたレオナルドの思考実験)
今日では明らかですが、当時の人々にとってはおそらく混乱を引き起こしたのが、この実験は「水色」など、緑成分が多く含まれる青を使う場合に限られるということです。なぜなら完璧な黄色は青を完全に吸収してしまうため、完璧な青の反射が黄色い表面上で起きても、最初からそこに存在しない緑分もなければ、単に泥のような暗部(ゼロの緑)しか生まれないからです!幸運にも彼らは純粋な青系の顔料にアクセスすることができず、そのためすべてうまくいったというものです。
さて、光の研究史についてはこれくらいにして、残念ながら魅力的ではあっても、これらの現象をシミュレートするリアルタイムレンダリングエンジンに私たちを近づけるものではありません。現在の状況を見てみましょう。
パス追跡とコンピュータ
今や我々のポケットや机の上に置かれている極めて高速な計算機のおかげで、レオナルドが思考実験に適用した論理は 1 秒間に何百万回も実行できます。これをパス追跡と呼びます。「光子」またはレイのそれぞれの旅を追跡し、それらが何をどう見るか、誰と話すかを観察し、その情報を元にコンピュータに特定のピクセルに適した色を指示するものです。Cycles などのレンダリングエンジンでは、1 枚のイメージを描画するのに数分〜数時間のスパンで、各ピクセルに対し数千本のレイを使用するのが一般的です。これによって卓越した品質のイメージが得られますが、リアルタイムアプリケーションにおいては画素全体のプロセッシング(レンダリングはその一部に過ぎません)を 16 ミリ秒以内で完了させる必要があるため、オーダー単位で遅すぎます。
ゲーム出荷時に「フルレイトレーシング」モード搭載(『Cyberpunk 2077』、『Alan Wake 2』など)が始まるとともに、将来はパス追跡が標準となる可能性がありますが、これには多くの人が利用できない強力なハードウェアが必要です。リアルタイムで完全にパス追跡を行うゲームを開発することは主に不可能であるため、これまでにさまざまな最適化や近似技術が進化してきました(ライトマップは静的、放射度プローブは低解像度、スクリーン空間のグローバルイラミネーションは本当の意味での「グローバル」ではない、ボクセルはリークしやすいなど)。ただし、ここには「無料のランチ」はありません。しかし、数年前に地平線上に軽食のようなものが見え始めて以来、EA の SEED 研究部門が SIGGRAPH 21 でサーフェルを用いた技術を紹介しました。「Surf-what-els?」と聞かれますね。見てみましょう!
サーフェル(Surfels)
さて、まずはタイムジャンプ!今回は自己中心的な小さなものですが。シアトルのヴァンクーバで開催された SIGGRAPH 2025 のホールを徘徊しながら、ルイペン・ワン、ジェン・レン、金祥(ジンシアン)・ワンによる「SurfelPlus: A Surfel-Based Global Illumination Solution」と題されたポスターを見つけました。そこでは研究者たちはこう述べています:
「低エンド GPU 向けに最適化されたサーフェルベースのソリューションを開発することで、リアルタイムでの豊かでダイナミックな間接照明を実現できます。」
少し目を細めると、「low-end GPUs(低性能 GPU)」は「the web(ウェブ)」とほぼ同じように見えます。私の住む場所がそこなので非常に興味を持ち、翌朝実験を始めることにしました。
(画像:SIGGRAPH のポスター)
それは 1 日目でした。当時、2 日目が数ヶ月後に起こることを私は知らなかったのですが、かゆみは一向に止まらず、サーフェルの考えが頭の中で漂っていました。待って、まだサーフェルとは何か説明していないではないですか!では、おわかりください:
サーフェル(surface element、2000 年の地味な SIGGRAPH の論文で Pfister らによって導入された)とは、3D スペースに浮遊する平たい円盤のことです。位置、法線(回転/方向)、半径で表されます。もちろん、それは表面に貼り付けられ、その半径が影響範囲を規定するのがより有用ですが、後ほど触れます。それらの主な利点は、照明を画面の解像度から分離できることです。画面が 200 万ピクセルであっても、5 万個のサーフェルを有効にシェーディングすることでグローバルイラミネーションを得ることができ、その高価な作業を時間経過とともにキャッシュできます。
(画像:サーフェルのイラスト)
ではサーフェルを使いますか?しかし残念ながら、誰にとってもサーフェルは木から生えませんので、利点を享受するにはまずそれらを作成する必要があります。そしてここで友人、本当の楽しさが始まります。
1. サーフェル化(Surfelization)
サーフェル化とは、三角形で作られた通常の幾何学形状を、微小な面領域を表す離散的なサーフェルのコレクションに変換するプロセスであり、レンダリングパイプラインにおいて概念的にも必要な計算量においても大きな部分を占めます。
プロダクショングレードのサーフェル化パスには以下が含まれます:
- G-buffer(G は Geometery の頭文字)を法線、深さ、アルベドと共にレンダリングし、
- サーフェルの「プール」およびそのライフサイクルを維持し、
- サーフェルが存在しない領域(または存在しすぎている領域)に対するスクリーンスペース分析を行い、
- 関連するサーフェルを高速で検索するための空間データ構造を持っています。
最終的なプロジェクトでは、これ単独でも 10 以上の計算パスが必要になり、空間構造(グリッド)の維持には 7 パス、サーフェルのライフサイクル管理には 4 パスが使用されます(サーフェル化も含めます)。これで楽しい!私はこのパイプラインの最初の概念的な塊に着手し、関わる部品の数を見て、WebGPU(あるいは私が)が全体システムを扱えるか疑問に思いました。しかしそれはできましたし、今でもできています。実は最も単純なステップの一つです。
簡単に言うと、シーンの法線と深さをテクスチャにレンダリングします(これが G-buffer です)。その後、そのテクスチャを検査して、サーフェルの最適な位置と方向を特定します。次に、グリッドをクエリすることで既存のサーフェルを取得し、それら候補と比較します。少しのアトミックな並列競争が行われ、勝者が実際のサーフェルとなり長く幸せな生涯を送ります。敗者は破棄されます。
(画像:インタラクティブなプレイグラウンドの可視化)
以下は WebGPU を必要とするインタラクティブなプレイグラウンドです。サーフェル化段階の重要な部分を実装していますが、空間データ構造を省略し、代わりに単純なブルートフォースの近傍検索を行っています。モデルを回転させ、拡大・縮小して、サーフェルが不足する領域にどのように充填されるか観察してください。パラメータを調整してシステムの振る舞いを理解してお楽しみください:
- サーフェルの数を増やし、システムがすぐに停止し始める様子を观察します。
- ベースの半径を小さくすると、モデルの全体表面を被う前に容量を使い果たすことに気づきます。
デフォルトの可視化はサーフェルを実際の 1/3 のサイズで表示しており、位置と方向をより簡単に理解できるようになっていますが、重み付きレンダリングのデバッグモードに切り替えて、実寸 1:1 でサーフェルを表示し、実際のシナリオでの色のブレンド具合を確認することもできます。
これは信じられないほど重いデモです(デバイスがトースターになりそうになった場合はパラメータで G-buffer のスケールを減らしてみてください)。それでも単なるシンプルなメッシュに約 512 つのサーフェルを維持するだけです。実際のエンジンでは数万ものサーフェルをサポートする必要があり、サーフェル化は単一フレームを描画するために必要な作業の一部に過ぎません。地球上での私たちはどうやってすべてこなすのでしょうか?
予期通り、グリッドの有無や追加はパフォーマンスにとって決定的です。それを設けないと、各ピクセルに対し 512 つのサーフェルを検索と比較する必要があり、フレームあたり数百万回の評価が必要になります。しかし賢いグリッドを使用すれば、せいぜい数十個のサーフェルにのみ比較できます。
やはり「無料のランチ」は存在しないので、このパフォーマンス向上をグリッドの維持と複雑性で支払っています。しかし、我々のアプローチがこれなしでは成立しないため、グリッドアルゴリズムの中に少なくとも少しのスナックが隠されているはずです。
2. グリッド
グリッドは、Tomasz Stachowiak がサーフェルを拡散グローバルイラミネーションの一部として使用する際にもっとも複雑なパイプラインの一部として使用した Kajiya レンダラーの手法に大きく影響を受けています。
エンジンにはデバッグ可視化モードがあり、グリッドを理解しやすくします。
(画像:グリッド可視化)
ご覧のように、これはカメラ中心の級連(Cascaded)3D スペース指数であり、多数のサーフェルをグリッド型加速構造のようにクエリできる何かに変換します。文脈における「級連」とは、多分解能データ構造を意味します。概念的には、観測者を中心とした空間が複数の立方体グリッド(動画の上部で最初に可視化)に分割され、それぞれ固定数のセルを持っています。Cascade 0 が最も細かい(小さなセルを持つ)ものでカメラに近い部分を担当し、より高い級連はより大きな領域をカバーします。これは知覚的な重要度と一致しています:近くのサーフェルには正確な検索のために詳細な空間解像度が必要ですが、遠いものは粗いセルを共有できます。これによりメモリを節約しクエリコストを低減できます。
各サーフェルはグリッドに対してテストされ、整数のセル座標にマッピングされます(これらのセルは上記動画で 2 番目に可視化)。級連レベルはセルの中心からの距離から選択され、小さなヒステリシス帯が適用されることで、境界付近のサーフェルが 2 つの級連に挿入されポップ避免出现を避けます。各候補級連に対し、サーフェルは重なりうるセルの AABB を計算し、それらのセルを反復処理します。そしてセルを箱として扱い、「圧縮」してサーフェルの法線方向に沿って距離をスクリューする(安価な異方的な測度)というより厳密な交差テストを実行し、サーフェル半径と比較します。各セル内のサーフェルの量はヒートマップで可視化され(動画の 3 つ目の可視化)、カメラが移動するにつれて常に変化しています。グリッドは、4D キー(x, y, z, cascade)を単一の整数化する線形化によってインデックス付けられ、フラットな配列として保存されます。
この構造の構築は複数の計算パスで行われます:
- 各セルのカウンターをクリアし、
- 原子増分で各セルが持つサーフェル参照数数をカウントし、
- そのカウントに対するセグメント化済みプリフィックス和スキャンを実行して連続的な書き込み範囲に変換し、
- 各セルのプリフィックス和を「終了ポインタ」として始め、各ライターが原子减量(atomicAdd(-1))で一意のスロットを獲得し、すべての書き込み後にヘッダー領域は自然に安定した開始オフセットへと落ち着き(最後のセンinel が合計値を持つ)、サーフェルインデックスを単一の結合バッファ(offsetsAndList)にスロットします。
結果としては本質的にリストレイアウトとなり、任意のグリッドセルに対してサーフェルインデックスの区間を O(1) でアクセスでき、その後にプールの代わりに関連するサーフェルのみを反復処理できます。
(画像:2D アルゴリズム可視化)
グリッドとその仕組みは視覚的に難しいですが、アルゴリズムは非常にエレガントなので、理解するのに時間をかける価値があります。これは 2D で各パスを詳細に示した可視化です。クリア、カウント、プリフィックス和、スロットリングの段階を経て進むため、オフセットとフラットリストがどのように埋め尽くされるかが見えます。下部のログにはすべての微ステップが表示されています。
パラメータを変えて遊んでみてください。サーフェルを大きくしたり、数を増やしたり、セルの数を増減させたりするとどうなるか。個々のグリッドセルやサーフェルの上をホバーしてタップし、どこに配置されたか確認できます。
さて、この段階でグリッド構築が完了しました。サーフェルのいっぱいいっぱいデータ構造があり、簡単に素早くクエリ可能です。サーフェル自体もシーンの幾何学上で最適に近い配置になっているはずです。ようやくレイ追跡を始められそうです!
3. インテグレータ(レイ追跡)
うわあ、待ってください、何が?WebGPU でレイ追跡はできません。仕様でサポートされていないではありませんか。あなたは私たちがこれまでに街道を 10 の計算パス通ったにもかかわらず、ハードウェアレイトレーシングの店舗が閉まっていたと言っているのでしょうか?
3.1 BVH の特別編
luckily for us, the friendly neighborhood shop is open - it's called three-mesh-bvh. This wonderful project by Garrett Johnson and company emulates ray tracing with compute shaders (build on the CPU, query with GPU), which isn't as fast as the hardware RT, but is pretty darned fast regardless.
3.2 The trace
With the BVH answering our ray-scene intersection queries, I guess a fair question to ask is what are we even ray tracing? Luckily (again? what are the odds?) for us, we're not doing it for every pixel, as that would not fly.
We ray trace per surfel.
The integrator's job is to figure out what light each surfel sees and accumulate it. In pseudo code:
for each surfel: irradiance = 0 for each sample direction: ray = shoot_ray(surfel.position, direction) if ray.hits_geometry: hit_color = direct_light(hit_point) + sample_surfel_grid(hit_point) else: hit_color = sample_environment_map(direction) irradiance += hit_color * cosine_term / pdf surfel.irradiance = temporal_blend(surfel.irradiance, irradiance)
Seems straightforward enough, but there are at least two more dragons here. First, if we generate random directions uniformly over the surfel's hemisphere, most of our rays will often probe directions that contribute little light, leading to noise. Second, raw averaging samples frame-to-frame produces either lag (if we blend slowly) or noise (if we blend quickly). So, what do?
4. 光を導く
あなたが Sponza の壁に住むサーフェルだと想像してみてください。あなたの仕事は間接光を見積もることです。
半球を一様(またはコサイン重み付き)にサンプリングすると、ほとんどのレイで次のような重要な情報を学習します:
- 「はい、天井はまだそこにある」
- 「はい、あの柱はまだそこにある」
- 「はい、虚空は暗いまま」
一方で、部屋の向こう側の明るい窓だけが叫び手を振ってジャンピングジャックをしており、あなたは数分に一度偶然それを見るだけです。ガイドリングがそれを修正します。
4.1 グリッド、パート2
各サーフェルは半球上に小さいグリッドの重みを保存しており、実装では 8x8 のグリッド(64 つの方向ビンを表す)です。半球方向を 2D 正方形にマッピングする hemi-oct-square マッピングを使用しています。このマッピングは安価なエンコード/デコードを持ち低歪み分布を提供し、緯度経度の極座標の極点を回避します。
(画像:半球ガイドリンググリッド)
さて、各回レイが放射量 L を返すと、その光度を計算して「スplat」してレイ方向に対応するグリッドセルに値を挿入します。時間の経過とともにサーフェルは確率分布を構築します:
- 「これらの方向は明るくなる傾向がある」
- 「これらの方向は暗くなる傾向がある」
4.2 注意深くサンプリング
ガイドリングされた方向のみをサンプリングすると、局所最適解に陥る可能性があります(「明るい壁を見つけたので、より明るい窓を発見しない」)。一方、コサインのみをサンプリングすると作業を無駄に使います。
したがってインテグレータは混合を行います:
- 確率 pGuide でガイドリンググリッドからサンプリングし、
- それ以外ではコサイン半球からサンプリングします。
そして我々はモンスターではないので、混合確率密度関数 mixPdf = (1 - pGuide) * pdfCos + pGuide * pdfGuide を使用して無偏性を保ちます。ガイドリング混合物は積分推定量を無偏に保ちますが、システム全体としてはもちろんサーフェルの離散化と時系列フィルタリングによるバイアスを持つリアルタイム近似です。
その後各サンプルは適宜重み付けされます。pGuide はサーフェルの年齢に応じて上昇します。新生サーフェルはより多くの探索を行います。成熟したサーフェルはより多くの活用を行います。小さな赤ちゃんサーフェルは好奇心を持っても構いません。
(画像:ガイドリングサンプリング可視化)
以下はこの仕組みの実際の可視化ですが、1 次元少なくしています。左下にはサーフェルとその方向(壁と壁の間で移動可能)があり、自分自身からレイを発射しています(面白い事実はプラトンやユークリッドなどが目の働き方をこうだと信じていた点です。これを放出理論と呼びます)。天井には小さな開口部があり、これも移動でき、そこから光が通り右側の壁に特に小さい領域に当たります。そこでのバウンスがガイドリングが目指している場所です(それより程度低いとして、開口部の向こうの空も)。レイダンスの下には 3 つの色が見え、最初のものが正解、第二のコサインサンプリングで得た色(青いレイ)、最後のものがガイドリングサンプリングによる色です。通常、ガイドリングサンプリングと比較してコサイン色のちらつきをかなり長く観察する前に安定します。
ここで直感をつかむために遊びやすいハンドルがたくさんあります。学習率を増やしすぎるとガイドリングは混沌に陥ります。ガイドリングされた光のみ reliance すると、シーンが変化したことを検出できず誤差率が跳ね上がります。ビン数を減らせばメモリ使用量は下がるものの、基本ランダムサンプリングに近づいていきます。
まあまあ!この時点で実際に興味深い画像をレンダリングできるパイプラインを持っています。サーフェル検索のための加速構造があり、レイシーンの交差のための加速構造があります。最も少ないレイ数で最大限の光を得るためにサンプリング場所を賢く学習しており、レイトレーシングヒットからテクスチャ色を取得する方法もあります。もし最小の解決パス(resolve pass)を追加して、画面の各ピクセルに対してグリッドからサーフェルをクエリし、その後サーフェルの位置、方向、サイズに基づいてその色を重み付けで平均化すれば、イメージが得られます。それはどのような見た目になるでしょうか?
(画像:ノイズ付きの生結果)
うっわ、ひどい。一体どうなっている?確かに光は適切にバウンスしており、迅速に反応していますが、このノイズのために全く使用できません。実際、単一フレーム内でノイズのないイメージに必要な情報を蓄積するのは daunting task です。サーフェルあたり 512 レイという非理知的なサンプル数に増やせますが、その場合パフォーマンスが著しく低下し、それでもイメージは希望するほどきれいになりません。前フレームの情報を使って現在のフレームを安定化させる必要があります。実際には複数のフレームに対して移動平均を実行して、各フレームで前の値をわずかに補正する必要があります。それを試してみましょう!
5. 時系列安定性への探求
(画像:時系列フィルタリング比較)
ああ、ずっと良くなりました!しかしなぜ「起動」に这么久々遅いのか、反応も遅いのか?私は「無料のランチがない」という方々が本当にそう言っていることを理解しました。実際の变化が起きているときすぐに反応し、世界が静かで安定しているときは落ち着くような統計的方法はありますでしょうか。両方の世界で最高のものを手に入れたいです。
登場、左舞台、マルチスケール平均推定量(MSME)の略称です!EA SEED の PICA パイプラインの一部として Ray Tracing Gems の第 25 章で説明されており(サーフェルが拡散グローバルイラミネーションに初めて使用された場所)、この美しいアルゴリズムは長期的な平均と短期的な平均の 2 つを追跡し、基本的に短期的な平均が変化を検知している場合、長期的な平均を一時的に適応させるためにすくい上げるように働きます。もし短期的な平均が長期的な平均と一致しないが、分散も高い場合、その不一致は単にノイズではなく本当の変化かもしれないという可能性があるため、MSME は落ち着き過剰反応しません。
(画像:MSME 可視化)
もう一つ、遊びやすいハンドルが多いものです!右のスライダーで信号を変え、両方の指数移動平均(EMA)と MSME が真の値を見積もろうとしている様子を観察します。MSME は EMA よりも速くないことに気づくでしょうが、それほど遠くはありません。しかし、それははるかに安定しています。同じ安定性を得るために EMA を使用すると学習率は最小でなければならず、それによる遅れは使用不可能になります。MSME が火虫(fireflies)の上を滑り抜ける様子を観察し、EMA はそれを投げ出されることを確認してください。他の例と同様に設定でこれらのパラメータを調整できます(ギアアイコン)。
さて、この魔法的なデノイザーがパイプラインの一部になったら、イメージはどのように見えるでしょうか?見てみましょう。
(画像:時系列安定した結果)
予想通り!起動も反応も速くなります。EMA ベースの時系列蓄積器がこのように速いようになると、多くのノイズを我慢する必要があります。私たちにまた与えられた軽食ですが、まだ無料のランチはありません。
このすべてのプロセスでの変動を視覚化するのは少し楽しくもあります。
(画像:変動可視化)
ここから WebGPU 刃物の端っこを行き来してきたが、パイプラインには 13 の以上の計算パスがあり、インテグレータパスは境界ストレージバッファの絶対限界、つまり 10 を感じている間ずっと使い尽くしています。Sponza は 60 fps で良く見えますので、確かに、すぐに終わったはずです...
... しかしカメラを以前とは異なる場所に置くと、少し不審なことがあります。
(画像:光リーク可視化)
あれ!?そのアーチの下には明るい光はあってはいけないのに、完全に影に入っています。そしてそれが襲ってきます。祖母が火のそばで冷たい嵐の冬の日夜に話した物語から明確に思い出します。恐ろしい光リーク!もちろん!
つまり...
6. リーク問題
光リークとは何か、なぜ光リークするか?サーフェルは幾何学的には実質的に接続されていないので、3D スペースに浮遊しており、各サーフェルは独自です。もし恰好に壁の端にある場合でも、それが分かっているわけではなく、半径内を明るく収集して、要求する誰とでも光を共有します。要求する者がその壁の向こう側にある場合、それは影の中にいるべきであるはずが盲目になります。しかしまたサーフェルは周囲について知ることはできず、単に外宇宙に浮遊しています。しかし本当でしょうか?
チェックイン荷物サイズのトリックバッグの最後の手段を導入しましょう:サーフェルに距離感覚を与えます!これは EA SEED の GIBS の著者たちからの直前の解決策であり、彼らは VSM を使用しています。実際、この投稿で記述されたパイプライン全体は、以下で説明されているアプローチとほとんど同じです:Global Illumination Based on Surfels に関する講演はよく価値があります。
ともかく、これを修復するために放射状深さアトラスを実装します。それは各サーフェルに 360 度の小さな深さカメラを与えることを想像してください(テクスチャアトラス内の 4x4 ピクセルのタイルとして保存され、半球から正方形テクスチャへのマッピングはガイドリングデータと同様に)。サーフェルが光を見つけるためにレイを発射すると同時に、その周囲の幾何学的な距離を記録します。これらは Moment Shadow Mapping (MSM) を使用して保存しており、統計的モーメント(E[z], E[z²], E[z³], E[z⁴])を使用して、厳密な影の縁ではなく滑らかな可視関数を再構築し、サーフェル境界でのソフトトランジションを処理します。
(画像:放射状深さアトラス可視化)
後で、同じ「質問者」が再びサーフェルの光について尋ねると、この深さマップを確認して適切に反応できます。「いいえ、ここに壁がありますよ」と答え、その光を共有することを拒否します。これは特にメモリ面で重い数学的チェックですが、効果的に壁を通り抜ける光の侵入を防ぎます。
さて、これはどのように機能するのでしょうか?誰よりもこのアルゴリズム(およびいくつかの他のもの)を正確にモデル化する友好的なインタラクティブ可視化に質問するのが良いでしょう。
(画像:インタラクティブ深さチェック)
そしてこの技術を以前の不快なリークに応用すると、リークは消えました。動画では遮断「強度」パラメータを調整しているのでその段階的な効果が見えますが、実際の効果はほぼ瞬間的です。
(画像:修正された光リーク)
放射状深さを使用することで完全にリークが解決されているわけではありません。薄い幾何学は常に問題となりますし、困難な条件下で遮断システムの設定を正しくするには各シーンごとに多くの細かいハンドル調整が必要です。それでもこれは日と夜の違いです。その平均深度の方向ごとのデバッグ可視化も見ていて非常に魅力的です。サーフェルが周囲を囲む幾何学の端を素早く見つけるところに注意してください:
(画像:遮断エッジ検出)
このシステムはパイプラインで 2 回使用されます:1 つ目はサーフェルとサーフェルのバウンス、2 つ目は解決パスで行うサーフェルからピクセルの魔法です。そのことで!
7. ソルバー
今、世界中の微小な領域において間接光の有効推定量を持つ何千ものサーフェルが浮遊しています。彼らは賢く、ガイドリングされており、時系列に安定しています。しかしまだ空虚の中で円盤に過ぎません。私たちは円盤を見たくありません。レンダリングされたイメージが見たいのです。
我々はサーフェルの光を画面のピクセルへ転送する必要があります。これが解決(resolve)パスです。
素朴な世界では、各サーフェルを画面に投影して加算的にブレンドするでしょう(スplatting のように)。しかしそれは過描画の頭痛を引き起こし、隠蔽を困難にします。代わりに役割を逆手に取ります。画面のピクセルごとに計算スレッドを発射し、「私の近所は誰か?」と尋ねます。
以前構築した同じグリッド加速構造を使用し、各ピクセルは G-buffer の深さを使用してワールドスペース位置を計算し、そのセルを見つけ、そこに保存されているサーフェルを反復処理します。
(画像:解決パスの経路)
上記のインタラクティブな例は解決パスの 2D 簡素化であり、特定のピクセルの最終色を知るために取る経路が見えます。ピクセルからグリッドへ、そこからサーフェルへ旅し、重要なものを選び、それらの光を運び合わせて最終色にします。
このプロセスの失敗モードのいくつかは試すのに特に興味深いです:もし各ピクセルで評価する最大取得数(これは大幅なパフォーマンスハンドル)が存在する場所にあるサーフェルの数を下げる場合、素早い結果が得られますが、最も重要であるか全くないサーフェルを得たかどうかを知ることは決してできません。したがってピクセルはゼロの光を持って出力するかもしれませんが、ちょうど到達不可能な場所に明るいサーフェルがあった可能性があります。上記の可視化では明確にアーティファクトとして観察できます。
たとえ特定のセルのすべてのサーフェルを取得しても、単に平均化するだけではなりません。上記の例では重みは問い合わせ位置からの距離で決定されますが、完全な実装ではピクセルのためにサーフェルの有用性を決定するために多くのデータポイントを使用します。もし私が床のピクセルであれば、天井にあるサーフェルについては気にしないはずです。たとえグリッドセルを共有してもそうです。したがって距離に加えて、以下を使用できます:
- **方向:**サーフェルがピクセルと同じ方向に向いている場合は良い一致です。それらが垂直(床対壁)である場合、重みはゼロに低下します。
- **年齢と信頼性:**新生サーフェルはノイズがあります。数フレームをかけてその影響をフェードアウトさせ、ストロボライトのように出現しないようにします。
- **遮断:**第 6 章の放射状深さアトラスを再利用します。ピクセルがサーフェルに向かってレイを打つ;もしサーフェルが「あなたは見えない」と言えば重みはゼロになります。
私は... そう、それで終わりだと思います!解決パスとともに、紳士淑女の皆様、我々はレンダリングパイプラインを持っています!
みんなで今
さあ、全体のパイプラインを振り返って評価しましょう。
(画像:最終レンダリングシーン)
各フレームで:
- **G-buffer レンダリング:**標準的なラスター化が深さ、法線、アルベドをキャプチャします。
- **欠落の発見:**スクリーンスペース分析が必要に応じて新しいサーフェルを生成します。
- サーフェルのライフサイクル(3 パス):
- 準備:各フレームのカウンターをリセットします。
- 年齢:サーフェルが年齢を蓄積し、混雑したサーフェルはより早くなります。
- 割り当て:生成競争の勝者は実際のサーフェルを得ます。
- **グリッド構築(7 パス):**空間加速構造を再構築します。
- **統合(1 パス):**各サーフェルからのレイ追跡を行い、ガイドリングデータ、放射状深さアトラスとモーメントの時系列平均を更新します。
- **解決(1 パス):**サーフェルの放射度を画面のピクセルに転送します。
- **合成:**直接照明と間接照明を結合します。
これはフレームあたり 13 の以上の計算パス+BVH 探索作業です。これもそこで行われます。多いように聞こえ、実際に多かったと感じました。複雑な機械時計を構築することを想像すると非常に類似した感じになります。しかし時計には数百の部品を持つことができ、現代のAAA ゲームでは一フレームで数十個の計算シェーダを配置します。したがって、実際にはあまり多くなく、 decent GPU 上では完全に 60fps で合理的に複雑なシーンで快適に走ります。
オウルの残り
それだけのことです、皆様!
さて、すべてではありません。我々はパイプラインの主要なビルディングブロックをカバーしましたが、この投稿が小説にならないようにいくつかの詳細を略しました。あなたが同意するでしょう、ここでは無視した他のビット(サーフェルの寄与をどのように重み付けするか、最終イメージが合成される方法、なぜ青ノイズを使用するか、間接計算ディスパッチの詳細、サーフェル住宅市場全体の説明が欠けており、など)はコードを通じて自分自身で語らせてください、勇敢な冒険家たちがそこを探検することを恐れないでください。
デモは Chrome、Firefox、Safari でうまく動作します。これは別の旅ですが、私に同行させることよりも好意的ではありません。その中にさらなるドラゴンがあります!このような複雑なパイプラインが全く動作すること自体が、WebGPU の人々と彼らの年間の努力に対する証です。あなた方全員に拍手を送ります。
それは mobile Safari 上でも動作し、Cornell Box シーンで古い iPhone 14 で約 60fps を得ていますが、シーンスイッチングには問題がありデバッグが困難でした。Sponza を試してください。もしかしたら面白いかもしれません!
このものはノッチがたくさんあり、怖がらないでください。これがある理由はそこにあるためです。特に様々なデバッグモードを見逃さないでください。それらは特定のサブシステムを照らし出します。
限界と今後の仕事
全体的に WebGPU インプリメンテーションの成熟度と機能セットには感動していますが、このプロジェクトを通じて最も戦っていたのは、Chrome における計算パスあたりストレージバッファ数の硬性制限が 10 のことです。これはジレンマです:これを Chrome に対して解決するために、興味深い解決策を使う必要があり、例えば読み書き可能な float ストレージテクスチャを使用します。しかしクロスブラウザテスト中に、これが Firefox や Safari(これらは他の多くの結合ストレージバッファをサポートできます)では絶対に機能しないことに気づいた後、再び可能である限りバッファを合併する必要がある。私はグラフィック開発者にとってはこのような制約との戦いは全てよく知られていますのであまり不満を述べませんが、プラットフォームにバインドレスがあることを知っていましたか?
他のことはもちろんハードウェアレイトレーシングへのアクセスの欠如です。three-mesh-bvh は素晴らしいですが、ハードウェアの速度には追いつけません。これらが組み合わさると、多くの光源や動的シーン(照明だけでなく幾何学も移動する)などの機能をサポートすることは非常に困難、あるいは不可能になります。
ここで構築したレンダリングパイプラインは、グローバルイラミネーションに関しては静的な幾何学の拡散(インター)反射のみを考慮しており、単一の方向光源と環境マップによって引き起こされます。スパチュラ/GLOSS 反射、透明性、環境遮断、自己発光はありません。そしてシステムは速く動く光源で破れ、高周波のディテールが好きではなく、薄幾何学も好まない。
それはすべてにもかかわらず、しかし我々はこのプロジェクトとそのアプローチがさらなる実験のための確固たる基礎であることを信じています。計算パスずつ境界を推し進めています。
終わり
光子の星の誕生からブラウザで実行されるリアルタイムグローバルイラミネーションまでの旅をしました。その間に空間加速構造、放射状深さ遮断、モーメント影マッピング、時系列フィルタリング、その他の楽しい部分を遭遇しました。すべて約 3000 行の TypeScript と WGSL で実装されています。
十分か?もしかしたら。速いのか?あなたの定義による。エキサイティングか?確かにそう思っています。物理的に合理的な光のバウンスと時系列安定性をリアルタイムでウェブページに、携帯電話に...得られるという事実が、我々実際に未来にいるような気がします。
私が残したいのは、2025 年 8 月の SIGGRAPH の早朝ハックで作成された最初のサーフェルのスクリーン録画です。美しいではありませんか?ああそして最後に GPU クラッシュがあります。
*"まず存在させてください、後で良くなります"*はアート界のインターネットですが、このプロジェクト全体は確かにその一つでした。長期間存在するだけのように見えました。しかし今は「後で良い」も起こり始めました。
WebGPU はウェブ上の高忠実度グラフィックエンジニアリングに真に扉を開きました。単に三角形を描画することに制限されていません;数年前に不可能 seemed だった複雑な計算駆動のパイプラインを構築できます。
初期のウェブグラフィック時代の霧は晴れ、光子は自由に roaming を行うことができます。さてでは、何を作りますか?
クレジット
このプロジェクトは巨人たちの上に立っています:
- サーフェル GI アプローチを設定した元の GIBS プレゼンテーションを提唱した EA SEED
- 優雅なハッシュグリッド実装とサーフェル化アプローチのための Tomasz Stachowiak と Kajiya レンダラー
- three-mesh-bvh のための Garrett Johnson と貢献者、これなしでは不可能です。
- WebGPU をアクセス可能にする Three.js チーム
- この冒険全体を開始した SIGGRAPH ポスターの SurfelPlus 著者
- ブラウザで動作するという事実がまだ私を驚かせている WebGPU 仕様と実装に取り組むすべての人々!
- そして最後に Blaž、Darko、Ricardo、Aleks、Zarja、Tina、そして Aras がこの投稿の初期草案に優れたフィードバックを与えました。ありがとう!
サポート
この投稿を楽しみましたか?私の執筆や実験をサポートしたい場合は Ko-fi で行うことができます。