![見出し画像](https://assets.st-note.com/production/uploads/images/40076449/rectangle_large_type_2_a850c8bc1355ca54c3c929828cd53ed4.png?width=1200)
Unity : Changing material from script
はじめに
Unity上で、Dynamicにmaterialを変更する方法として、以前、Klak syphonを使った方法を紹介しました。
これは、openframeworksなどで複雑なtextureを作成し、これをRealtimeにUnity側へ送る方法です。
一方、もっとシンプルに、ただmaterialの色をDynamicに変更したいケースがあります。
今回は、これを実現するためのtipsです。
環境
* MacBook Pro(Retina, 15-inch Mid 2015)
* Unity2018.2.2f1
* XCode v7.2
materialのPropertyをscriptから変更
例えばマテリアルの色を変える場合、以下のコードで行えます。
Color color = new Color(1.0f, 0, 0, 1.0f);
GetComponent<Renderer>().material.color = color;
ただしこれは、_Color という名前でプロパティが設定されているシェーダにのみ有効です。
より一般的には、以下のようなCodeとなります
Color color = new Color(1.0f, 0, 0, 1.0f);
GetComponent<Renderer>().material.SetColor("_Color", color);
第一引数はPropertiesの名前です。
また、SetFloatやSetVectorなどを使う事で他のプロパティも変更できます。
Propertyの確認
プロパティは、マテリアル右上の歯車からSelect Shaderを選択し、
下の方にあるPropertiesから確認できます。
左側がプロパティの名前、右側が型になります。
プロパティが存在するか
プロパティの存在確認を行いたい場合はHasPropertyを使います。
if(GetComponent<Renderer>().material.HasProperty("_TintColor")){
GetComponent<Renderer>().material.SetColor("_TintColor", Color.red);
}
sharedMaterial
Renderer.materialを変更すると、内部でマテリアルをコピーして作成し、その値を変更します。
同じマテリアルを使用しているObjectを全て変更したい場合、sharedMaterialを使います。
GetComponent<Renderer>().sharedMaterial.color = Color.red;
sharedMaterialはマテリアル自体の設定を変更しているので、シーンの実行を終了しても元に戻りません。
ご注意ください。
まとめ
Renderer.sharedMaterialは、元のmaterial自体を操作する。
よって、同materialをapplyされた全てのObjectが同時に変更される。
また、scriptによって変更された"元のmaterial"は、実行後も変更されたままである点に注意。
Renderer.materialを操作すると、このObject専用のmaterialが、内部で自動複製され、これが操作される。
GameObjectを破棄しても、materialは破棄されないので、leakには注意すること。
official pageの使い方に乗っ取り、Start()で取得してこれを操作。OnDestroy()でmaterialを破棄すること。DestroyImmediateの方がいいのかな、と思ったけど、DestroyImmediateは非推奨のようです。official pageもDestroy( )で対応しているので、こちらがいいですね。
もっと考察
Renderer.materialのmemory leakが心配だったので、さらに考察した。
具体的には、"Resources.FindObjectsOfTypeAll"を使ってmaterialのResourceを表示しながらtestした
> 結果と考察
* Renderer.materialを使っても、実行中に"Resources.FindObjectsOfTypeAll(typeof(Material)).Length"が増えていくことはなかった(leakしてない)。
* "Resources.FindObjectsOfTypeAll(typeof(Material)).Length"の絶対値については、Scene中に配置したmaterialの数と合わず、不明
* unity editor上では、Start/Stop/Start...を繰り返す度、"Resources.FindObjectsOfTypeAll(typeof(Material)).Length"の初期値が増えていった(実行中には増えないが).
* 試しにexeを書き出し、これを実行してみたが、この時は、何度起動し直しても、毎回 同じ初期値(つまりeditorのみの問題)。Material意外のitem(e.g. GameObject)は、起動の度、増えるようなことは、ない。
また、 "Resources.FindObjectsOfTypeAll(typeof(Material)).Length"について、
* Unity2017.4.11f1(Latest of 2017)までは、起動の度、同じ値(相変わらず、絶対値は不明)
*Unity2018.1.0f2(1st of 2018)から、起動の度に絶対値が1ずつ増える現象が発生
であることがわかった。
...Unity2018から発生したbug? or editor上で、Gabage Collectionをするタイミングや条件を最適化したのだろうか?
結論
Unity2017を使おうかとも考えたが、以下の理由から最新(Unity2018.2.2f1)を使うこととしよう。
* 少なくとも、書き出されたexeは問題ない
* Klak Syphonが"Unity 2018.1"以降対応
「editor上の最適化が異なるだけ」であると信じるとしよう。
どなたか、知っている人がいたら教えてください。
Source Code
Source Codeは、以下にupしてあります。
https://github.com/SJ-magic-study-unity/MaterialCol_x_script
から、"ControlMaterialColor.cs"をダウンロードしてください。
編集後記
今、以前つくっていた音楽連動Systemをzeroからつくりなおしています。新Systemでは、Unity上に配置したLight用Objectを音楽に合わせて光らせようと思っています。このためには、materialの色だけでなく、Bloom効果や、emissionのDynamicな変更が必要になりますが、これらは次回、ご紹介します。
参考文献/ URL
* マテリアルのプロパティをスクリプトから変更【Unity】
* Color (unity official documentation)
* Unity でスクリプトから Renderer の Material を操作するとリークする件について
* Renderer.material(公式page:English)
もしよろしければ、サポートをお願いします! 頂いたサポートは、Creatorとしての活動費に充てさせて頂きます。