【uGUI】自作shaderのマテリアルをオブジェクト個別に作成して別の値を適応させる

起きた事象

uGUIのImageに自作のshaderを適応させようとした際に、
マテリアルの値を更新すると適応した全てのImageオブジェクトの反映されてしまいました。
期待値は変更した1つのImageオブジェクトにだけ変更した値が適応されたいです。

【環境】
unity2021.3.3f1

対処法

これは複数のImageオブジェクトで使用しているマテリアルが同一インスタンスのために発生しています。
なので、別のインスタンスを生成してセットしてあげればよいだけです。

Material baseMat = this.image.material;
this.image.material = new Material(baseMat.shader); //new して新しいインスタンスを作って設定する

this.image.material.SetFloat("_Alpha", alpha); //適応したい変更を新しく作ったマテリアルに適応する

これで、変更したいImageオブジェクトだけに変更を適応できるようになりました!

補足

マテリアルの値を変えるとそのたびにマテリアルが複製される。という有名な話がありますが、それはuGUIには当てはまりません。
※3Dオブジェクト等のUI以外のマテリアルを操作した際には発生するのでその時はMaterialPropertyBlock等を使って対処する必要があります。

試しに先程のコードに以下のようなログを仕込んでみると
変更前後で同じインスタンスIDがかえってきているので、これで複製されていない事が分かります。

Debug.Log("before:" + this.image.material.GetInstanceID());
this.image.material.SetFloat("_Alpha", alpha); //適応したい変更を新しく作ったマテリアルに適応する
Debug.Log("after:" + this.image.material.GetInstanceID());

【uGUI】Mask配下にあるImageに自作したshaderが適応されない時の回避方法(スクロールコンテンツでおきやすいかも)

起きた事象

以下のような①Canvas直下にあるImageオブジェクトと、②親にMaskコンポーネントを持つImageオブジェクトの2つがあるとします。

どちらのImageにも自作のマテリアル(shader)を適応しています。
話を単純にするためにshaderの中身はマテリアルで指定した色を反映するだけのものにしています。

この状態でマテリアルの色を変えると、Mask配下にあるImageにはなぜか適応されませんでした。
左:Mask配下のImage、右:Canvas直下にあるImage

この現象は、Maskコンポーネントを使ったものでおきるため、スクロール内のコンテンツなどでよく遭遇するかもしれません。

【環境】
unity2021.3.3f1

対処法

結論からいうと対処法というより回避方法になりますが、
マテリアルの値を変更する直前にMaskを無効化する、ということで対処しました!

Mask無効化→マテリアルの値変更→Mask有効に戻す をスクリプトから行うことで対処できました。1フレ内でも問題なし。

~~~~~~~~~~~~~~~~~

よくよく見ていくと、インスペクターでも変更不可になっていることが目にみえてわかる。
左:Mask配下のImageのインスペクターの表示がグレーアウトされて値を変更できない見た目になっている。
右:Mask配下ではないImage
 


詳しくはわからないが、以下の記事を見る限り(ステンシルバッファ?
Maskコンポーネントは配下のオブジェクトの描画に影響を与える仕組みが実装されているっぽく、
それによって自作shaderが無効化されてしまうタイミングがあるようだ。このあたりの動きも加味したshaderを書くのが本当は正しいように思われる。 discussions.unity.com

【Timeline】AnimationTrackに早送りやスキップがうまく適応されない時に見直したい事

起きた事象

前提として、TimelineのAnimationTrackを使うことで、TimelineからAnimationClipのアニメーションを呼びだせる。

コードからTimelineを操作してスキップ(特定の時間へ即移動)したり、倍速再生したときに

 playableDirector.time = 5f; //5秒目へスキップ

AnimationTrackで作ったアニメーションだけにスキップ処理や倍速処理が適応されなかった…(他のTrackは問題なし)

本来は、TimelineからAnimationClipを呼んだ場合もスキップや早送りが適応されます。
(Timelineで作ったアニメーションじゃなくてもこれらの恩恵はちゃんと得られる)

対処法


AnimationTrackに設定しているAnimatorのContollerにAnimatorController がついていたことが原因。Timelineで使う場合はNoneになってる事を確認しよう。
(そもそもAnimatorControllerの代わりにTimeLine作ってるのでいらない)
Timelineの操作がAnimatorControllerで打ち消されてしまっていた模様。
(自分でアニメーションを作っている人なら問題でなそうだが、デザイナが作ったデータをエンジニアが操作しているときとか発生しそう)

ちなみにシグナルから呼ばれたスクリプト処理にはスキップや早送りは適応されません
シグナルから呼ばれるスクリプトでサウンド再生処理とか作った上で早送りとかしても、サウンド自体は早送りされないって意味。