[Unity] DrawCallメモ(transform.renderer.material.color)
それについてコメントをいただいたので検証してみました。
いただいたコメントは、
「マテリアルを複製しないでマテリアルのパラメータを変更するには SetPropertyBlock() を使う」
というもの。
結論を先に言うと、
「DrawCallの検証は途中までで、SetPropertyBlock()の使い方がわかった」
という記事になります。
はじめに、状況確認。
スフィアを4つ用意して↓

各々に同じマテリアル(Diffuse)を適用します↓

次に、スクリプトを実行するために空のゲームオブジェクトを用意しました。
検証するスクリプトは2つなので、各々チェックボックスで切替えて実行します↓

準備ができたので検証に入ります。
@これまでやっていたマテリアルの切替え
MaterialTest1.js
---------------------------------------------------------------------
// これまでの手法(DrawCallが増加するはずだったのに……。3.5.5から解消?)
#pragma strict
private var objA : GameObject; // 各GameObjectのShaderには、マテリアル(Diffuse)が適用されている
private var objB : GameObject;
private var objC : GameObject;
private var objD : GameObject;
function Start() {
// GameObjectをキャッシュ
objA = GameObject.Find("TestSphereA");
objB = GameObject.Find("TestSphereB");
objC = GameObject.Find("TestSphereC");
objD = GameObject.Find("TestSphereD");
}
function Update() {
objA.transform.renderer.material.color = Color.green;
objB.transform.renderer.material.color = Color.white;
objC.transform.renderer.material.color = Color.cyan;
objD.transform.renderer.material.color = Color.blue;
}
---------------------------------------------------------------------そしてDrawCallを確認。
プレビュー前(DrawCall = 4)↓
プレビュー中(DrawCall = 4)↓
あれ?DrawCallが増えるかと思いきや、増えてない……。
rendererのmaterialを触ってしまうとマテリアルの複製がされるということですが、
どこを見るとマテリアルの数がわかるんだろう……。
詳しいことはわからないまま、次の検証へ。
SetPropertyBlock() を使ってみます。MaterialTest2.js今度はどうなったかな?
---------------------------------------------------------------------
// 参考
// http://docs.unity3d.com/Documentation/ScriptReference/Renderer.SetPropertyBlock.html
// http://docs.unity3d.com/Documentation/ScriptReference/MaterialPropertyBlock.html
// http://docs.unity3d.com/Documentation/ScriptReference/MaterialPropertyBlock.AddColor.html
#pragma strict
private var objA : GameObject; // 各GameObjectのShaderには、マテリアル(Diffuse)が適用されている
private var objB : GameObject;
private var objC : GameObject;
private var objD : GameObject;
private var materialProperty : MaterialPropertyBlock; // MaterialPropertyBlock
function Start() {
// GameObjectをキャッシュ
objA = GameObject.Find("TestSphereA");
objB = GameObject.Find("TestSphereB");
objC = GameObject.Find("TestSphereC");
objD = GameObject.Find("TestSphereD");
// MaterialPropertyBlockを生成
materialProperty = new MaterialPropertyBlock();
}
function Update() {
// マテリアルの色を設定
materialProperty.Clear();
materialProperty.AddColor("_Color", Color.green);
// GameObjectに反映
objA.transform.renderer.SetPropertyBlock(materialProperty);
// 他Objectも同様
materialProperty.Clear();
materialProperty.AddColor("_Color", Color.white);
objB.transform.renderer.SetPropertyBlock(materialProperty);
materialProperty.Clear();
materialProperty.AddColor("_Color", Color.cyan);
objC.transform.renderer.SetPropertyBlock(materialProperty);
materialProperty.Clear();
materialProperty.AddColor("_Color", Color.blue);
objD.transform.renderer.SetPropertyBlock(materialProperty);
}
---------------------------------------------------------------------
プレビュー中(DrawCall = 4)↓
こちらは予想通りDrawCallは増えず。
1つ目の検証と同様に、マテリアルが複製されているかどうかを知りたいところ。
ということで、SetPropertyBlock() を使ってGameObjectの色を変更することができました。
DrawCallを調べるという検証はマテリアルの数を調べるところで止まってしまいましたが、
SetPropertyBlock()の使い方がわかってよかったです(言い訳
------------------------- 2012.9.13追記 -------------------------
いただいたコメントのとおり、従来の方法(MaterialTest1.js)だと
Inspectorウィンドウのマテリアル名の後ろに(Instance)が表示されました↓
なるほど。
これでマテリアルが複製されることをチェックできるようになりました。
SetPropertyBlock()については、複製はしないけどDrawCall数を抑えるものではないとのこと。
詳しい内容はコメントの通りということで、また1つ勉強させていただきました。
ありがとうございます!
さて、SetPropertyBlockですが、あくまで「マテリアルを複製せずにシェーダのパラメータ転送が行える」ものなので、DrawCall数を抑えるものではないようです。
DrawCall数に変わりはありませんが、シーンの再生中に無駄なマテリアルのコピーが発生しないのと、シェーダプロパティの変数名ではなく、シェーダプロパティIDを指定することが出来るので、マテリアルの複製よりは高速に動作すると思われます。
また、マテリアルが複製されているかどうか?ですが、Inspectorウィンドウのマテリアル設定フィールドのマテリアルの名前の後ろに(Instance)が付いているとマテリアルが複製されているということみたいです。
シーン内の複製されているマテリアル数をカウントするツールを作ってみようかと思いましたが、renderer.material.nameプロパティにアクセスした時点でマテリアルが複製されてしまうので断念しましたw
それでは。
従来の記事に追記をして補足しました。
わざわざ検証方法まで検討していただいて、ありがとうございます!
マテリアルの複製は抑えても、DrawCall数は変化ないんですねー。
まだまだ知らないことが多いUnityですが、これからもコツコツ情報を蓄積していきたいと思います!