夏までにiPhone アプリつくってみっか!

趣味でiPhone/Androidアプリを開発し、日々勉強した事を書いています。オープンワールド系レースゲームをUnityで開発中です。

【Unity, Blender】LOD機能を使って自動的に表示ポリゴン数を節約

今回はUnityのLOD (Level of Detail)機能を使い、ポリゴンが細かいモデル、中間のモデル、荒いモデルを自動的に切り替えて不要なポリゴン数を抑える実験をしてみました。

LOD機能を使用するには、まずBlenderでポリゴン数の異なる複数のモデルを準備する必要があります。
Blenderには自動的にポリゴンを間引いてくれるDecimate Modifierというモディファイアーが用意されていますが、CR-Xの場合それほど上手には間引いてくれなかったので手動でポリゴンを削っていきます。
基本的にはDissolve Edgesでエッジを消して両隣のフェースを繋げていく作業を繰り返し、できるだけ元の形状を崩さぬように作業します。ポリゴンを消すことでUVが乱れるので形が崩れた部分は適宜Unwrapして配置し直します。

元の細かいモデルのTrisの数は7198です。
f:id:takujidev:20151027222925j:plain

中間のモデルでは3454まで減らしました。まだ違いはあまりありません。
f:id:takujidev:20151027223008j:plain

荒いモデルは1614です。元の1/4以下になっています。ここまで減らすと違いはわかりますが、遠く離れた時に表示されるモデルなので問題ありません。
f:id:takujidev:20151027223103j:plain

Blender上での複数のモデルの扱いですが、1つのファイル内の、異なるレイヤーに配置する方法をお勧めします。
そうしておくととUnityにインポートする時に自動でLODの処理をしてくれるので少し楽です。
レイヤーを分ける時はライトをそのレイヤーにも配置しないとマテリアル表示で真っ黒な車が出てきてしまうので要注意です。
私はこれでしばらく悩みました。
ライトを選択し、Mを押すと出てくるレイヤー選択画面でShiftを押しながら新たなレイヤーをクリックすると元のレイヤーと新しいレイヤー両方に同じライトが配置されます。Shiftを押さないとレイヤー間で移動してしまいます。

Emptyオブジェクトの子オブジェクトとして各LODのオブジェクトを入れたい場合は、BlenderでShift-Aで適当なEmptyオブジェクトを作り、Outliner上で子オブジェクトをEmptyオブジェクトにドラッグしParentingします。
BlenderのOutlinerの構造はUnityのHierarchyに同じ構造ででインポートされるので便利です。

例えば、車のモデルでタイヤを回すためにタイヤオブジェクトを参照する場合は各LODレベルの子オブジェクトを入れた親Emptyオブジェクトを参照すればOKです。
そうせずに、どれか1つのLODレベルのオブジェクトを参照すると、そのレベルの時だけタイヤが回転し、他のレベルでは止まってしまいます。

Blenderでこのようにオブジェクトを整理してみました。
f:id:takujidev:20151027224422j:plain

Unityにインポートために一番重要なのは、各オブジェクトの名前の後ろに_LOD0, _LOD1, _LOD2の識別子をつけておくことです。一番細かいモデルが_LOD0で荒くなるごとに_LOD1, LOD2と数字の部分を上げて行きます。
こうしておくとUnityがインポートする時に自動的にLODの設定をしてくれます。

このようにして作ったファイル(CR-X_LOD.blend)をUnityのプロジェクト内のフォルダーにコピーするとインポートされます。
インポートされたモデルをインスタンス化すると、Blenderでの構造と全く同じようにインポートされました。
f:id:takujidev:20151027224615p:plain

インスペクターで見るとCR-X_LODオブジェクトにはLOD Groupというコンポーネントが付いています。
LOD0, LOD1, LOD2と書かれたグラフをクリックすると、それぞれにアサインされているメッシュが表示されます。Blenderで_LOD(n)をつけ忘れるとここに出てこないので注意です。
f:id:takujidev:20151027225106p:plain

グラフの境界の部分を左右にドラッグすると画面上に表示されるオブジェクトの高さ(実際にはオブジェクトの周りに表示される四角の高さ)が画面の高さに対してどのくらいの比率(黄色矢印に対する赤矢印のパーセンテージ)になったら隣のレベルに切り替えるのかを調整できます。また、Culledの位置でモデルがどのくらいの大きさになったら表示をやめるか調整できます。
f:id:takujidev:20151027234030j:plain

カメラアイコンを左右にドラッグするとカメラがオブジェクトに近づいたり離れたりが離れたりしてLODレベルの切り替わりの様子がわかります。

グラフのカメラアイコンのグラフ上の位置と表示されるLODレベルが一致していない場合は、Quality Setting のLod Biasが1になっていないと思います。
これを1にするとちょうどグラフの境界で切り替わるようになります。
Lod Biasはプログラムを走らせる環境によりLODの切り替わり具合を調整するのに使います。個々のモデルのLOD Groupの設定を全て調整するのは大変ですが、Lod Bias設定を使用すれば一括で調整できます。
モバイルデバイスなど用のビルドではLod Biasを低めに設定することでLOD Groupでの設定値より早めに荒いモデルに切り替えポリゴン数を節約したりできます。

以上でLODの設定は完了です。
Blender側でファイルを分けてしまったなどの理由でインポートでうまくいかなかった場合はエンプティオブジェクトを作り、それにLOD Groupコンポーネントをアタッチして、グラフの各部分をクリックすると出るAddのところに対応するモデルをドラッグしていくことで手動でLODの設定ができます。手動で設定した時はカメラアイコンの動きと画面の動きが全く合わない場合がありますが、Recalculate:のBoundsボタンをクリックすると正しく追従するようになります。

実験結果です。
LODを使用しない場合は64.5kポリゴンのシーンです。
f:id:takujidev:20151027235619j:plain

LODを使用すると、同じシーンですが小さく表示される敵車の画面表示には荒いモデルが使用され、ポリゴン数が42.3kに抑えられました!
f:id:takujidev:20151027235752j:plain

ポリゴン数はかなり減りましたが、見た目には違いはほとんどありません。

https://itunes.apple.com/jp/app/toraberushutingu-retorona/id917570972?mt=8&uo=4&at=10laCt
https://itunes.apple.com/jp/app/beecluster-wu-liaono-zongsukurorushutingugemu/id663801586?mt=8&uo=4&at=10laCt

【Blender, Unity】ノーマルマッピングでちょっとした凹凸をつける

私がノーマルマッピングを初めて体験したのはXBOX360バイオショックというゲームでした。
壁のタイルがデコボコして縁がテカテカしているように見えるのを「これがノーマルマッピングかー」と感動しながら視点をグリグリ動かして遊んでいました。

さて、そんな感動的なノーマルマッピングを自分がモデリングした物体に施せる日が来るとはその時は思いもしませんでした。

これまでモデリングしてきたCR-Xですが、正直ノーマルマッピングを試せるような場所はほとんどありません。
と、いうことで今まで忘れていたナンバープレートを急遽取り付けてみました。

ついでに今までテクスチャで汚く反射を書き込んで誤魔化していたヘッドライトの具もモデリングし、完成したモデルがこちら。

f:id:takujidev:20151020220430j:plain

f:id:takujidev:20151020220443j:plain

肝心のナンバープレートは残念ながら解像度が足りなかったせいか少しいびつにデコボコしているように見えます。

今回は白黒で高さを表すハイトマップを手書きで作成し、それをUnityに取り込む時点でノーマルマップ化しています。

こちらがハイトマップ。
f:id:takujidev:20151020221058p:plain

白いほど高い所、黒いほど低い所です。ここではナンバープレートとホイールナットだけ白くしています。

UnityのProjectパネルからハイトマップのファイルを選択し、Texture Type をNormal mapにし、Create from Grayscaleにチェックを入れればUnityが内部的に青紫色のノーマルマップとして扱ってくれます。

f:id:takujidev:20151020221328p:plain

あとはこれをStandard シェーダーのNormal Mapスロットにドラッグするとデコボコするはずです。
デコボコ具合は先ほどのテクスチャ取り込み設定画面のBumpinessかNormal Mapスロットのパラメーターで設定できますので、いい感じに設定してあげます。私はNormal Mapのパラメーターは1のままBumpinessを0.01にするといい具合になりました。 なお、Bumpinessの値を変更したあとはApplyボタンを押さないと反映されないので注意です。

拡大するとこんな感じです。

ノーマルマッピングなしの場合
f:id:takujidev:20151020223335j:plain

ノーマルマッピングありの場合
f:id:takujidev:20151020223351j:plain

あんまり綺麗じゃありませんでしたね。

Blenderの場合は新たにテクスチャスロットを作ってそこにグレースケールのハイトマップを開き、Influence設定のGeometry:Normalにチェックを入れ、こちらもパラメーターを変化させて丁度良い具合にします。
f:id:takujidev:20151020224135j:plain
Blenderレンダリングした場合はUnityよりは少し綺麗に見えます。
ただ、地面に反射したナンバープレートはおかしく表示されてしまいました。

さて、ライトのモデリングですが、こうなっています。

f:id:takujidev:20151020224716p:plain

前回の百式のくだりで書いた通り、UnityではスペキュラーマップのRGBチャネルの値によってMetallicパラメーターを設定できます。

tf.hateblo.jp


ライトの反射鏡のようなパーツは不透明の白(RGBアルファ全部最大値)にすれば綺麗な鏡面になります。
あとはライトのガラスを表現すれば完成ですが、透き通った材質を表現するにはマテリアルを分け、そのマテリアルのシェーダーのパラメーターを変える必要があります。
使うシェーダーは同じStandardシェーダーですが、Rendering ModeをTransparentにします。
あとはテクスチャーを設定してやればOKです。マテリアルが違っても同じテクスチャを共用することは可能です。

最後に、Smoothnessの値を調整して太陽の光が当たった時にいい感じに反射するようにしてみました。

f:id:takujidev:20151020230623j:plain

今回でCR-Xモデリングは完成となります。この1台作るのに1ヶ月以上かかったと思います。
もっとペースアップが必要ですね。

最終的にVerts 3749, Faces 3679, Tris 7198となりました。

https://itunes.apple.com/jp/app/toraberushutingu-retorona/id917570972?mt=8&uo=4&at=10laCt
https://itunes.apple.com/jp/app/beecluster-wu-liaono-zongsukurorushutingugemu/id663801586?mt=8&uo=4&at=10laCt