BETA

VRChatパフォーマンス最適化ことはじめ Part 1

投稿日:2020-07-15
最終更新:2020-07-15

伝えたいこと

計測しましょう。最適化は計測にはじまり、計測で終わります。

想定する読者層

  • VRChatユーザー
  • Unityでアバターやワールドをアップロードしたことがある
  • Unityの操作はできるが、詳しい仕組みはわからない
  • 「自分のアバターやワールドが重いんじゃないかな」という漠然とした不安がある
  • アバターやワールドの容量を軽くしたり、フレームレートを上げたいと思っているが、どうしたらいいかわからない

この記事を読んだらわかること

  • パフォーマンス最適化の心構え

次回以降で書くこと

  • コンピュータグラフィックスの基礎知識
  • パフォーマンスを計測する方法
  • 計測した情報を解釈して、どこを直したらいいのかを推測するための基礎知識や方法論

書かないこと

  • 何をしたら容量が軽くなるのか、フレームレートが上がるのか、という詳細で具体的な手順

はじめに

VRChatはユーザーが自由にアバターやワールドといったコンテンツを投稿でき、多くの人は無償で活動しています。作ったワールドでフレームレートがどれだけ下がろうが、大容量高精細のアバターを使おうが自由です。すべてのユーザーは重いアバターを自動的に非表示にできるので、ある程度の快適性を保つことができます。
フレームレートが高ければ快適に過ごすことができます。アバターやワールドの描画負荷が軽く、しかも魅力的な表現を両立できていれば、よりたくさんの人に見てもらえる機会が増えます。また、インスタンスの参加者が増えてもフレームレートが下がりにくいワールドを作ることができれば、たくさんの人を集めてイベントをすることもできます。Quest向けであればバッテリー消費を減らし、長時間おしゃべりを楽しむこともできます。
パフォーマンス最適化をすることのメリットは多いですが、作業が不要な場合もあります。

  • すでにフレームレートや容量の目標を達成している
  • ワールドの描画負荷は高いが、参加者を少数に制限することで目標のフレームレートを達成している
  • 演者のアバターの描画負荷は高いが、観客のアバターを超軽量に制限することで目標を達成している
  • 動画撮影など自分一人で利用するので、重かろうが関係ない

このように、すでに目標を達成しているのならば、最適化は不要です。最適化は目標を達成できれば完了です。やりすぎて表現力をいたずらに削ったり、睡眠時間(寿命)を削ったりしては本末転倒です。
つまり、最適化を成功させるためには、適切に目標を設定することが大切です。

  • 自分の作るアバターやワールドは、誰がどんなふうに使うことを想定しているのか
  • どれくらいの性能の機器で、どれくらいの人数が参加して、どれくらいのフレームレートが出ればいいのか
  • コンテンツのダウンロード容量はどれくらいであればいいのか
  • たくさんの人が参加するインスタンス向けに軽いアバターを作りたいのか
  • 少人数のインスタンスで大切な誰かをもてなしたり自分を表現するために、描画負荷が重くても素晴らしい表現力を宿したアバターを作りたいのか

まずは自分がなにを目指して作ろうとしているのかを、ぼんやりでもいいので思い浮かべましょう。
目標に到達するためには、なにかを犠牲にしなければならないことがあります。運良くなにも犠牲にせずに目標を達成できることもあります。なにを犠牲にしてなにを得るかはすべてあなたの選択です。ですから、この記事では「こうすれば必ず軽くなる」といったことは書けません。

自分がどんな目標に向かって最適化をするのかぼんやりとつかめたら、最適化のための方法論を学びましょう。まずは、ここまでさんざん登場している「フレームレート」について解説します。

フレームレートとは

「フレームレート(frame rate)」とは、1秒間に何回ディスプレイの映像を更新できたか、という統計です。単位はHz(ヘルツ)だったり、fps(frame per second)だったりしますが同じ意味です。
「フレーム(frame)」とはディスプレイに描画する1枚の画像のことです。フレームを1秒間に何度も描画することで、モノが動いているように脳を錯覚させます。パラパラ漫画と同じ原理です。
フレームレートはディスプレイごとに最大値が決まっていて、Oculus Questなら72Hz、Rift Sなら80Hz、Valve Indexなら144Hzです。フレームレートが高ければ高いほど、なめらかに動いているように見えます。
VRChatでは、メニューの右下で定期的に更新される値がそれです。下図では「92 (Hz)」と表示されています。次の瞬間には89だったり、93だったり振れ幅があります。

フレームレートの逆数(分母と分子をひっくり返すやつ。1をフレームレートで割る)を取ると、1フレームあたりどれくらいの時間で描画しなければならないのかがわかります。たとえば、72Hzなら1 / 72 = 0.0139です。/は割り算記号の代わりです。千分の1秒である「ミリ秒(milliseconds, ms)」単位で表すと、13.9ms となります。

フレーム落ちとは

ディスプレイのフレームレートが72Hzだとして、もしVRChatのワールドとアバターを描画するのに13.9ms以上かかると、描画の更新が間に合わず、ディスプレイは前回の更新で描画された画像のままになります。VR HMDの場合、頭の動きと前回の描画内容をもとに高度なフレーム補完を用いて、VR酔いしにくいように自動的に描画を更新してくれます(が、万能ではありません)。
目標のフレームレートに到達していない状態のことを「フレーム落ち」といいます(会社や地域やコミュニティによってさまざまな言い方があります)。Oculus Storeやコンソール機など、プラットフォームによってはフレーム落ちするとストアで売らせてもらえません。VRChatでは今のところ何も言われないようです。
VR HMDを使っている場合は、フレーム落ちするとVR酔いしてしまうおそれがあります。VR酔いは個人差が非常に大きく、1フレームでも落ちるとだめな人もいれば、10fpsしか出てなくても平気な人もいます。とくに開発者は慣れてしまって信用ならないので、VR酔いしやすい人はテスターとして重宝されたりします。
残念ながらVRChatでは、40人超など大人数のインスタンスにおいて、最新のPCでもVR HMDの上限フレームレートを維持できるケースはまれなようです。今のところはそういうものだと腹をくくって、運営に改善要望を出しつつ、ユーザー側でできることをやりましょう。

VR HMDでフレーム落ちが発生したときのフレームレートの特性

2Dのディスプレイと異なり、VR HMDではフレーム落ちしたときに段階的にフレームレートが下がります。例えばOculus Rift CV1では、90Hzに満たないフレームレートになると45Hzになり、それも間に合わなければ約22Hz、次に10Hz程度になります。Oculus QuestをPCで使用した場合(Oculus LinkやVirtual Desktop)も同様で、おそらくValve Indexでも同じでしょう。

ダウンロード容量とは

VRChat向けに作成したアバターやワールドは、VRChatのサーバーにアップロードされます。インスタンスに参加した全員がアバターやワールドのデータをダウンロードします。VRChatでインスタンスに参加するときにプログレスバーが出ますが、これがワールドのダウンロード容量です。

アバターのダウンロード容量は、VRChatを普通にプレイしていると表示されることはありません。

計測に始まり、計測に終わる

では、快適なフレームレートを維持し、素早くダウンロードが終わるためにダウンロード容量を小さくするにはどうすればいいでしょうか?最初の一歩は、計測することです。
VRChatのメニューを開いて、フレームレートが十分に出ているかを見てみましょう。自分が十分だと思えば、もうやることはありません。おめでとうございます!
もし十分にフレームレートが出ていなければ、なにか作業をしてフレームレートが出るように修正したくなるでしょう。では何をしましょうか。ポリゴン数を削ってみる?テクスチャを圧縮する?リアルタイムライトを消してベイクしてみる?それとも全部やる?
ちょっと待ってください。もちろん手当たり次第にやってフレームレートが上がれば成功かもしれません。でも、それで犠牲にしたものはなんでしょうか?

  • ポリゴン数を削る:モデルの輪郭がカクカクとしてなめらかでない、表現力の喪失
  • テクスチャを圧縮する:ぼやけた画像、透過部分のノイズ、ロード時間の増加
  • ライトのベイク:最初の意図とは異なる表現、ダウンロード容量増加、メモリ使用量増加、テクスチャの負荷増加

なにか作業をすれば、必ず副作用があります。その副作用は納得して受け入れたものでしょうか?もし同時にこれらの作業をしていたとしたら、どの作業がどれくらいフレームレートに影響したのでしょうか?フレームレート向上に効果のない作業がなかったでしょうか?逆にフレームレートを下げる結果となった作業はなかったでしょうか?
実際の最適化作業では、ある作業が逆にフレームレートを下げる結果となる場合がよくあります。フレームレートが向上するかわりに、メモリ使用量やダウンロード容量が爆発的に増加することもあります。
意図しない副作用を防ぐため、最も原始的な作業手順は次のとおりになります。

  1. 現状のパフォーマンスを計測する
  2. 試しになにか一つだけ変えてみる
  3. どう変わったか計測する

そして、バージョン管理ツールを導入しましょう。GitHub for Unityがよいと思います。この記事がとてもわかりやすくコンパクトです:【超初心者向け】Unityのプロジェクトを、GitHub for Unityを使って超簡単にバックアップする方法
バージョン管理をすれば、試しに変えてみたところがうまくパフォーマンス向上につながらなくても、すぐに完全に元に戻すことができます。手作業で元に戻すのはおすすめできません。人間はミスするものですし、UnityやVRCSDKにもバグはあります。

当てずっぽうで試しに変えてみるのをたくさんやるのもいいですが、膨大な時間がかかります。しかも、成果につながらないことがほとんどです。効率的に最適化作業を進めるためには、「ボトルネック」を探し当てる必要があります。

ボトルネックを探す

ある一つの処理が原因でフレームレートが落ちていて、その処理を高速化しない限り、他をどうがんばっても改善できないということがほとんどです。フレームレートが落ちる原因となっているこの処理を指して「ボトルネック」と言います。コンピュータグラフィックスは、たとえば水道管のように、複数の処理をつなぎ合わせてデータを加工していくことで画像を描画する仕組みになっています。そのため、どこか一つが遅いとそこで詰まってしまい、他をどれだけ高速化したところでフレームレートは改善しません。これを「細くなった瓶の首部分」にたとえて「ボトルネック」と呼んでいます。
コンピュータは電気で動いているので、水の流れを見るようにはボトルネックが見えるわけではありません。水道管でも要所に水流計を置いて計測します。そうです、ボトルネックを特定するには計測するしか方法はありません。
コンピュータは物理的にもたくさんの部品でできていて、ソフトウェアという形のないものを搭載しています。それでも、計測するための道具を使って物理的かつ論理的なボトルネックを探すことができます。この道具は総じて「プロファイラ(Profiler)」と呼ばれています。この道具を駆使して、なにを改善すればよいのかを一つひとつ探して、改善して、また計測して効果をみる。これが最適化という作業です。

つづく

次回は、コンピュータグラフィックスの基礎からプロファイラを使ったボトルネックの特定方法まで解説します。
(いつ頃になるかは未定、気分次第です)

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

フリーランスなオーディオプログラマの技術ブログ。VRやUnityについての記事を書きます。 https://twitter.com/tyounanmoti

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう