VRゲームのグラフィックを強化しよう(後編)
前回は、アニメーションの付いた3Dキャラクターモデルを設定し、それをエネミークラスと連携させる方法を解説した。今回は、背景モデルにライティングを行うことで、ゲームの見た目をよりリッチにしてみよう。なお今回の解説では、Unityアセットストアで無料公開されているStylized cityを使用する。こちらを利用したい人は、事前にアセットストアから入手し、プロジェクトにインポートしておこう。
ライティングとは
CGのライティング(Lighting)とは、その名の通り「照明」の効果をシーンに適応することだ。例えば、現実世界では屋内において天井の照明や暖炉の火の有無などで部屋の見え方が大きく変わってくるし、屋外では太陽という「照明」が時間によって変化することで朝・昼・夜といった異なる状況が生まれる。ライティングは、このような光による変化をCG空間上で再現するための手段なのだ。
しかし、リアルタイムで描画されるCGの照明は現実と異なる働きをしているため、それを理解するためにはいくつかポイントを抑えておく必要がある。なお、ライトそのものに関する基礎的な内容はここでは解説しない。Unityの公式ページなどで確認してほしい。
直接光と間接光
ゲームエンジンにおける光には、「直接光」と「間接光」の2種類がある。ここでは、ライトから直接照射される光が直接光
で、その直接光が物体に当たって跳ね返った光を間接光
としておこう。間接光は光が跳ね返る分だけ何回も計算を行う必要があり、リアルタイムCGで表現するのは難しい。そのため間接光を事前に計算してデータに保存しておき、ゲーム中で表現できるようになっている。このような直接光と間接光の表現を、一般的なCGではグローバルイルミネーション(GI)表現
と呼ぶので覚えておこう。Unityでは「リアルタイムGI」「ライトマップ」「ライトプローブ」の3種類の方法でGI表現ができるが、リアルタイムGIはモバイルVRには処理負荷的に適さないため除外し、ライトマップとライトプローブの2つの方法を解説していく。
リアルタイムライトとベイクライト
ライトにも「リアルタイムライト」「ベイクライト」と、この2つ両方の性質を持つ「ミックスライト」の3種類がある。これらを見分けるために、ライトのインスペクタの「Mode」に表示されている項目を見てみよう(図1)。リアルタイムライトは、直接光として常にオブジェクトに対して光を照射し、リアルタイムGIの間接光にも影響を与える(ここでは詳しくは解説しない)。
ベイクライトは、ライトマップやライトプローブを作成するときに使用されるライト
だ。ライトマップ
とは直接光および間接光を事前に計算し、その結果をテクスチャとして保存したものだ。一方ライトプローブ
は直接光と間接光の情報を「空間」に保存する。このように事前に計算し保存しておいた光の情報を使用することで、ゲーム中に直接光+間接光の表現をリアルタイムで行えるわけだ。ミックスライトは前述した通りリアルタイムライト・ベイクライトの2つの性質
を持つ。
staticオブジェクトとnon-staticオブジェクト
ライティングに関する最後の解説として、static / non-static オブジェクトについて説明しておこう。その場から動かないオブジェクトをstaticオブジェクト
、そうでないものをnon-staticオブジェクト
と呼ぶ。具体的には、背景モデルなどゲーム中には絶対にその場から動かないモデルがstaticオブジェクト、キャラクターモデルや背景モデルでもドアや宝箱といったアニメーションを行うオブジェクトがnon-staticオブジェクトだ。このようにモデルを2つに分けるのは、主に描画負荷を減らすための仕組みである「ドローコールバッチング」が動作するようにするためだ。staticになっているオブジェクトは、たとえ異なるオブジェクトでも諸条件さえ揃えば自動で描画をひとまとめにするドローコールバッチングが行われる。それにより処理負荷軽減の恩恵を受けるため、背景などの動かないオブジェクトは必ずstaticオブジェクトにする必要がある。
ライティングの話に戻ろう。staticオブジェクトはライトマップ
、そしてnon-staticオブジェクトはライトプローブ
によってライティングを表現する。すべてのゲームオブジェクトは、何もしなければ常にnon-staticオブジェクトの状態だ。インスペクタの右上に表示されている「static」オプションを押下すれば、staticオブジェクトにできる。
ライティングのポイントまとめ
これまでに解説したポイントをまとめると、以下のようなマトリクスになる。
オブジェクトの種類 | 表現方法 | 具体例 |
---|---|---|
static | ライトマップ | 背景モデルなど |
nonstatic | ライトプロープ | キャラクターモデル・動く背景モデルなど |
※リアルタイムGI を使用するケースは含まず
背景モデルをライティングしてみよう
ライティングに関する大まかな概要が掴めたところで、実際にシーンをライティングしてみよう。今回使用する背景アセット「Stylized Simple Cartoon City」は、Assets > Area730 > Stylized city > Prefabs
にモデルのプレハブが保存されている。新規のシーンを作り、そこへプレハブを組み合わせて配置し、背景シーンを組み立ててみよう。
なお、ヒエラルキーパネル上のCreate Empty
で空のトランスフォームを作成し、そこに背景のオブジェクトを入れておくとヒエラルキーがすっきりするので、こちらもやっておこう(図2)。
背景オブジェクトはstaticオブジェクト扱いとなるので、ルートとなるトランスフォームを選択してから、インスペクタ上のstaticのチェックボックスを有効にしておこう(図3)。また、この時ダイアログで「Yes, change children」を選択し、子オブジェクトすべてに対してstaticが有効になるようにしよう(図4)。
最後に、シーンの保存も忘れずに。
アセットの最適化
次は、アセットの最適化だ。本アセットの殆どのマテリアルはStandardマテリアルと呼ばれるPBR表現(物理的に正確な光表現)が行えるマテリアルで構成されているが、重すぎてモバイル用途には向かないため軽量なマテリアルに変更する必要がある。
Assets > Area730 > Stylized city > Materials
の中にあるマテリアルアセットをすべて選択し(この時フォルダは選択しないように)、マテリアルのシェーダを{Legacy Shaders > Diffuse
に変えておこう(図5)。
最後に、Assets > Area730 > Stylized city > Models
からマテリアルの時と同様にすべてのモデルアセットを選択し、インスペクタから{Generate Lightmap UVs
にチェックを入れてApplyしておこう(図6)。これは、後で解説するライトマップが正しくモデルに反映されるようにするためだ。
なお、自前の背景モデルを使用する場合も、上記の処理をマテリアルとモデルにも行えばOKだ。
ライトの配置
それでは、いよいよライトを配置していこう。まずは、Create > Light > Directionl Light
で、直接光となるライトを配置してみよう。Directional Lightは太陽光などの平行光源を表現するのに使われるライトで、今回のような屋外のシーンをライティングするのにピッタリだ。
この光源の特徴として、ライトを回転させることで光源の向きを調整できる。また、Intensity
で光源の強さを、Color
で色を変えることができる。今回は夜のシーンを表現したいので青めのライト設定にした。最後にライトのインスペクタからMode
をBaked
に、Shadow TypeをSoft Shadow
にしておこう(図7)。これで、後でライトマップを生成したときにライトが当たったオブジェクトから影が落ちる設定になった。これ以外にも自由に任意のライトを配置して良いが、必ずベイクライトにするように注意しよう。
そして、ライトもまた専用の空トランスフォームの下階層でまとめれば、管理が楽になる。
ライトプローブの作成
次は、non-staticなゲームオブジェクトの環境光を設定するために、ライトプローブを設置してみよう。ヒエラルキーパネル上でCreate > Light > Light Probe Group
と進み、ライトプローブを作成する。ライトプローブを選択したら、インスペクタ上からEdit Light Probeを実行しよう。
シーンビューに黄色いスフィアで表示されているのがライトプローブで、このライトプローブに囲まれたエリアの環境光をサンプリングし、それをゲームオブジェクトに照射する。そのため、このライトプローブはできるだけnon-staticなオブジェクトが存在する可能性のある空間をカバーするように配置するのが望ましい。スフィアを選択して位置を調整してみよう(図8)。マップが複雑な場合はライトプローブの数を増やしてライトプローブグループの形状を変えることもできるが、ライトプローブの数が増えれば処理負荷も上がるため、注意が必要だ。
今回はモバイルでビルドすることに加えて、ライトプローブグループが1つでもシーンに存在すれば自然な環境光を作り出してくれるため、最小の8個のライトプローブでライトプローブグループを作成した(図9)。
ライトプローブからの環境光を実際に確かめるためには、この後のライトマップの作成が終わるまで待つ必要がある。
ライトマップの作成
ここからの解説はUnity 2017以降を対象としている。それ以前のバージョンでは操作方法が異なるので注意。
Window > Lighting > Settings
へ進み、ライティングの設定画面が開く。次の点に注意して設定してみよう(図10)。
- Skybox Material
・SkyboxはCG空間で最も奥で描画され、文字通り空などを表現するときに使用する。ただし、Default-Skyboxは描画コストがかかるため、モバイル向けの場合はNoneにしておくほうが無難だ。 - Environment Lighting
・ここでは環境光を設定する。ここでの設定はライトマップ・ライトプローブに影響を与える。
・Source は Color にし、Ambient Colorで環境光の色を指定する
・Ambient ModeはBakedにしよう。 - Realtime Lighting
・Realtime Global Illuminationのチェックを外す(リアルタイムGIは使用しないため)。 - Mixed Lighting
・Lighting ModeはBaked Indirectにしておく。 - Lightmapping Settings
・Directional Mode は Non-Directional にしておく。 - Lightmap Parametersからライトマップの品質に関するプリセットが選べる。ライトマップの作成に時間がかかるようならDefault-VeryLowResolutionを選ぶ。
最後にウィンドウ最下部のAuto Generateのチェックを外し、隣のGenerate Lightingボタンを押すとライトマップの生成が始まる(図11)。Unity Editor右下のプログレスバーがなくなれば完了だ。
シーンの確認と調整
ライトマップが作成できたら、シーン全体を見渡してstaticなオブジェクトにライトマップが適応されているか(影などがテクスチャとして焼きこまれているのがわかるはずだ)、non-staticなオブジェクトに直接光と間接光が当たっているかを確認してみよう(図12)。
最後にLighting Settingsパネルの下部にあるFogを設定する。Fogは奥に行くほど霞んで見える霧がかかったような表現を作ることができる(図13)。Fogの色や深度などを設定し、より雰囲気を高めてみよう。
ビルドして遊んでみよう
ライティングの設定が一段落したら、今まで作ったクラスやキャラクターをシーンに設定し直してUnity Editor上で動作を確認し、端末にもビルドして遊んでみよう(図14)。
おわりに
さて、今回の解説をもって本連載は終了となる。開発環境のセットアップからUnityそのものの仕組み、C#を使ったゲームロジックの作成、グラフィクス設定の方法を紹介してきたが、実はこれでほとんどのVR開発に必要な基礎的な知識をカバーしたことになる。もちろん、この他にもさまざまな機能があるが、まずは最低限ゲームとして成り立つプログラムを作った後(ミニマルデザイン)、さらに高度な表現を実現するための機能を自分で調べていくと良いだろう。