Wonderland Engineによるバーテックスカラーのライティングベイク
Colin Freeman、Ayushman Johri、そしてJames Kaneは、彼らのMini-Golfゲーム”Above Paradowski”で、素晴らしいテクニックを使ってシーンのライティングをベイクしました。彼らはフラグメントシェーダー内でのライトマップテクスチャのルックアップを削減しながら、非常に洗練された体験を実現しました。
この記事では、この手法がいかに賢明かを紹介し、Wonderland Engineでの使用方法を解説します。


Blenderでの浮遊島のスクリーンショット: フラットライティング(左)、バーテックスカラーでベイク(右)。
動機
ライティングの計算は非常に時間がかかります。現実的な結果を得るには、光の経路とバウンスをトレースし、各バウンスごとにさらに多くの計算が必要になります。この過程で計算量が爆発します!
これはアニメーション映画がレンダリングされる方法ですが、リアルタイムVRではフレームあたり数分ではなく、90 HzのスタンドアロンVRデバイスで11ミリ秒で2フレーム(左目と右目)をレンダリングしなければなりません。GPUレンダーファームの代わりにモバイルGPUを使用します。
VRで快適さと没入感を保つために60-90 Hzを維持することが重要であるため、異なるアプローチが必要です。Wonderland Engineはすでに多くの優れた方法や最適化を実装しており、リアルタイムシャドウでも高速にレンダリングできますが、非常に大規模なシーンでは可能な限りのパフォーマンスが必要です。
ライトのベイク
ランタイムでライティングを計算する代わりに、事前に計算して結果をアセットに保存することができます。例えば、シャドウをテクスチャに描画または計算することによって行います。このプロセスは「ベイク」と呼ばれます。
3Dアニメーションで使用される同じ手法を使用することで、非常に現実的な結果を得ることも可能です。
テクスチャは、細かいシャドウやライティング効果を保存するのに適しており、特にWonderland Engineのテクスチャストリーミングを使用すると、非常に高解像度のテクスチャを使用して驚くほど美しいシーンを演出できます。
しかし、テクスチャは大量のデータを保存する必要があり、圧縮されていても、多くの場合効果がありません。そこで、ダウンロードサイズを削減するために、細部を犠牲にして各頂点に追加のカラー属性を保存できるのです。
ライトマップテクスチャとバーテックスカラーの比較
テクスチャにライティングをベイクする場合、GPU上でのライト計算は主にテクスチャの読み取りに減少します。スクリーンに描画する各ピクセルごとに、正しいピクセルをライトマップからルックアップします。 描画される各ピクセルは、ライトマップから異なる色を取得できるため、非常に高い周波数のディテールが可能です。
一方、バーテックスカラーは頂点シェーダーへの入力としてバーテックス間で補間されます。ディテールの周波数はメッシュの解像度に依存し、一般的に非常に低くなります。これにより、ピクセルカラーの計算は、頂点シェーダーから出力バッファへと補間されたカラーを通過させるだけになり、さらに簡略化されます。
パフォーマンス
どちらが性能に優れているか?どちらも正しい答えは「状況次第」です。特にボトルネックによります。
今日の多くのWebXRアプリは、描画コールで制約を受けています:CPUがこれ以上の作業を行うことができないため、GPUの作業を最適化しても効果がありません。 バッテリー寿命に影響する可能性はありますが、フレームレートには影響しません。
Wonderland Engineは、その最適化により、ほとんどのケースでわずか数回の描画コールで数万の動的オブジェクトをレンダリングすることにより、これを完全に解決します。他のアプリが、多くのアニメーションキャラクターをスキニングすることによって制約されている場合、数百の異なるスキンメッシュを効率的に処理できる高性能なVR最適化スキニングメソッドで解決します。
しかし、Wonderland Engineのアプリでも、断片シェーディングに制約されることがあります。フラグメントシェーダーでの指示や高コストの操作がスクリーン上の各ピクセルごとにGPUの計算能力をより多く必要とします。我々の「Physical」(PBR)シェーダーは「Phong」よりも多くの指示を持っており、「Flat」よりも多く持っています。
現代のGPUはテクスチャの読み取りが非常に速いものの、頂点フェッチ中にメッシュデータから色を単に読み取ることは、キャッシュ効率が良く、特にメッシュからノーマルやテクスチャ座標を完全に省略できる場合には非常に有利です。この手法のために、位置と色のみを必要とする非テクスチャ化されたFlatシェーダーを使用できます。
これにより、頂点ごとの読み取りメモリ量が減り、フラグメントごとの作業量がほとんどありません。これにより、頂点シェーディングまたは頂点フェッチによってのみ制約されますが、概要で示す非常に大きな頂点数のシーンでのみです。
チュートリアル
Blenderでバーテックスカラーにライティングをベイクし、そのモデルをWonderland Engineにインポートする手順を始めます。
Blenderでバーテックスカラーへのベイク
シーンを選び、ライトを設定します。Blenderはすでにバーテックスカラーへのベイクを完全にサポートしているため、プラグインは不要で、設定は簡単です。
- Blenderでスクリプトウィンドウを開き、以下のPythonスクリプトを使用してすべての選択されたオブジェクトにバーテックスカラーレイヤーを追加します。このスクリプトを実行してください:
import bpy
for o in bpy.context.selected_objects:
if o.type != 'MESH':
continue
if len(o.data.vertex_colors) != 0:
continue
o.data.vertex_colors.new() - レンダープロパティで、レンダリングエンジンをCyclesに変更
- 下部のベイクセクションを見つけ、Output > Targetをバーテックスカラーに切り替え
- ベイクタイプをディフューズに設定
- このセクションの上部にあるベイクボタンを押す
結果を確認するには、ビューポート設定を変更して結果を視覚化します:
- 3Dビューポートで、レンダータイプの横にある矢印をクリック(通常、トップメニューで最も右にあるボタン)
- ライティングをフラットに選択
- カラーをバーテックスに選択

最後に、モデルをGLBとしてエクスポートします:File > Export > glTF 2.0 (.glb/.gltf)を選択します。
Wonderland Engineへのインポート
プロジェクトのshadersサブフォルダーに次のVertexColor.fragを作成します:
#include "lib/Compatibility.frag"
#define USE_COLOR
#define USE_MATERIAL_ID
#include "lib/Inputs.frag"
void main() {
outColor = fragColor;
} 次に、このモデルをWonderland Engineにインポートし、このシェーダーを使用してレンダリングします:
.glbファイルをアセットブラウザーにドラッグ&ドロップ- そのファイルをシーンビューにドラッグ
- ビュー>リソース>パイプラインに移動し、Phong OpaqueまたはPhong Opaque Texturedを選択、オブジェクトが初めにテクスチャを使用していた場合に応じて選びます。
- シェーダーを新しい
VertexColorシェーダーに変更する。
既存のPhongパイプラインを変更することによって、すべてのマテリアルを自動的に変更できます。よりクリーンなセットアップとして、自動作成された「VertexColor」パイプラインを割り当て、それを変更したい材料すべてに適用することが可能です。
これで、シーンにバーテックスカラーが正しく適用されているはずです。

まとめ
バーテックスカラーにライティングをベイクすることは、美しいビジュアルを達成するための非常に効率的な方法です。 以下のビデオは、Meta Quest 2のMeta Quest Browserでこの方法を用いて3.6百万頂点が60-72 fpsでレンダリングされる様子を示しています。
このデモは、Wonderland Engineの直感的な最適化、固定フォービエーション(1.0)、そしてこのブログ記事で説明された方法を使用しています。 シーンは2回の描画コールでレンダリングされます(バージョン0.9.4時点、将来のマルチビューに対するサポートによりこれが50%削減される予定です)。 すべてのオブジェクトは、スクリプトやアニメーションを通じて独立して移動でき、パフォーマンスに悪影響を与えません。