[Unity] リアルタイム向けの形状の最適化

  • Unityで統計情報を表示 (Statistics)
  • UnityでV-Sync待ちを無効にする
  • ポリゴンメッシュの「隣接頂点の結合

Unityなどのリアルタイム表現のため、形状を最適化していきます。
リンゴの形状を使用した「テクスチャを持つマテリアルを渡す」の説明では、3つのマテリアルと5つのテクスチャを使用しています。
このマテリアルとテクスチャの削減を行います。
また、少しだけ面を削減します。

最適化の目的

最適化は、主に以下の2つが目的としてあります。

  • 多数の面やテクスチャを使用する場合のメモリ消費を抑える
  • マテリアルの切り替えを抑える

形状に対して複数のマテリアルを使用する、というのはよくある使用方法ではありますが、
マテリアルの切り替え自身がリアルタイムでは速度に影響します。
PBRのシェーダーではよく使用されるメタリックやスムーズ指定についても、
テクスチャとして与えることで、1マテリアルで複数形状の異なるメタリック/スムーズを持つ表現を行ったりもできるようになります。

統計情報を表示 (Statistics)

Unity上でのメモリの消費やメッシュの総面数、Draw Call(Unity5以降はSetPass Callと表記)と呼ばれる呼び出し回数の指標を見ることで、
どれだけ描画時に負荷がかかっているかをチェックすることができます。
リンゴ1つだとわかりにくいため、複製して敷き詰めてみました。

全部で2048個のリンゴを配置してます。
一度実行し、Gameビューの右上から「Stats」を選択します。
これで右上に統計情報が表示されます。

ここで、Batches/Saved by batching/Tris/SetPass calls/Shadow castersをチェックします。
Batches 7199/Saved by batching 8394/Tris 4.8M/SetPass calls 29/Shadow casters 10020、となっています。

「FPS」で速度チェックできますが、デフォルトではV-Sync待ちを行っており、レンダリングが速くても60-70 fpsで安定するようにウエイトが置かれています。

速度検証もできるようにV-Sync待ちをしないようにする

検証のため、V-Sync待ちを無効にします。
メインメニューの「Edit」-「Project Settings」-「Quality」を選択します。
Inspectorウィンドウで「Other」の「V Sync Count」を「Don’t Sync」と変更しました。

なお、検証後は必ず「Every V Brank」に戻すようにしてください。

これで実行してStatisticsを表示すると、待ち時間を入れない純粋な描画時間がFPSとして表示されます。

リンゴの形状を表示/非表示する(Inspectorウィンドウのチェックボックスをオン/オフ)ことで、描画時間が変化することを確認します。

このFPSも最適化の目安としましょう。
以降はShade3Dの作業になります。Shade3Dでの最適化が終わってから、再びUnityに戻ることにします。

面数を抑える

本体、枝、葉の3つのポリゴンメッシュのうち、頂点や面を削減しても影響がなさそうなところを探ります。

リンゴの本体の場合は、極となる上下部分は頂点が密集しているため面をいくつか削除しても問題なさそうです。

下記の黄色の稜線で囲まれる面をつぶすように削除します。
UVの調整も必要ですので、UV図面も表示しておきます。

形状編集モード +稜線選択モードで円周状の2つの稜線を選択します。
ツールボックスの「編集」-「メッシュ」-「選択」-「ループ選択」を選択することで、円周状にぐるっと稜線が選択されます。

UV図面でマニピュレータのV方向に縮小し、UV図面上で2つのラインが同一V値に近づくようにします。だいたいで問題ありません。

次に、形状の2つの稜線をほぼ中央に収束するように変形して、頂点を結合してまとめます。
右面図で、マニピュレータのY軸方向に縮小し、2つのラインが同一Y値に近づくようにします。だいたいで問題ありません。

上面図と透視図を表示し、下画像のように稜線を選択します。
2つの円周状の稜線より、内側部分だけを選択した状態です。

この選択された稜線を、マニピュレータを使用して上面図の+X方向に拡大し、+Z方向も同じように拡大していきます。
上面図と透視図でチェックしながら、1つ外側の稜線にほぼ一致する位置まで拡大しています。

右面図で、ほぼ同一位置にある頂点を選択します。

ツールボックスの「編集」-「メッシュ」-「結合/除去」-「隣接頂点の結合」を選択し、
ツールパラメータの距離値(デフォルト1.0mm)を確認して「結合」ボタンを押します。
これで頂点数/面数が減り、頂点数306/面数320から頂点数290/面数304となりました。

同様に、リンゴ本体の下部の曲部分でも面を削減します。

頂点数 274、面数288まで削減できました。
枝や葉も、まとめてもいけそうな頂点があれば結合してしまいます。
3Dとしての輪郭は極力保つようにして、結合できそうな頂点をまとめていくのがよいかと思います。
ツールボックスの「隣接頂点の結合」や「平均位置で結合」が頂点を結合する機能としては有効です。

テクスチャを1つにまとめる

リンゴの「本体」「枝」「葉」のテクスチャを1つにまとめることにします。
イメージパート内の3つの拡散反射用テクスチャ、2つの法線マップテクスチャが存在します。

拡散反射と法線マップの2つのテクスチャを用意することにしました。
1つのテクスチャを2×2分割した状態で、3か所にそれぞれのテクスチャを押し込んでいくことにします。
この作業は2Dペイントツールで行います。
fbx出力したときに出力されたテクスチャを、2Dペイントツールに読み込んで編集するのが楽かと思います。
1つ1つを256×256ピクセルにして、512×512ピクセルのテクスチャ上に並べました。
左が拡散反射用、右が法線マップ用です。

「apple_diffuse.png」「apple_normal.png」というファイル名としました。
注意点として、同一UVを参照するため拡散反射と法線のテクスチャの配置は同じ場所になるようにします。
左上がリンゴ本体、右上が枝、左下が葉、としています。

この2枚のテクスチャをShade3Dに読み込みます。

UVを調整

Appleのポリゴンメッシュをブラウザで選択し、表面材質のテクスチャを入れ替え。
UV図面でUVをUとV方向に0.5倍していきます。
グリッドスナップ」をオンにすると、UV図面での位置指定や移動がしやすくなります。
ツールボックスの「作成」-「移動/複製」-「移動」-「数値入力」を選択。
UV図面で左上をクリックし、「トランスフォーメーション」ウィンドウで拡大縮小を (0.5, 0.5)として「OK」ボタンを押します。

以下のようになりました。

同様に、枝のポリゴンメッシュは以下のようなUV指定となります。

葉のポリゴンメッシュは、以下のようなUV指定となります。

これで、今まで使っていたリンゴ本体、枝、葉、のテクスチャは不要となりました。
整理してブラウザ上では以下のようになります。

なお、マテリアルはUnity側で変更を加えることにします。
これでfbxエクスポートします。

Unity上のリンゴを置き換え

以降はUnityでの作業となります。
Unityのプロジェクトがあるフォルダ内のfbxファイルとテクスチャを上書きします。
また、シーンに配置した2048個のリンゴは削除します。
Projectウィンドウ内では、形状、テクスチャ、マテリアル、は以下のように配置しました。

fbxで割り当てられているマテリアル、「apple_body」「apple_branch」「apple_leaf」それぞれでテクスチャを入れ替えました。

マテリアルをまとめる

「apple_leaf」についてはカリングを行わないシェーダーを別途割り当ててるため、そのまま。
「apple_body」「apple_branch」を1つのテクスチャにまとめます。

シーンに「apple」の形状をドラッグして配置します。
「apple」は「Apple」「Branch」「Leaf」のメッシュから構成されており、それぞれにマテリアルが割り当てられています。

Appleのマテリアルを、Branchにも割り当てることにします。
HierarchyウィンドウでBranchを選択し、Inspectorウィンドウの「Mesh Renderer」の「Materials」-「Element 0」の右の小さい丸をクリックして、「Apple_body」のマテリアルに変更します。

これで、Apple/Branchの両方のメッシュに対して同じ「Apple_Body」のマテリアルが割り当てられました。
こうすることで、実行時のStatistics表示で「SetPass calls」を1つ削減することができました。

Prefab化

シーン上の「Apple」形状は、1つ前の説明でマテリアルが置き換えられました。
これを複製する前に、Projectウィンドウにドラッグします。

こうすると、オリジナルの「apple.fbx」を元にしてマテリアルを変更した形状をPrefab(プレファブ)というもので保持できます。
このPrefabをシーンに配置することで、オリジナルに差分情報を付加した形状として扱えるようになります。

最適化の確認

Prefab化したリンゴ形状をシーンに配置していきます。
始めに検証したのと同じ数の2048個分を並べました。
実行し、Statisticsで情報を表示します。

Batches 7199 → 4886
Saved by batching 8394 → 9289
Tris 4.8M → 3.8M
SetPass calls 29 → 24
Shadow casters 10020 → 8437

のように、大部分は最適化されたのを確認できました。
速度は若干上がったくらいですね。
なお、Statisticsでの情報表示は視点から見えている状態によっても変化します。
視点からのビューが全く異なる場合は、結果も大きく変わるときがあります。

今回はリンゴの形状で試してみたのですが、キャラクタなどの複雑な形状の場合は最適化の効果はもっと大きく出るかと思います。
リンゴとかを大量に並べる予定はない、という場合でも、シーンにはいつのまにかたくさんの形状が存在する、という状態になるのはよくあります。
塵も積もれば山となる、で小さい段階で最適化には踏み込んでおいたほうがよいかもしれません。

形状の最適化についてはここまでです。
次回は、「植物を作る」で作成した透過のあるテクスチャを渡す際の調整について記載予定です。

カテゴリー: Unityに形状を渡す