【Unity】Draw CallやSetPass Callって結局なんなのか?

Draw CallやSetPass Callについて調べると、どうやらこれらがパフォーマンスに影響することがわかります。
また、実際に回数を減らすためのノウハウも色々と解説されています。

が、じゃあDraw CallやSetPass Callってそもそも何なの?どう違うの?って話がイマイチわからなかったので調べました。

レンダリング処理の流れ

レンダリングする際には、まずCPUが全てのレンダリング対象オブジェクトの情報を集めます。

次にこれらのうち、マテリアルが同じだったりといったバッチング条件に合うものを一つのメッシュにまとめます。
こうしてまとめたメッシュごとに、Batchという処理単位を作ります。

その後このBatchごとに、SetPass Call -> Draw Callの順に処理をしていきます。

SetPass Callとは、マテリアルの設定値をCPUがGPUに教える処理です。
もし一回前にSetPassした時とマテリアルが同じであれば、SetPass Callは不要なのでスキップされます。

その後Draw Callが呼ばれます。
Draw Callとは、CPUがGPUに、SetPass Callで設定された値を用いてメッシュを描画することを命令することです。

同一マテリアル、別メッシュでレンダリングしてみる

さてDraw CallとSetPass Callの意味がわかったところで、いくつか検証をしてみます。

まず、マテリアルを同一にしてメッシュを変えた二つのオブジェクトをレンダリングしてみます。
片方はCube、片方はCylinderにしています。

f:id:halya_11:20180605232941p:plain

バッチングされてBatches、SetPass Calls共に1となりました。

同一マテリアル、大きいメッシュでレンダリングしてみる

次に、頂点数の多いメッシュはバッチングされないということなので、同じマテリアルを使ってSphereを2つレンダリングしてみます。

f:id:halya_11:20180605232702p:plain

確かにバッチングはされずBatchesは2となっています。
ただし同じマテリアルを使っているため、2回目のSetPassがスキップされてSetPass Callsは1で済みました。

マルチパスシェーダを使ってみる

次にシンプルな2パスのシェーダを適用したマテリアルを作り、二つのCubeにアサインします。

f:id:halya_11:20180605235210p:plain

Batchesは4、SetPass Callsは2となりました。
2パスのシェーダはバッチングの条件を満たさないためバッチはされません。
SetPass Callsについては、今回のケースではまず両オブジェクトの1パス目がレンダリングされ、それから両オブジェクトの2パス目がレンダリングされるという順序であったため、2回に節約されました。

MaterialPropertyBlockを使ってみる

MaterialPropertyBlockについては、これを使ったからといってDraw Call、SetPass Call削減につながるということはありませんでした。

もちろんマテリアルの値が完全に同一であればバッチングされはしますが、これはMaterialPropertyBlockを使わなくても同じことです。

MaterialPropertyBlockは、ただマテリアルのインスタンスを複製することなしにプロパティを変更できるという機能であるようです。

Unity UIについて

UIに関しては、上述の内容とは少し違った挙動をします。
例えばSpriteの違うButtonを大量に並べたりするとわかりますが、Batchesは増えるもののSetPass Callsが増えません。

UIに関しては何か特別な最適化が内部的に行われていそうです。

参考にしたサイト

この記事を書く上で、下の記事を参考にしました。
パフォーマンスの最適化に関する記事ですが、レンダリングの仕組みについても詳しく書かれています。

unity3d.com

A brief introduction to renderingあたりに色々と書いてあります。