ライトニングは、ゲームの最も重要な要素の 1 つです。ムードの設定、プレーヤーの主導、脅威や目標の特定などが可能です。ライトニングはゲームのビジュアルを左右します。たとえば、ライトニングが適切であればモデルが不十分でもゲーム内の見栄えを良くすることができますが、そうでない場合は優れたモデルでも見栄えが悪くなります。
このガイドでは、モバイルゲームでより適切なライティング パフォーマンスを実現する方法について説明します。ライトニングの使用方法は、モバイルゲームのパフォーマンスに影響します。ゲームをできるだけできる限りスムーズに実行するには、ライトニングを効果的に使用することが重要です。
レンダリング パイプラインのオプション
Unity の従来のレンダリング パイプラインには、次のレンダリング パスが含まれています。
- フォワード レンダリング
- ディファード シェーディング
フォワード レンダリング
フォワード レンダリングでは、リアルタイム ライトは非常に高コストになります。ピクセルごとのライト数を減らすと、このコストを相殺できます。
ディファード シェーディング
ディファード シェーディングには GPU サポートが必要です。互換性のあるハードウェアでは、ディファード シェーディングによって、高レベルのライティング忠実度を持つ多数のリアルタイム ライトをレンダリングできます。残念なことに、モバイル GPU は帯域幅が小さいため、ディファード シェーディングはうまく機能しません。
モバイル タイトルを開発する場合は、できる限り多くのデバイスでゲームをスムーズに実行することが重要です。
ユニバーサル レンダリング パイプライン
Unity は、ユニバーサル レンダリング パイプライン(URP)を開発しました。モバイルゲームには URP を使用することを強くおすすめします。
ライトモード
シーンの中での光の動きや使い方によって、ライトモードを使い分けます。 ライトモードにはさまざまなパフォーマンス特性があります。ライトを実装する場合は、以下の点を考慮してください。
- 静的ライトニングには baked を使用します。これは、ランタイム中にライトニングを変更しないオブジェクトに最適です。ライトのベイクは、ライトマップと呼ばれるテクスチャ マップにライトニング データを事前計算して保存するプロセスです。
- ベイクしたライティングは、ランタイム時に変更することはできません。ライトマップのライトとシャドウは静的です。ライティングはすべて Unity で前処理されているため、ランタイム時のライティング計算はパフォーマンスに影響しません。
- 動的シャドウは、ベイクしたライトで作成することはできません。これは、動的オブジェクト、つまり移動するオブジェクトでは不自然に見えることがあります。
- 移動するオブジェクトを操作する予定の固定ライトには、混合を使用します。
たとえば、プレーヤーに光を当て、プレーヤーの動きに合わせてシャドウを生成するトーチなどです。
- 混合ライティングにより、動的な直接光とシャドウが生成されます。
- 静的オブジェクトのライトマップ計算に混合ライトニングを含めることができます。
- ランタイム時の強度を変更できます。直接光のみが更新されます。
- 高コスト。
- 地面から上昇して爆発する火の玉から放たれる光など、動的または移動可能なライトにはリアルタイムを使用します。
- 動的ライトとシャドウのプロパティはランタイム時に変更できます。
- リアルタイム ライトは、ライトマップにベイクされません。
- 非常に高コスト。
詳しくは、Unity のライティング パイプラインをご覧ください。
可能であれば、静的ライトを使用し、動的ライトを使わないようにする
動的(リアルタイム)ライティングはフレームごとに計算されて更新されます。これは、オブジェクトを移動したり、インタラクティビティを高めたり、感情を生み出したりするのに効果があります。
これに対して、静的ライト情報はライトマップにベイクされます。ライトマップ テクスチャを使用することで、オブジェクトでの高コストな頂点ごと、ピクセルごとのライティング計算を回避できます。ライトマップ テクスチャのレンダリング コストは常に、動的ライティングよりもはるかに低くなります。モバイルゲームに実装する場合は、ベイクしたライティングを第一候補とすることをおすすめします。
ライトマップのベイク
ライトの効果を事前計算することを、ライトマップのベイクといいます。ライトの効果は、ライトマップと呼ばれる別のテクスチャに格納されます。ライトマップは、オブジェクトの外観を向上させるために使用できます。ライトマップのベイクは、シーンのイテレーションごとに 1 回行うだけで済みます。シーンのジオメトリを変更する場合、またはベイクしたライトのパラメータを変更する場合は、ライトマップを再ベイクする必要があります。ライトマップ テクスチャのオーバーヘッドを除いて、ランタイム時に余分なパフォーマンス コストは発生しません。これは、モバイル プラットフォームでのライティングにおいて最初に行う方法として最適です。
ベイクしたライトは、シーンの動的な側面や移動の側面による影響を受けません。 ベイクしたライティングには、すべての静的要素に対するベイクしたグローバル イルミネーションが含まれます。つまり、ライトマップの計算には、オブジェクトに直接当たるベイクしたライトだけでなく、他の静的オブジェクトに跳ね返った間接的なライトも含まれるということです。
図 1. Armies の技術デモで使用される、すべてがベイクされたライトニングの設定
ライトをベイクするには、次の 3 つの手順を行います。
ステップ 1: ライトを Mixed または Baked に設定する
ライトの [Mode] を [Mixed] または [Baked] に設定します。モバイル タイトルの場合、「Mixed」よりも「Baked」ライトを使用することをおすすめします。Baked は、最もコストのかからない、ライトのレンダリング方法です。
図 2. Unity でのライトのモード設定
ステップ 2: オブジェクトを静的にする
ベイクしたライトの影響を受けるオブジェクトをすべて静的にします。静的としてマークされたオブジェクトの最適化は多数ありますが、通常は [Static] プルダウン リストで [Everything] を選択することをおすすめします。オブジェクトが [Static] とマークされている場合、Unity はそのオブジェクトがライトのベイクの対象であると認識します。
図 3. 静的メニューの例
ステップ 3: ライトをベイクする
ライトをベイクするには、[Window] > [Rendering] > [Lighting Settings] の [Lighting] メニューを使用します。
ライトをベイクする場合、保存されるデータは、ベイクの開始時にアクティブだったシーンに基づきます。フォルダは、ベイクされるシーンと同じ名前で生成されます。このフォルダには、ライティング データのコンポーネントがすべて格納されます。プロジェクトで同時に複数のシーンを読み込む場合は、各シーンのライトをベイクする必要があります。シーンを調整するときは、ライトを再ベイクする必要があります。
図 4. ベイクしたライトマップの例
ライトマップを最適化する
ライトをベイクするように設定したら、ベイクされるマップが最適化されていることを確認します。ライトマップは、ベイク時の設定に応じてサイズが変わります。モバイルではメモリ使用量を抑える必要があります。そのため、ライトマップのサイズを監視する必要があります。
次の Armies デモの例では、1024x1024 ピクセルのライトマップが 7 つあります。マップのプレビューでは、ライトマップに配置されたメッシュを確認できます。 選択したメッシュがハイライト表示されます。
図 5. ライトマップの一例。青い部分が選択したメッシュ
[Lightmapping Settings] には、マップのサイズと、各マップが使用するメモリとストレージ容量を決定する設定が数多くあります。 以下のセクションでは、いくつかの重要な設定について説明します。
ライトマッパー
Unity には、シーンのライトをベイクするために以下の 3 つの方法があります。
- Enlighten: 2020 LTS(長期サポート)リリースまでしかサポートされません。新しいプロジェクトには使用しないでください。
- Progressive CPU: ライトのマップが段階的に作成されるため、時間を大幅に短縮できます。 [Prioritize View] が選択されている場合は、シーンビューの領域が優先されます。これにより、シーンのライトを設定するイテレーション時間を短縮できます。
- Progressive GPU: これはプログレッシブ CPU と同じように機能しますが、ライトマップの生成は CPU ではなく GPU で行います。サポートされているハードウェアでは、この方法を使用すると CPU を使用する場合と比較して、ベイク時間を大幅に短縮できます。 プログレッシブ GPU の設定には追加の要件があります。要件について詳しくは、プログレッシブ GPU ライトマッパーのページをご覧ください。
図 6. ライトマッパーの設定では、シーンのベイク方法を変更できる
テクセル
テクセル(テクスチャ ピクセル)とは、テクスチャ マップ内の個々のピクセルを指します。テクセルは、オブジェクトに当たるライトの点ごとに、ライトマップにライト情報を保存します。単位面積あたりに使用するテクセル数が多いほど、ライティングの質、ベイクにかかる計算時間、ディスク ストレージのコスト、ライトマップの VRAM コストに影響します。
必要なライトマップ データの量を減らすには、[Lightmapping Settings] でベイクの単位あたりのテクセル数を調整します。
図 7. ライトマップで利用できる設定
[Lightmapping Settings] の [Lightmap Resolution] パラメータは、ライトマップに使用する単位あたりのテクセル数を制御します。以下は、[Lightmap Resolution] 設定がそれぞれ違うキューブの例を示しています。解像度を高くすると、必要な作業量が急激に増加するのがわかります。
図 8. 最初の立方体の [Lightmap Resolution] は
1 です。2 番目の立方体の [Lightmap Resolution] は
2 です。3 番目の立方体の [Lightmap Resolution] は
5 です。
シーン内でテクセルがどのように配置されているかを確認するには、[Scene] ビューで [Draw Mode] プルダウン リストを選択し、[Baked Lightmap] を選択します。
ベイクしたオブジェクトはチェッカーボードのオーバーレイで覆われています。チェッカーボードのパターンは、ライトをベイクしたときにテクセルがどのように分布するかを示しています。
次の例で、Armies デモの [Lightmap Resolution] を
15 から
12 に下げると、必要なマップ数が 7 から 4 に減少します。
図 9. [Lightmap Resolution] が
12 の Armies デモ
テクセルの使用
シーン全体で単位あたりのテクセル数を設定することもできますが、そこまでのテクセル数を必要としないオブジェクトも多々存在します。
Unity では、各オブジェクトで使用するテクセル数を制御できます。オブジェクトの [Inspector] > [Mesh Renderer] にある [Scale In Lightmap] パラメータ値により、オブジェクトがライトマップで使用するテクセル数が制御されます。
以下の例で、左側の立方体のライト情報は、ベイク単位あたり 5 テクセルです。右側の立方体では、[Scale In Lightmap] が 0.5 に設定されています。この設定により、ライトのテクセルが 2.5 にスケーリングされるため、左側の立方体よりもライトマップのスペースが少なくなります。
図 10. ライトマップ解像度が異なる 2 つの立方体
図 11. [Scale In Lightmap] 設定を変更して、オブジェクトのテクセル数を減らすことが可能
次のような場合にテクセルを使用しないようにしてください。
- プレーヤーに見えないサーフェスとオブジェクト。これにより、画面に表示されていない細部のライトマップにメモリを無駄に消費することがなくなります。
- ライトの変化が少ないサーフェス。たとえば、シャドウ内のオブジェクトや単一の光源に接触しているオブジェクトなどです。
- 小さなオブジェクトまたは細長いオブジェクト。これらが受けるライトニングの量は、シーンの最終レンダリングにはあまり影響しません。
できる限りライティングにフェイクを使用する
処理要件を減らすために、いくつかの要素にフェイクを使用できます。これにより、ライトを使用したコンテンツのように見えても、実際にはより効率的な方法が使われています。
フェイク シャドウ
リアルタイム シャドウは高コストです。シャドウ マッピングと呼ばれる手法を使用して生成されます。シーンのジオメトリをシャドウマップにレンダリングするコストは、シャドウを有効にして描画された頂点の数に比例します。シャドウを投影するジオメトリの量とリアルタイムのシャドウを投影するライトの数を制限することをおすすめします。
動的ライトを使用せずに、動的オブジェクトのシャドウにフェイク シャドウを実装できます。これにより、レンダリング コストを低く抑えることができ、動的シャドウと同様の効果を得られます。フェイク シャドウを実装する方法には、以下のようなものがあります。
- Plane や Quad などの 3D メッシュをキャラクターの下に配置し、そのテクスチャにぼかしを入れます。
- 独自のカスタム シェーダーを作成して、より高度な輪郭のぼやけたシャドウを作成できます。
次の例は、3D メッシュをシャドウに使用した場合の結果を示しています。
図 12. Armies 技術デモにおけるシャドウの実装
テクスチャ上にライト情報を直接ペイントする
シェードの一部をテクスチャに描画すると、余分なライトに必要な計算を減らすことができます。シーンのライトをベイクする際に必要なライトマップ データが少なくなるため、メモリを節約できます。
ライトプローブ
動的オブジェクトにベイクしたライティングを使用すると、ライトマップの影響を受けません。そのため、シーンの一部ではないように感じられる可能性があります。
この問題はライトプローブで解決できます。ライトプローブにもライトマップと同様のメリットがあります。これは、事前に計算して、ランタイム時に使用するために保存できるライトデータを格納します。これにより、計算コストの大部分が編集に費やされます。
ライトマップが表面のテクセルで受けるライトをエンコードするのに対し、ライトプローブは何もない空間を通り抜けるライトを格納します。このデータを使用して、移動するオブジェクトにライトを当てることができます。ライトプローブを使用すると、動的オブジェクトをシーン全体のライトマップされたオブジェクトと視覚的に統合できます。
ライトプローブは、シーン内の移動しているオブジェクトを照らすのに最適です。このプローブは、ベイクしたライトを利用しているため、移動しているオブジェクトにシーンと同じライトを当てることができます。ライトプローブを使用した動的オブジェクトのライティングは、リアルタイム ライトよりも低コストです。
図 13. Armies 技術デモにおいて動的な群衆を照らすために配置されたライトプローブ
メッシュ レンダラの設定
シーンで使用するライトのタイプに関係なく、[Mesh Renderer] の設定を正しく行うことが重要です。
使用していないものはオフにします。[Cast Shadow] などの設定では、オブジェクトが照らされていなくても、シーンをレンダリングする際にコストがかかります。次の [Meche Renderer] 設定の例は、図 13 に示したキャラクターを対象としています。このキャラクターではライトプローブ データを使用しますが、リフレクション プローブは使用しません。
[Light Probes] の設定を [Blend Probes] にすると、最も近いライトプローブのライト情報がキャラクターに合わせられます。キャラクターがシーン内を動き回ると、キャラクターに影響を与えるライトプローブが変化します。レンダリングでは blob メソッドを使用するため、[Cast Shadows] はオフになります。シーンがベイクされ、リアルタイム シャドウがないため、[Receive Shadows] もオフになります。
図 14. 図 13 のレンダリング用の [Mesh Renderer] 設定
リアルタイム ライトとライトタイプ
ライトのタイプによって、ライティング計算コストが異なります。各ライトタイプの詳細は次のとおりです。
- ディレクショナル: このライトは方向性が均一で、減衰しません。 ディレクショナル ライトは、最も低コストなリアルタイム ライトです。多くの場合、シーンごとに 1 つのディレクショナル ライトがあれば済みます。モバイル向けに推奨されているレンダリング パスであるフォワード レンダリングでは、シーン内にディレクショナル ライトがない場合、Unity によりデフォルトのディレクショナル ライトが含まれます。
- スポット: スポットライトはその円錐の外側にあるオブジェクトを除外して光を当てません。 これにより、スポットライトは球形のポイントライトよりも計算コストが抑えられます。最高のパフォーマンスを得るには、円錐の幅を狭くして、目的のオブジェクトのみを照らすようにします。
- ポイント: 全方向に光を放ちます。全方向への照明は便利ですが、非常にコストがかかります。ポイントライトは広い領域にわたるため高コストです。さらに、シャドウの計算はライティングの中で最もコストがかかる部分です。全方向に光を当てればシャドウが多くなり、計算量が増えます。