質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

2560閲覧

【Unity2D】SetPropertyBlockによるテクスチャ差し替えのタイミングについて

flow_man

総合スコア19

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/04/15 10:04

やりたいこと

Unityで2Dゲームを作成しようと思っています。Unity歴1ヶ月ほど、ゲーム開発経験なしです。

下記サイトを参考に、1つのAnimatorControllerを画像の差し替えのみで(同画面内の)複数キャラに使いまわそうと思っています。
参考にさせていただいたサイト

質問したいこと

一応思った通りの動作はしてくれたのですが腑に落ちない部分があります。

「sprRenderer.SetPropertyBlock(block);」について、
「Update()」で実行すると、差し替え前のアニメがちらちら見えます。
「LateUpdate()」で実行すると、それがなくなり問題なく表示されます。

「Update()」では上手く表示されなかった原因はなんでしょうか?

ネットで調べてみてもコレというものが見つかりませんでした。

海外のサイトで「アニメーションシステムは、更新後、LateUpdateの前に更新されることに注意(和訳済み)」と書いてあるのを見つけたのですが、このことなのでしょうか?(よく理解は出来ていないのですが)

また、この方法が効率が良いと思ったので採用を考えているのですが、もしこの方法での問題点やほかに良い方法などがあればアドバイスを頂けると幸いです。

該当のソースコード

私が動作確認に使用したスクリプトはこちらになります。
下記のことを行っています。

  1. SpriteRendereからMaterialPropertyBlockを取得する。
  2. 取得した内容を任意のTextureで上書きする。
  3. SpriteRendereを上書き後の内容で更新する。(Update / LateUpdate)

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Enemy : MonoBehaviour 6{ 7 // アニメーション差し替え用テスクチャ 8 [SerializeField] 9 private Texture texture = null; 10 11 // プロパティーのIDを取得しておく 12 // マテリアルのシェーダーのテクスチャ変数名らしい 13 private static int idMainTex = Shader.PropertyToID("_MainTex"); 14 15 // アニメーターコンポーネントへの参照を格納する 16 private Animator animator; 17 18 // スプライトレンダラーコンポーネントへの参照を格納する 19 private SpriteRenderer sprRenderer; 20 21 // オブジェクトのマテリアル情報を格納する 22 private MaterialPropertyBlock block; 23 24 25 void Awake() 26 { 27 // 各コンポーネントを取得など 28 block = new MaterialPropertyBlock(); 29 sprRenderer = GetComponent<SpriteRenderer>(); 30 animator = GetComponent<Animator>(); 31 32 // SpriteRenderer から MaterialPropertyBlock を取得 33 sprRenderer.GetPropertyBlock(block); 34 35 // MaterialPropertyBlock にテスクチャをセットして上書き 36 block.SetTexture(idMainTex, texture); 37 38 // 初期のキャラの向きを設定 39 animator.SetInteger("direction", 1); 40 } 41 42 void Update() 43 { 44 // MaterialPropertyBlock を SpriteRenderer にセット 45 //sprRenderer.SetPropertyBlock(block); // こっちだとチラチラと元のアニメが見える 46 } 47 48 void LateUpdate() 49 { 50 // MaterialPropertyBlock を SpriteRenderer にセット 51 sprRenderer.SetPropertyBlock(block); 52 } 53}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ご提示いただいた「【Unity】”テクスチャの差し替え” で切り替わるスプライトアニメーションを作成する手順 - テラシュールブログ」の記事中で、

またスプライトが1秒間に12回だと速いので、半分の6回に減らしています。

とあります。これをさらにアニメーションを遅くして秒間2回とか1回にしていただくと明確になるでしょうが、スプライトが切り替わったタイミングでチラッと差し替え前のテクスチャが表示されるような挙動になっているかと思います。

イベント関数の実行順序 - Unity マニュアル」に載っている「スクリプトライフサイクルのフローチャート」をご覧いただきたいのですが、UpdateはGame logicセクションの冒頭、LateUpdateはGame logicセクションの末尾に位置しており、両者の間にInternal animation updateと書かれたセクションがあるのを見て取れるかと思います。

想像が混じってしまいますが(すみませんが実装の詳細はネイティブコードになっており、十分追い切れませんでした)、Animatorによるスプライトの切り替えはこのInternal animation update内で行われるのだろうと思います。そしてSpriteRendererはスプライトが差し替えられた時に自身のMaterialPropertyBlockを更新していると予想されます。

Update内でテクスチャ差し替えを行った場合、毎フレームGame logicセクションの冒頭でMaterialPropertyBlockのメインテクスチャ情報が新テクスチャに変更されるはずです。しかしその後にInternal animation updateのセクションがありますので、Animatorによるスプライト切り替え発生時には、そこでさらにスプライト切り替えに起因するMaterialPropertyBlock更新が起こるのでしょう。
そのためテクスチャが本来のテクスチャに戻されてしまい、そのフレームの描画は差し替え前のテクスチャとなってしまうと考えられます。その後次のフレームに進むと再びUpdateでテクスチャが差し替えられますので、結果として本来のテクスチャが1フレームだけ一瞬表示される...と説明できそうです。

一方、LateUpdateはInternal animation updateセクションよりも後ですから、ここでテクスチャ差し替えを行う場合は確実に毎フレームテクスチャが差し替えられた状態で後続のScene renderingセクションへ進むことができるはずです。ですので元のテクスチャがチラチラまぎれ込むことはないのでしょう。

この方法で問題点はあるか...という点に関しては、私の見たかぎりでは特に問題が起こりそうな要素は思い当たりませんでした。ですがもし気になる挙動に遭遇しましたら、コメントいただければ可能であれば対策を検討してみようと思います。

投稿2021/04/15 14:05

Bongo

総合スコア10811

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

flow_man

2021/04/16 18:11 編集

詳細なご説明ありがとうございます。納得いたしました。 実行サイクル「Update()」と「LateUpdate()」の間に「Internal animation update」があり、そこでAnimatorによるスプライト切り替えが発生してしまうという事なんですね。 「イベント関数の実行順序」のページは見たことがあったのですが、あまり詳細まで確認していませんでした。もっとしっかりと確認しようと思います。 また、この方法で問題なさそうとのご意見もありがとうございます。 まずはこの方法で進めていき、何か問題が発生して自己解決が出来なければ、この場所もしくは新たな質問投稿をしてご相談させて頂きたいと思います。 ありがとうございました。 #4/17 3:09 一部記載漏れがあったので訂正しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問