Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Unity+スマホで3Dゲーム開発最適化するための考え方

Cygames
January 14, 2016

 Unity+スマホで3Dゲーム開発最適化するための考え方

2015/11/15 Cygames Tech Fes

Cygames

January 14, 2016
Tweet

More Decks by Cygames

Other Decks in Programming

Transcript

  1. 自己紹介 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 金井 大

    • 技術研究チーム所属のエンジニアです • VR、ゲームエンジン、グラフィックスとかの研究 開発してます
  2. アジェンダ $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • Unity +

    スマホで3Dゲーム開発/最適化する ための考え方を、以下で紹介します – 開発の指針 – 構成およびスペックの一例 – 開発と最適化のためのTIPS – 指針と手法の答え合わせ
  3. 大事なこと $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 端末の性能を把握する •

    コンテンツの要素を把握する – 適切な単位で区切り – コストを把握し – そのコストを最適化する • 要素を選択できるようにする
  4. UNITY HARDWARE STATISTICS $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  •

    出典:http://hwstats.unity3d.com/mobile/ • unity mobile stat で検索
  5. 詳細 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • Mali 400

    MP: 20.0% • Adreno 305: 12.5% • PowerVR SGX543: 10.9% • Apple A7: 8.5% • Adreno 330: 5.9% • Adreno 306: 5.4% • Apple A8: 4.7% • PowerVR SGX544: 4.1% • Adreno 320: 2.8% • Vivante GC1000: 2.3% • Videocore IV: 2.2% • Mali 450 MP: 2.1% • Mali T760: 2.1% • PowerVR SGX540: 1.6% • PowerVR SGX531: 1.5% • Adreno 203: 1.4% • PowerVR SGX535: 1.3% • Adreno 200: 1.2% • PowerVR SGX554: 1.0% • Adreno 225: 0.9% • Adreno 405: 0.8% • Mali T628: 0.7% • Apple A8X: 0.6% • PowerVR G62xx: 0.5% • Mali T624: 0.5% • Tegra 2: 0.5% • Intel HD BayTrail: 0.4% • Adreno 220: 0.4% • Vivante GC2000: 0.4% • BlueStacks ES2.0 Emu: 0.3% • Tegra 3: 0.3% • Mali 300: 0.3% • Mali T720: 0.3% • Mali T622: 0.2% • Adreno 205: 0.2% • PowerVR G64xx: 0.2% • Adreno 420: 0.2% • Adreno 430: 0.1% • Immersion.16: 0.1% • Adreno 418: 0.1% • Vivante GC7000: 0.1% • Vivante GC800: 0.1% • Something strange: 0.1% • Adreno 304: 0.0% • PowerVR SGX530: 0.0% • Vivante GC4000: 0.0% • Android ES Emulator (GeForce): 0.0% • Tegra 4: 0.0% • Mali T604: 0.0% • Android ES Emulator (Radeon): 0.0%
  6. どうしてこうなった $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • キャリア •

    チップセット • CPU – コア数 – クロック • GPU • メモリ
  7. 例えばシェーダーを例に $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • Vertex shader

    – カラーアニメーション – UVアニメーション – アウトラインメッシュの法線方向への拡大 – セルルック • Fragment shader – イメージエフェクト – スキンシェーダー – ノーマルマップ – セルルック
  8. アプリケーションでの抽象化 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • Vertex shader

    – カラーアニメーション – UVアニメーション – アウトラインメッシュ – セルルック • Fragment shader – イメージエフェクト – スキンシェーダー – ノーマルマップ – セルルック 低スペック 高スペック 使わない
  9. 端末に落とし込む $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • Vertex shader

    – カラーアニメーション – UVアニメーション – アウトラインメッシュ – セルルック • Fragment shader – イメージエフェクト – スキンシェーダー – ノーマルマップ – セルルック 低スペック 高スペック 使わない iPhone5s iPhone6 iPhone6s Galaxy  S5 Galaxy  S6
  10. 大事なこと $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 端末の性能を把握する •

    コンテンツの要素を把握する – 適切な単位で区切り – コストを把握し – そのコストを最適化する • 要素を選択できるようにする
  11. 目標 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 60fpsをキープしたい •

    キャラクターを5体表示 • 絵力 – フェイシャル – モーションキャプチャー – 他と差別された強い絵力が欲しい! • タイトなスケジュールに負けない
  12. より現実的なゴール $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 低スペック端末では –

    幅広く動作するようクオリティぎりぎりまでスペック を落としつつ60fpsをキープ • 高スペック端末では – 高性能端末で高品質な画面を提供しつつ60fpsを キープ
  13. キャラクター $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • スペック –

    テクスチャ • ETC1(αチャンネルなし)/PVR • Mipmapなし(データサイズ縮小のため – ウェイト • 基本は2ボーン – 3ボーンをPlayerSettingで2にするとメッシュが崩れることがあ る
  14. キャラクター $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • フェイシャル –

    ボーン制御 – Animatorで眼球、リップの動きを用意し、外部から 制御 – 眼球の追従先をプログラム制御 • アウトライン – アウトラインメッシュ – 頂点カラーでの調整 – リムライト、セルルックは…? • 造形が良ければアウトラインでも
  15. キャラクター $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • クロス –

    独自実装 – それなりに重いので、まずはC#でチューン • 計算部分のみなら22行程 – マルチスレッド化できるようにデータ局所化 – あとはネイティブプラグイン化すれば…
  16. 背景 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • テクスチャ –

    基本はETC1(αチャンネルなし)/PVR – Mipmapあり – UVアニメーション用に3MB程度を確保 • 画面キャプチャ – ImageEffectで作成した中間バッファを流用 – 1フレーム遅れた絵になるが低コスト
  17. その他 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • ライティング –

    基本的にはライティングしない – アンビエント – 板を1軸回転してカメラに向けてボリュームライトっぽく • シャドウ – リアルタイムシャドウは断念 – 板ポリの安いやつ。Diffuseに焼く。 • ないと立体感なくなります • パーティクル – 一定数まとまったメッシュを用意 – パーティクルとして降らせる – Vertex shaderで動きをつける
  18. Image Effect $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • ImageEffect

    – DOF(被写界深度 – Bloom – カラーコレクトはオミット • Unityのシェーダーをベースに – 1カメラで実現できるようカスタマイズ – ついでに高速化
  19. Directシーン $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • キャラクターや背景の任意組み合わせを確認でき る専用シーン

    • デザイナー/プランナーの作業、確認が主用途 • 各種アセットのデータ形式に対応 – 通常アセット – アセットバンドル(サーバー上 – アセットバンドル(ローカルPCにつくったやつ • 端末でも動作可能 – アプリ本体を経由しないので、単体テストやコスト計測 にも使える
  20. GPU Profiler $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 描画系の追跡はUnity

    Profilerでは限界がある – オーバーヘッド – GPUのプロファイルに難アリ • チップセットと対になったGPU Profilerを使う – iOS -> instruments / OpenGL ES Frame Debugger – Adreno -> Adreno Profiler – Tegra -> PerfHUD ES • 端末や要素の性能を把握できる
  21. Adreno Profiler $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • プロファイルした情報を保存することが可能

    – チューニング前後の比較に • 頂点データ/テクスチャの保存 • シェーダーの可視化と変更 • Etc…
  22. 描画負荷軽減のポリシー $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • おおざっぱに以下のように考える –

    vertex負荷 = (描画リクエストされた頂点数) x (vertex shaderの命令数) – fragment負荷 = (描画されたピクセル数) x (fragment shaderの命令数) – 厳密にはパイプライン次第だと思う • 各ベンダー/各世代のチップ考慮するのは大変なので
  23. 描画負荷軽減のポリシー $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • vertex負荷の制御はデリケート –

    描画対象となる頂点数を減らしたい – 何らかで頂点数を削れば良いのだが… • データ削減するとシルエット崩れや作業コストが懸念 • カリング精度を上げるにはCPU/GPU負荷が懸念 • fragment負荷は比較的制御しやすい – 描画面積とシェーダーで制御できる – カメラワークには注意
  24. 描画負荷軽減のポリシー $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • vertexは最初から低めに抑さえる –

    特に低スペック端末を考えると低めにせざるを得 ない – 最低限のLODデータを用意する • fragment負荷を制御できる手段を用意する – ImageEffectをOn/Offする – 画面解像度を制御する – Meshのfragmentシェーダーを軽量版に切り替える
  25. 描画順の制御 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 前提として「描画順」と「ZTest」を理解する –

    ZTestが有効な場合、隠れたfragmentは描画されない • 1がZ値的に手前にある時、1を描いてから2を描 くと、一部は描画されない 2 1
  26. 描画順の制御 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 極端にすると。 •

    1を描画してから2を描くと、2は殆ど描画されな い 2 1
  27. 描画順の制御 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 不透明は(基本的には)手前から描く –

    隠れた個所はfragmentシェーダーが走らない – 基本的にUnity側が手前からソートしてくれてる
  28. 描画順の制御 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • なんだけど –

    原点位置を基準にソーティングする – 意図した結果になるとは限らない – こういう時は床を最後にしたいが原点基準だと。。。
  29. 描画順の制御 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • Unityで描画順を制御する手段 –

    Camera.depth – MeshRenderer.sortingLayerName – MeshRenderer.sortingOrder – Material.renderQueue
  30. 描画順の制御 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 優先としては以下になる Camera.depth

    sortingLayerName =“default” sortingOrder =0 renderQueue=2000 renderQueue=2010 renderQueue=3000 sortingOrder =100 renderQueue=2000 renderQueue=2010 renderQueue=3000 sortingLayerName =“after” sortingOrder =10 renderQueue=2000 renderQueue=2010 renderQueue=3000 sortingOrder =200 renderQueue=2000 renderQueue=2010 renderQueue=3000
  31. Camera.depth $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • CameraはCullingMask設定が必要になるなど、 色々面倒

    – ImageEffect使用時は注意! • Camera.clearFlags=Depthだとclearが劇重 • GPU20%程度の消費することも
  32. Material.renderQueue $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • マテリアル単位で描画順を制御する •

    Material.renderQueueはシェーダーからも設定可能 – Tags {"Queue"="Geometry-1" "RenderType"="Opaque"} • Queueは文字列に見えるけど実際は数値 – Background = 1000 – Geometry = 2000 – AlphaTest = 2450 – Transparent = 3000 – Overlay = 4000 • なので、前述の例は「1999」になる
  33. 髪の毛より手前にある眉 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 髪の毛に隠れてしまう眉毛を何とかして手前 に出したい

    – ZTest / ZWriteをOffにして対処 – ZTestしないので、「必ず」最前面に眉が描かれる (髪の上に描かれる) – ZWriteしないので、他のオブジェクトにZ値干渉し ない
  34. 髪の毛より手前にある眉 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 問題はいくつか残る –

    頭と眉の形状によっては、自キャラの眉が貫通して くる • カメラワークでの回避 – 無駄な描画が発生する • 我慢する
  35. DrawCall $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • まずDrawCall –

    GPUへ描画リクエストする、ということ – 固有のマテリアルを描画リクエストすると 1DrawCall消費する – Unity5からStatisticsより消失しました
  36. DrawCall $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 固有のマテリアルとは –

    UnityEngine.Materialのメンバがユニークであるこ と – 例えば • Colorが異なる • Textureが異なる • Shaderが異なる • Etc… – 他と異なるメンバがあれば、それは固有である
  37. DrawCall $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • (BOX全体にマテリアルA)x2 →

    DrawCall=2 • (BOX各面にマテリアルABC)x2 → DrawCall=6 A A B C A A B C
  38. DrawCallとバッチ処理 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • バッチ処理は2種類ある •

    StaticBatch – 移動しない同一マテリアルを持つメッシュをマーキングし、 事前にバッチ用のデータをしこむ – 統合の効果が高いが、移動したりマテリアル操作するメッ シュには適応できない • DynamicBatch – 前後のドローコールが同一マテリアルをもつ場合、ランタイ ム時に統合する – ランタイムに行うのでCPUコストがそこそこある – StaticBatchより効果が低い(頂点数等の制限数がある) • http://docs.unity3d.com/ja/current/Manual/DrawCallBatchin g.html
  39. DynamicBatch $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • DynamicBatchの注意点 –

    前後のドローコールが同一マテリアルを持たないと統 合しない – 描画順によっては統合できない! – 例えば描画順が以下だと統合されない • BOX(マテリアルA • BOX(マテリアルB • BOX(マテリアルC • BOX(マテリアルA • BOX(マテリアルB • BOX(マテリアルC • DrawCall=6になる
  40. DynamicBatch $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 描画順が以下であれば統合される –

    BOX(マテリアルA – BOX(マテリアルA – BOX(マテリアルB – BOX(マテリアルB – BOX(マテリアルC – BOX(マテリアルC – DrawCall=3になる • 描画順は前述のsortingOrderで制御可能
  41. DrawCall $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • DrawCallを減らすのであれば、描画時に固有 マテリアルが連続するよう、ルールを決めてお

    く – Batch処理を利用する – sortingOrder等で描画順を制御する – そもそも固有マテリアルを減らす • テクスチャを共有化する • シェーダーを共有化する • 変更するパラメーターを限定する • Etc…
  42. SetPass $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • SetPassとは –

    よりパフォーマンスの指針となる数値 – DrawCall時に前回使用したマテリアルから変更が あった場合、1SetPass消費する
  43. SetPassとDrawCall $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 【Unity】Unity Performance

    Casual Talk 「ド ローコール伝説の終わり」 レポート – http://qiita.com/baba_s/items/5260807ced7fc3c02ca 6
  44. SetPassとDrawCall $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • (BOX各面にマテリアルABC)x2 →

    SetPassは描 画順に依存する • SetPassを減らすにはDrawCallと同じく描画順を 意識する • DrawCallと同じノウハウが利用できる A B C A B C
  45. Depth Texture $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • ImageEffectの被写界深度はZ値を参照してボカ

    シ処理を行う • Z値を参照するには、DepthTextureが必要 – Camera.depthTextureMode = DepthTextureMode.Depth; • 注意点 – DepthTextureはRenderTargetへ描画を行うことで 生成されてる – DepthTextureへポリゴンを描いている、ということ – 単純に描画頂点数が二倍になる
  46. Depth Texture $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • DepthTextureへの描画時に利用されるシェー

    ダーは? – シェーダー中のTagsを参照してます • http://docs.unity3d.com/ja/current/Manual/SL- ShaderReplacement.html – UnityにLightModeというタグが用意されており、以 下タグを持つSubShaderに置き換わる • Tags{ "LightMode" = "ShadowCaster" } – Unity4 -> 5で変更された箇所なので注意
  47. Depth Texture $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • ShadowCasterシェーダーを実装する理由

    – アウトライン+DOF時に必要となる事がある – キャラクターはアウトライン分微妙にサイズが大き くなる • ので、DepthBufferに書き込む大きさを調整する – やらないとアウトラインがボケてしまう
  48. Multi threaded Rendering $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  •

    CPUがGPUを待つケースが減り、FPSの上昇が 期待できる • (空いてるCPUコア数が少ないと意味はない)
  49. Multi threaded Rendering $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  •

    なのですが。。。 – UnityのMultiThreaded Renderingに関する資料は 少ない – マルチスレッド関係は不具合出やすい個所なので 注意しましょう。 • Multithreaded + DynamicBatchでハングする事例あり • Unity5.0.2p3で発生
  50. 大事なこと $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 端末の性能を把握する •

    コンテンツの要素を把握する – 適切な単位で区切り – コストを把握し – そのコストを最適化する • 要素を選択できるようにする
  51. 端末の性能を把握する $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 実際に計測すること •

    Profiler – Unity Profiler – Frame Debugger – GPU Profiler • 各種サイト – 3DMARK – Unity Hardware Statistics
  52. 要素を適切な単位で区切る $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • ゲーム的かつ技術的な視点で区切る –

    キャラクタ/背景/エフェクト – 頂点数/テクスチャ/ボーン数 – シェーダー – ImageEffect – CPU/GPU
  53. コストを把握 $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 実際に計測すること •

    Profiler – Unity Profiler – Drame Debugger – GPU Profiler • CPU/GPUどちらがネックなのか • GPUネックならこれが参考になります • Computer Graphics Gems JP 2015 • http://www.borndigital.co.jp/book/5498.html# • 2.5.4 パイプラインのボトルネック解析
  54. コストを最適化する $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • 定期的に監視すること –

    できるだけ早いタイミングから – 想定された端末でのチェック – 機能が入ると知らない間にコスト上がる • 配分を決めること • FPS/SetPassといった性能指針を
  55. 要素を選択する $POGJEFOUJBM $PQZSJHIU ˜$ZHBNFT *OD "MM3JHIUT3FTFSWFE  • What if

    – ◦◦したらどうなるだろう • キャラクタを増やすor減らす • ImageEffectをOn/Offする • シェーダーを切り替える • 選択を容易にする機能を実装する • ゲームと独立した場所があるとベスト