Version: 2023.1
言語: 日本語
シェーダーのパフォーマンスについての理解
Visual Studio を使ったシェーダーのデバッグ

シェーダーのランタイムパフォーマンスの最適化

異なる種類のプラットフォームには、かなり大きなパフォーマンス能力の違いがあります。ハイエンドの PC GPU はグラフィックスとシェーダーの面で、ローエンドのモバイル GPU に比べ、ずいぶん多くを処理できます。個々のプラットフォームに関しても同じことが言えます。GPU が速いと、GPU が遅いものに比べ、十数倍速く処理を行います。

モバイルプラットフォームおよびローエンド PC での GPU パフォーマンスは、使用されている開発用マシンより遥かに低速であると考えられます。ローエンド GPU マシン全体で良好なパフォーマンスを得るために、シェーダーを手動で最適化して計算量およびテクスチャ読み込みを削減することを推奨します。例えば、いくつかのビルトインシェーダーオブジェクトは大幅に高速な “モバイル版” の同等オブジェクトを備えいます。ただし、いくつかの制限事項や近似要素があります。

このページでは、ランタイムパフォーマンスのためにシェーダーを最適化するための情報を提供します。

必要なものだけを計算する

シェーダーコードが行う計算や処理が多ければ多いほど、ゲームのパフォーマンスに影響を与えます。例えば、各マテリアルごとのカラーをサポートするのはシェーダーを柔軟にするにはよいですが、常にカラーが白のままに設定すると、画面上にレンダリングされる各頂点やピクセルのために不要な計算が行われます。

もう一つ頭に入れておくべきことは計算の頻度です。通常、ピクセル(ピクセルシェーダーとして実行)のほうが頂点(頂点シェーダーとして実行)より多くのがレンダリングされ、さらに頂点ほうがオブジェクトより多くレンダリングされます。このため、一般的にはできることならば、ピクセルシェーダーコードの計算を頂点シェーダーコードに移動する、あるいはシェーダーから計算を完全に除いてスクリプトから値を設定するようにします。

計算の精度

Cg/HLSL でシェーダーを書く場合、3 つの基本的な数値タイプがあります。 floathalffixed です(詳細は シェーダーのデータタイプと精度 ページを参照してください)。

良好なパフォーマンスを実現するため、可能な限り低い精度を使用します。これはローエンドハードウェアで特に重要です。経験則から以下のようにします。

  • ワールド空間の位置とテクスチャ座標には、float 型を使用してください。
  • 上記以外 (ベクトル、HDR カラーなど) には、half で始めます。必要なときだけ、増加します。
  • テクスチャデータのとても簡易な操作には、fixed を使用します。

実際には、正確にはどの数の型を使用すべきかは、プラットフォームや GPU に依存します。一般的な概要は以下のとおりです。

  • あらゆる現代のデスクトップ GPU は、常にすべての事を完全な 浮動小数点数精度で計算していて、そのため、根底では float/half/fixed の結果はまったく同じになります。この事がテストを少し困難にしており、half/fixed の精度で実際は十分なのかどうか、PC上では判りにくいです。作成したシェーダーを、実際にモバイルデバイスで試してください。
  • モバイル GPU は実質的な 精度浮動小数点数をサポートしており、大抵は計算がより早く、より省エネです。
  • Fixed の精度は、一般的に古いモバイル GPU でのみ使いやすいものです。現代の多くの GPU(OpenGL ES 3 や Metal を実行することができるもの)は 固定 小数点数と 精度浮動小数点数を、内部的にはまったく同じものとして取り扱います。

詳細は、シェーダーのデータタイプと精度 を参照してください。

複雑な数学演算

超越数学関数 (powexplogcossintan など) は非常にリソース負荷が高いため、可能な場合はローエンドハードウェアでの使用を控えてください。可能な場合は、複雑な数学的計算の代替案としてルックアップテクスチャの使用を検討してください。

独自の操作 (normalizedotinversesqrt など) を書くことを避けてください。Unity のビルトインオプションは、ドライバがより優れたコードを生成できることを確証しています。アルファテスト (discard) の操作がしばしばフラグメントシェーダーを遅くすることに気を付けてください。

汎用サーフェイスシェーダーを減らす

サーフェスシェーダー はライティングと相互作用するシェーダーを書く場合に優れています。しかし、これらのデフォルトのオプションは、ある特定の状況向けに最適化されているのではなく、一般的なケース向けに対応できるようになっています。多くの場合、それを微調整することでシェーダーの実行を速くするか、サイズを小さくすることができます。

  • approxview ディレクティブは、ビュー方向を使用するシェーダー(鏡面)のためにあり、ピクセルごとでなく頂点ごとにビュー方向を正規化します。概算ですが、通常はこれで十分です。
  • halfasview は鏡面シェーダータイプをさらに早くします。Half-vector (ライティング方向とビューベクトルの中間)が計算され頂点ごとに正規化され、ライティングの関数 はあらかじめ、中間ベクトルをビューベクトルの代わりに、引数として受け取ります。
  • noforwardadd によりシェーダーは、フォワードレンダリングで指向性ライトのみ完全にサポートします。残りのライトは、頂点ライトや球面調和としてのエフェクトを、引き続き表現することができます。これはシェーダーを小さくすることに優れていて、複数のライトが存在していても、常にひとつのパスでレンダリングされます。
  • noambient により、シェーダーの環境光ライティングおよび球面調和を、無効化しますこれによりわずかに速くなります。

アルファテスト

固定関数の アルファテストやそのプログラマブル同等物である clip() は、異なるプラットフォームで異なるパフォーマンス特性を示します。

  • 一般的に、ほとんどのプラットフォームで、完全に透過のピクセルのカリングを使用するのは小さな利点があります。
  • しかし、iOS といくつかの Android デバイスでみられる PowerVR GPU では、アルファテストは高価です。ゲームがかえって遅くなるため、このプラットフォームでは、パフォーマンス最適化として使用しないでください。

カラーマスク

いくつかのプラットフォーム(たいてい、モバイル GPU は iOS と Android デバイスでみられます)では、ColorMask を使用してチャネルを除くこと(すなわち ColorMask RGB )は、高価であり、本当に必要な場合のみ使用してください。

シェーダーのパフォーマンスについての理解
Visual Studio を使ったシェーダーのデバッグ