【Unity道場スペシャル 2017京都】最適化をする前に覚えておきたい技術

3.2K Views

November 18, 17

スライド概要

2017/11/18に開催されたUnity道場スペシャル 2017京都の講演スライドです。
講師:黒河 優介(ユニティ・テクノロジーズ・ジャパン合同会社)

「効果的な最適化のために事前に何をしたらよいか?」「どういう考えで最適化を行っていけばよいか?」などの基本的な考え方から、具体的なProfilerの使い方までお伝えしていきたいと思います。この講演で紹介する考え方は、日本のエンタープライズチームを通して得た知見になります。最適化のテクニックそのものは紹介しませんが、考え方を身につける事で、最適化のために役立つでしょう。

こんな人におすすめ
・最適化したいが、何をしてよいかわからず困っている人
・効率的に最適化を行いたい人

受講者が得られる知見
・Unity Profilerに関するノウハウ
・最適化の目算、見積もりをする技術

Unityのイベント資料はこちらから:
https://www.slideshare.net/UnityTechnologiesJapan/clipboards

profile-image

リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。

シェア

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

最適化をする前に覚えておきたい技術 - Unity道場 京都スペシャル2 Edition ユニティ・テクノロジーズ・ジャパン合同会社 エンタープライズサポート 黒河 優介

2.

自己紹介 • 役職 • ユニティ・テクノロジーズ・ジャパン合同会 エンタープライズコンサルティングデベロッパー リレーションマネージャー/エンジニア • 仕事内容 • 大規模プロジェクトのサポート業務 • プロジェクトに合う形で、パフォーマンスに関す る提案等を行っている

3.

この講演について 本講演はUnite2017の「最適化をする前に覚えておきたい技術」を ベースに作成しております。

4.

本日の講演内容 • 「最適化」とは何なのか? • 「プロファイリング」について • 実際のケーススタディ • ステップアップのためのTIPS

5.

本日の講演 • 講演資料のキーとなる箇所には ユニティちゃんが出現 大事なポイント やってはダメなパターン 覚えておくと役立つ知識

6.

最適化とは何か? • スクリプト、プロジェクトの設定、シーンの構成を見直して、ゲームの クオリティを維持したまま、パフォーマンスの向上・メモリの削減を行 う事

7.

なぜ最適化を行うのか? • ターゲットにしている端末で、想定している処理速度が出ない • これによりユーザー体験が落ちてしまう • ユーザー体験が落ちたことによる低評価を避けたい ターゲットにしている端末で十分快適に遊べているなら、無理して最適化 を行う必要はない

8.

最適化とは? より良いゲーム体験のため、 プロジェクトを見直して、適切な形に 組みなおす事

9.

最適化を行いたいシチュエーション • メモリ使用量が多くて、ゲームが不正終了してしまう • ロード時間が長くて、ゲームのテンポが悪くなってしまう • ゲームプレイ中に急に画面が一瞬固まり、プレイミスが起きてしまう。 • 低いフレームレートでゲーム体験が劣化してしまう

10.

最適化の前に覚えておきたい法則 • 「パレートの法則」 • 通称:80:20の法則。全体の数字の大部分は、全体を構成するごく一部 によるものである • 処理負荷となっている部分は、プロジェクトのごく一部分によって起 きている

11.

最適化の前に覚えておきたい法則 処理の一部分を直せば、 大体の問題は解決する

12.

最適化の前に覚えておきたい法則 直すべき処理を見極めるのが 最優先事項!!

13.

最適化の前に覚えておきたい法則 いきなり修正作業を始めては ダメ 体重も測らず、ダイエットを始めてしまうのが ダメなのと一緒

14.

いきなり最適化作業をしてはダメな理由 • 何を直すべきかもわからないまま当てずっぽうに作業をしても、時間を 浪費してしまう • どの程度の負荷があったのか把握しておかないと、作業によってどの程 度効果があったのか測れず、修正がうまくいったのかわからなくなる

15.

プロファイリング超重要 最適化の前に プロファイリングをしてく ださい!絶対に!絶対にしてください! これは超重要案件です!!! 最適化への道はプロファイリングすることから始まる

16.

最適化のための手順 1.ゲーム内の処理負荷となっている箇所を特定するためプロ ファイリングする 2.負荷となっている処理の内容が特定出来たら、直すための算 段を立てる 3.実際に作業して直す

17.

最適化のための手順 1.ゲーム内の処理負荷となっている箇所を特定するためプロ ファイリングする 2.負荷となっている処理の内容が特定出来たら、直すための算 段を立てる 3.実際に作業して直す この講演は、ココの話がメイン

18.

プロファイリングについて • 処理毎に掛った時間、メモリの使用状況を確認する作業 • Unity標準機能で Profiler が用意されているので、こちらを使って 計測可能 • より詳細な事は各プラットフォームが提供しているネイティブの Profilerがあるが、大まかな問題把握では UnityのProfilerで十分

19.

プロファイリングについて まずは、UnityのProfilerを 使おう!!

20.

Unity Profilerについて • Editor上でプレイした時に、CPU / GPU / Rendering / Memory / Audio / Physics / uNet / Video Player / UI / GIなどの状況を確認できる • Editor上でのプレイだけでなく、Android/iPhone上での実行のパフォーマ ンスも見られる ※Video Playerは Unity 5.6から利用可能 UIは Unity 2017.1から利用可能 GI(Global Illumination)は Unity 2017.2から利用可能

21.

Profiler使い方 デモ

22.

Unity Profilerの使い方 Menuから Window -> Profiler を選択すると、このウィン ドウが出てくる

23.

Editor実行中に処理負荷を見られる Editor上で Playボタンを押せば、 負荷がグラフで見られる

24.

色々な種類の情報を確認できる CPU/Rendering/ Memory に関する情報が カテゴリ別にグラフ表示

25.

もし見たい項目がなかった時は… 項目が表示されていない場合は、 ココで追加

26.

選択した項目の詳細情報の確認 現在選択中の項目の 詳細情報がコチラに 表示される

27.

Unity Profilerを実機と繋げる 「Active Profiler」をクリックす ることで、プロファイルする 対象が切り替えられる AndroidやiOSの実機上での実行 もプロファイル出来る ※1.Developビルドしたアプリのみ接続可能 ※2.同じネットワーク環境かに接続、もしくは 有線でPCとつなぐ必要がある

28.

実機とPCを同じWifiに繋いで アプリを起動するだけ

29.

ただ大体の問題はEditor上で 見つけられる。 Editor上での実行の方が早く て楽なので、オススメ

30.

Profiler の使い方について 学んだので早速実践編 ~ケーススタディ~

31.

ケーススタディ • 最適化を行いたいシチュエーションによって、見るべき場所も変わって くる • メモリ使用量が多くて、ゲームが不正終了してしまう • ロード時間が長い • ゲームプレイ中にカクツキが頻発してしまいストレスフル • 低いフレームレートでゲーム体験が劣化してしまう

32.

~ケーススタディ~ メモリ使用量が多い場合

33.

メモリ使用量が多い時に考える事 • 単純にメモリ使用量が多いのか?それともリークしているのか? • C#メモリが多いのか? Unityメモリが多いのか? ※リークとは未使用のものがメモリに残り続けてしまい、 必要以上にメモリを消費してしまう現象

34.

メモリがリークしているかチェックする メモリの詳細項目に読み込んでいる Texture・Mesh等の数がある。 繰り返しプレイしていて、右肩上が りに数字が増えていたらリークして いる可能性大

35.

メモリリークしているか 雰囲気でわかる方法 メモリを沢山積んでいる端末でも、 沢山遊んでメモリがたりず落ちるな らメモリリークの可能性大!!

36.

C#メモリが大きいのか、 Unityメモリが大きいのか • Unityが使用するメモリは大きく分けて二つある • C#メモリ(Mono Memory) • Unityメモリ →どちらが大きいかによって取るアクションは大きく変わってくる

37.

C#メモリが大きいのか、 Unityメモリが大きいのか Memoryの詳細に、C#メモリ・Unityメモリの使用状況がある

38.

C#メモリとUnityメモリについて • C# メモリ • C# スクリプト側で使用しているメモリで、Garbage Collectionされる • 一度メモリをReserve(予約)してから使う。C#用に予約済みとなったメ モリはアプリ終了まで二度と返されない • Unityメモリ • Texture, Mesh, Animation などのアセットのデータで主に占められるメ モリ

39.

メモリのイメージ図 C#使用メモリ 未使用 C#用に予約したメモリ Unityメモリ アプリで使用している全体メモリ

40.

C#のメモリでの着目点 • Used(現在使用中)よりも、Reserved(予約)の方に着目 • Editor上での実行の場合はEditorが使ったメモリも換算されてしまうの で、実機でのチェックが望ましい • Reserved(予約) が大きすぎる場合、どこかで一時的にC#メモリが膨らん でいる可能性がある • ファイル読み込みや、通信のために一時的に大量のC#メモリを使用し ていないか?

41.

Unityメモリでの着目点 • メモリ上にある各Asset毎のメモリ内の容量をチェック • Memory Profilerを、Detailed (詳細) ビューに切り替えて確認 • 別途 Unity Technologies製のEditor拡張ツールもあり • 出来ることは殆ど同じだが、ちょっとグラフィカルで見やすい

42.

Memory Profiler使い方 デモ

43.

Memory Profiler の使い方 ここを押して、Simpleビューと Detailビューの切り替えをする

44.

Memory Profiler の使い方 Take Sampleボタンを押すと、メモ リの詳細を調べられる

45.

Memory Profiler の使い方 どのアセットがメモリに読み込まれ ていて、どれだけメモリを使用して いるかが一覧でわかる

46.

UnityのMemory Profiler https://bitbucket.org/Unity-Technologies/memoryprofiler にて配布 これをプロジェクトに組み込む必要がある

47.

メモリが多かった時の対策 • C#メモリ • C#スクリプトの見直しを行う • 特にファイル読み込みや通信時等にメモリを多く消費していないか? • Unityメモリ • 余計なアセットが読み込まれないようにする • 必要であれば、読み込みのタイミングをずらす等も視野に • 必要以上に大きいアセットは圧縮等を行うようにする

48.

メモリが足りなくて落ちるときの図 YES メモリリーク? メモリリークの原因を 探して対処 NO 大きいのは C#メモリ? Unityメモリ? Unityメモリ どのアセットが多く使っている か特定して対処する C#メモリ C#のソースを見直す。(特にファ イル読み込みや通信周り)

49.

~ケーススタディ~ ロードが長い場合

50.

ロード時間が長い時に考える事 • 本当にロード時間が長いのか?それとも初期化処理が重いのか? • 読み込むデータは適切か?余計なデータを読んでいないか?

51.

ロードが重かった時のデモ

52.

ロードが重かった時のデモ グラフが一気に跳ね上がったところが、 ロードをしたタイミングなので、ここ をクリックして、その時の詳細を追っ ていくことで負荷を見ていく

53.

ロードが重かった時のデモ [スクリプト名].Awakeという形で C#スクリプトと対応している。

54.

ロードが重かった時のデモ Awakeの中のLogStringToConsole が ロード時間の4分の1近く…

55.

プロファイリングする時の注意 負荷になっていたのが Debug.Log書き出しだった…

56.

プロファイリングする時の注意 プロファイリングをするとき は Debug.LogをOFFに! Debug.logger.logEnabled = false; でログ書き出し処理を無効に出来る。 ※理想は全部のDebug.Log呼び出しを#ifdefなどで 事前に括って置いて呼び出しそのものをしない事

57.

改めて… ロードが重かった時のデモ

58.

ロードが重かった時のデモ(改) Texture.AwakeFromLoadで0.35秒。Texture 読み込みに多くの時間がかかってい るのがわかる

59.

ロードが重かった時のデモ(改) CPUの詳細情報をTimelineへ変更する事で、 メインスレッド以外の様子がわかるよ うになる

60.

ロードが重かった時のデモ(改) 別スレッドで行っているファイル 読み込み処理も確認できる

61.

ロードが重かった時のデモ(改) • Memory ProfilerのDetailedビューを使って余計なデータを読み込んでいな いか、読み込んだデータのサイズをチェック 読み込まれるはずのない データも読み込まれてし まっていないか? データサイズが大きすぎ ないか?

62.

AssetBundleを使っている時の注意 AssetBundleを使っている場合、予期せず重複 したデータを含んでしまっている事がよく あるので注意

63.

ロードが長い時の処理 DebugログをOFFに 長いのは 初期化処理? ロード処理? 初期化処理 ロード処理 ロード済みデータを確認 余計なデータがあれば読み込まないように 大きすぎるデータは圧縮等検討 C#スクリプトを見直す

64.

~ケーススタディ~ 一瞬、画面が固まった場合

65.

一瞬だけ画面が固まる場合 • 裏でロード処理を行っている等の心当たりがない場合は、ほとんどの場 合 GC(Garbage Collection)が走っている • GCとは、C#メモリが足りなくなった時に整理して未使用のメモリを再 び使えるようにする処理 • GCは膨大な処理時間を取られる • まずはGCが起きていないかProfilerでチェック

66.

GCが起きていないか 確認デモ

67.

GCが起きていないか確認デモ 項目をクリックするとグラフに表示をする/しな いが選択できる GarbageCollectorのみをONにする事で発見しやすく なる

68.

GCが頻繁に起きていた時の対策 • まずは、どのC#スクリプトで多く消費しているか特定する • C#のメモリ使用を可能な限り抑えるように書き換える • 文字列操作はメモリを都度使用するので、扱いには注意! • StringBuilderクラスを使うようにしましょう • 特に毎フレームUpdate処理でのメモリ確保は控える

69.

GCの発生箇所特定デモ

70.

GC発生個所の特定デモ CPUの詳細の「GC Alloc」にて、どれだけ C#メモリが確保されたか確認できる

71.

GC発生個所の特定デモ Deep ProfileをONにすることで、更に詳細 の呼び出し先の情報が確認できるように なる。 ※その分動作は重くなる

72.

画面が頻繁に固まっている時 GCが発生していないか確認。 頻発していたらC#メモリの 消費を極力抑える

73.

C#メモリの消費について string関連の処理は何かと C#メモリを使うので注意!

74.

string処理の扱いについて string関連の処理で 1.0MBも C#メモリを確保してしまっている

75.

string処理の扱いについて string name = “player”; dialogTitle.text = “名前は” + name + “ですか?” + “¥n”; このプログラムを元にC#メモリがどう確保されるかを図解します

76.

string処理の扱いについて string name = “player”; dialogTitle.text = “名前は” + name + “ですか?” + “¥n”; 一時的に生成されるstring 名前はplayer “名前は”とnameを結合し、 一時的に結果を保存するた め、stringを生成

77.

string処理の扱いについて string name = “player”; dialogTitle.text = “名前は” + name + “ですか?” + “¥n”; 一時的に生成されるstring 名前はplayer 名前はplayerですか? 一時的に生成したstring ”名前はplayer”と”ですか?” を結合した結果を別途生成

78.

string処理の扱いについて string name = “player”; dialogTitle.text = “名前は” + name + “ですか?” + “¥n”; 一時的に生成されるstring 名前はplayer 名前はplayerですか? 最後に改行文字を足した文字列を dialogTitle.textに追加して処理が完 了

79.

string処理の扱いについて string name = “player”; dialogTitle.text = “名前は” + name + “ですか?” + “¥n”; 一時的に生成されるstring 名前はplayer 名前はplayerですか? 一時的に生成されたが ゴミとしてメモリ内に溜まる (GCのタイミングで完全に処理され る)

80.

stringの足し算の過程で C#メモリが無駄に使われてし まった

81.

正しい string処理 StringBuilder sb = new StringBuilder(32); string name = “player”; dialogTitle.text = sb.Append(“名前は” ) .Append( name ) .Append( “ですか?” ) .Append( “¥n” ).ToString(); 上記のように StringBuilderを利用することで、一時 的なstringの生成を防げる

82.

正しい string処理 StringBuilder sb = new StringBuilder(32); string name = “player”; dialogTitle.text = sb.Append(“名前は” ) .Append( name ) .Append( “ですか?” ) .Append( “¥n” ).ToString(); string用のBuffer( 32文字分確保) string用に 32文字分の バッファーを確保

83.

正しい string処理 StringBuilder sb = new StringBuilder(32); string name = “player”; dialogTitle.text = sb.Append(“名前は” ) .Append( name ) .Append( “ですか?” ) .Append( “¥n” ).ToString(); string用のBuffer( 32文字分確保) 名前は バッファーに ”名前は”を追加

84.

正しい string処理 StringBuilder sb = new StringBuilder(32); string name = “player”; dialogTitle.text = sb.Append(“名前は” ) .Append( name ) .Append( “ですか?” ) .Append( “¥n” ).ToString(); string用のBuffer( 32文字分確保) 名前はplayer バッファーに nameの値を追加

85.

正しい string処理 StringBuilder sb = new StringBuilder(32); string name = “player”; dialogTitle.text = sb.Append(“名前は” ) .Append( name ) .Append( “ですか?” ) .Append( “¥n” ).ToString(); string用のBuffer( 32文字分確保) 名前はplayerですか? バッファーに ”ですか?”を追加

86.

正しい string処理 StringBuilder sb = new StringBuilder(32); string name = “player”; dialogTitle.text = sb.Append(“名前は” ) .Append( name ) .Append( “ですか?” ) .Append( “¥n” ).ToString(); string用のBuffer( 32文字分確保) 名前はplayerですか?¥n バッファーに ”¥n”を追加

87.

正しい string処理 StringBuilder sb = new StringBuilder(32); string name = “player”; dialogTitle.text = sb.Append(“名前は” ) .Append( name ) .Append( “ですか?” ) .Append( “¥n” ).ToString(); string用のBuffer( 32文字分確保) 名前はplayerですか?¥n バッファーの中身を stringにして dialogTitle.textに入れ る

88.

正しい書き方はわかったが、 修正がありすぎてツライ!! あと気楽に書けなくてつらい…

89.

そんな貴方のために 楽な良いやり方あります!! これを導入すれば… https://github.com/wotakuro/StringBuilderTemporary ※MITライセンスなので、ご自由にお使いください

90.

楽な直し方 まず、下記のgithubのソフトを導入 https://github.com/wotakuro/StringBuilderTemporary 導入後… string name = “player”; dialogTitle.text = StrOpe.i + “名前は” + name + “ですか?” + “¥n”; 文字列の足し算の前に “StrOpe.i +”を 追加するだけの簡単なお仕事!

91.

少しだけ解説 • C#の暗黙的型のcastとoperatorのoverrideを少し応用したテクニック • StrOpe.i + “文字列” をしたときに、別の型を返すようにしていて、その 型とstringでの演算を別途定義することで無理くり動かすテクニック • 内部的には StringBuilderのAppendが呼ばれるようになっている

92.

画面が頻繁に固まる時の処理 YES GC発生している? プロファイラで、C#メモリを大きく 確保している場所を特定し、C# スクリプトを見直す NO 他にロード等をしていないか? この後の低いフレームレート編のやり方で 探す

93.

~ケーススタディ~ 低いフレームレートの場合

94.

低いフレームレートとは? • 60FPS(秒間60フレーム)にしたいなら、1フレーム辺りの処理を 16.6ミリ秒に抑える必要がある • 30FPS(秒間30フレーム)にしたいなら、1フレーム辺りの処理を 33.3ミリ秒に抑える必要がある -> これを超えてしまうとフレームレートが低くなる

95.

低いフレームレート時に考える事 • ゲームロジック側による負荷なのか?それとも描画負荷なのか? • 直すべきはゲームのロジックそのものなのか、描画処理に関する事な のか? • 描画処理の方が修正した事によるバグ発生は少ない

96.

ゲームロジックの負荷?描画負荷? 「Rendering」が描 画の負荷具合、そ れ以外がゲームロ ジック。 CPUのグラフで、Renderingとその他(Vsync除く)の どちらが重いかでジャッジ

97.

ゲームロジックか描画負荷か 見極めるときの注意 PCとモバイル端末では描画性 能/解像度が大きく違うので、 このチェックは実機で!

98.

ゲームロジックか描画負荷か 見極めるときのテクニック 試しに解像度をギリギリまで下げた 状態で、実機で動かしてみる。 フレームレートが大幅に向上するよ うなら、描画負荷! Screen.SetResolutionでの解像度変更や CameraのRectを弄って描画範囲を小さくする

99.

ゲームロジックの負荷の場合 • 負荷となっているのは、C#スクリプトの処理か?それともUnity側での処 理か? • Unity側の処理の場合、物理処理、UI処理あたりがよくある負荷原因 • GameObject数が多すぎて、全体的に重くなってしまう事も時々ある • モバイルでは、3000程度には抑えておきたい

100.

Physicsが重いデモ

101.

Physicsが重いデモ オレンジ色が処理の大部分を占めていることから、 Physicsが重いということがわかる

102.

Physicsが重いデモ Physicsが重い場合、Edit → Project Settings → Time のFixedTimestep設定を 見直す。 Physicsは、通常のゲームループとは違う周期(フレームレート)で動い ている。デフォルトでは 50FPS( 0.02 )となっているので、30FPSで動 いているゲームの場合、Physicsも30FPSになるように「0.03333」を指 定すると良い

103.

Physicsが重いデモ それでもPhysicsが重い場合… Edit → Project Settings → Physicsにて、 衝突判定を行うLayerの設定を見直す

104.

UIが重いデモ ※2017.1からの新機能

105.

UIが重いデモ(2017.1以降) 紫色が多くを占めることから、UIが負荷となってい ることが確認できる

106.

UIが重いデモ(2017.1以降) 2017.1以降では、 UI処理負荷を詳しく見る ための機能が追加

107.

UI処理の負荷(2017.1以降) Layoutは、頂点計算処理を表している

108.

UIが重いデモ(2017.1以降) UI描画の詳細が確認できる ※Editor上での実行時のみ有効

109.

ざっくりと原因と対策 • C#スクリプト • 原因&対策:ゲームによって色々 • 物理処理 • 原因:余計な衝突判定を行っている • 対策: Layer Collision Matrix を見直す • 原因:複雑な衝突判定を行っている • 対策:MeshColliderは重いので、BoxCollider等で置き換える • 原因:1フレームに複数回Physics処理が回っている • 対策:TimeのFixedTimeStep設定を見直す

110.

ざっくりと原因と対策 • UI処理 • 原因:重い頂点計算が走っている • 対策:uGUIはAnimationしているものは別Canvasに分けないと重い

111.

描画の負荷で考える事 • 余計な描画が入っていないか? • Batch数、Set Pass数が多くないか? • 頂点数が多すぎないか? • 描画面積が広くないか?(Overdrawをしすぎていないか?) • Shaderが重くないか?

112.

余計な描画とは? 町の背景を描画 山の背景を描画 最終的な画面 例えば、このような形で画面の描画が行われているとする

113.

余計な描画とは? 町の背景を描画 山の背景を描画 最終的な画面 この描画処理は、画面に反映されないので無駄!!

114.

シーン上にCameraが複数あると、 意図せず「余計な描画」をして しまうケースが多々ある

115.

余計な描画を調べるには? • Unityには描画の処理を確認するためにFrameDebuggerがある • 描画の順番、描画したMaterialなどの確認が出来る

116.

FrameDebuggerデモ

117.

FrameDebuggerデモ メニューのWindow -> Frame Debugger にて呼び出し可能

118.

FrameDebuggerデモ Enableを押すと、キャプ チャーを開始

119.

FrameDebuggerデモ Unityが画面を描くときの 手順が記される 選択した部分までの描画 がGame画面に反映される

120.

Batch数、SetPass数について • Batch数はドローコールとも呼ばれ、実際に描画の命令を何回呼んだか? • SetPass数はマテリアル切り替えの処理を何回呼んだか? • 単純に呼ぶ回数が多ければ多いほど処理負荷になる。モバイルゲームで は200を超えた辺りから見直しが必要

121.

Batch数、SetPass数を測る Profilerの Renderingにてチェック

122.

Batch数、SetPass数への対策 • 出来るだけ同じマテリアルで描画する事でDynamic Batchingが効くよう にする • 同じマテリアルで描画するべく、Textureをパッキングする • 動かない背景モデルなどをStaticにして、Static Batchingが効くようにす る

123.

頂点数が多すぎないか? • 実はあまり問題になったことがない • モバイルでも数万ポリゴンは余裕で出る • 頂点数はわかりやすいので、作成時に最初から気を使っている様子

124.

描画面積が多すぎないか? • 塗るピクセル数が多ければ多いほど、描画の負荷が大きくなる • 透明な色で塗っていても、描画負荷は同様に掛かる • 特にUI/半透明オブジェクトでの描画面積には注意が必要 • 透明色で大きな面積を塗りつぶしている可能性がある • ImageEffectは一つ付ける毎に画面を塗りなおしている

125.

Shaderが重くないか? • Shader内での計算が複雑になればなるほど、1ピクセルを描画するのにか かる時間が増えていく • 描画面積×Shaderの重さ が負荷になる • 描画面積の大きい「地面・空」などで重いShaderを使っていると、大き な描画負荷になる

126.

地面のShaderに要注意 地面は描画面積が大きくなる ケースが多い 軽めのShaderにしないと描画処 理が重くなる

127.

Shaderが重くないかチェックする • Unity Profilerよりも、各プラットフォーム別に用意されているGPU Profilerで測った方が早く出来る • 大抵の場合、描画毎にどれだけの時間がかかったか測れる • もう一つの手段としては、描画面積が大きい部分を、軽いShaderに置き 換えてみて、Profilerで差分を見てみる • 「Mobile/Unlit/Texture 」 「Mobile/VertexLit」辺り

128.

常にフレームレートが低い時 DebugログをOFFに 描画負荷 描画負荷? ロジック側の負荷? ロジック負荷 ロジック負荷チェックへ 描画処理負荷チェックへ

129.

ロジック側のチェック C# C#側が重い? Unity処理が重い? NO 重い箇所を更に特定。 UIか?物理か? 重い箇所に合わせた対応を行う C#のスクリプトの見直し

130.

描画負荷チェック YES 余計な描画をしないようCamera 余計な描画してない? の設定等見直し NO YES Batch数は多いか? Materialをうまくまとめて、 DynamicBatchingされるようにする NO あとは、Shader×描画面積の問題。 重いShaderで沢山塗っていないか? 何度も半透明で重ね塗りしていないか?

131.

まとめ • 最適化はゲーム体験をよくするためにする作業 • 最適化を行う前にプロファイルをして、直すべき箇所を探し出す • Unityにはプロファイルのための機能があるので、それらをうまく活用し よう

132.

Thank you!

133.

Appendix: ステップアップ テクニック集

134.

ステップアップテクニック • Profilerの結果保存について • スクリプトのある部分だけ処理負荷を測りたい • 各プラットフォーム毎のGPU Profilerも使う

135.

Profilerの結果保存について Unity 5.6から、結果の保存/読 み込みが可能に!!

136.

でもグラフに表示されている 300フレームしか保存されない!

137.

結果保存のためのツール・手順紹介 • Unity 5.6以降で有効なエディター拡張 • 300フレーム毎に、SaveをするためのEditor拡張を作成 • https://github.com/wotakuro/UnityProfilerIntervalSave • Unity5.5以前でも有効な方法 • Android/iOS端末上でログファイルを書き出すようにして、実行後にPC へ転送、解析を行う手法 • https://github.com/wotakuro/ProfilerBinarylogSplit

138.

前ページで紹介したやり方を使 えば、プロファイル結果を全て 保存できるように

139.

スクリプトのある部分だけ 処理負荷を測りたい C#側で処理の時間が測れるのは、 メソッド単位になっている

140.

スクリプトのある部分だけ 処理負荷を測りたい • Profiler.BeginSample(“Profilerに出したい名前”); Profiler.EndSample(); で囲った区間の処理を測ることが可能! ※Unity 5.5からは「using UnityEngine.Profiling;」が 必要なので注意

141.

BeginSampleのサンプルコード void Update(){ // 移動処理等が書いてある …. Profiler.BeginSample(“アニメ切り替え”); // Profilerで測りたいアニメ切替の処理 …… Profiler.EndSample(); // 残りの処理等 …. }

142.

スクリプトのある部分だけ 処理負荷を測りたい Profiler.BeginSample ~ EndSample の処理時間 が確認できる

143.

こんな使い方も… void LoadAssetBunlde( string name){ Profiler.BeginSample(“AssetBundle読み込み ” + name); // nameで指定されたAssetBundleを読み込む処理 …… Profiler.EndSample(); } 好きな名前を指定できるので、読み込もうとしている AssetBundle名を入れることで、AssetBundle毎の 読み込み時間がわかる

144.

BeginSample/EndSampleを 使いこなせば、Profilerの幅が もっと広がる

145.

各プラットフォーム毎に用意された GPU Profilerを使う • 各プラットフォーム別のGPU Profilerを使う主な理由 • 描画で、GPUに関する情報はUnityのProfilerでは不足 • 描画毎に何ミリ秒取られたかが細かく確認できる

146.

各プラットフォーム毎に用意された GPU Profilerを使う • iOS • XcodeのOpenGLES Frame Debugger • Android • チップメーカー毎に違う • Mali -> Mali Graphics Debugger • Snapdragon -> Snapdragon Profiler • Tegra -> Tegra Graphics Debugger • Windows上のEditor • Render Doc

147.

OpenGLES Frame Debugger

148.

Mali Graphics Debugger

149.

Snapdragon Profiler

150.

Render Doc

151.

描画負荷を深追いしたい場合は、 各プラットフォーム毎にある GPU Profilerを使う