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

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

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

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

Q&A

解決済

1回答

1855閲覧

アニメーションイベントによるブレンドシェイプの挙動について

MethCat

総合スコア1

C#

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

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

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

0グッド

0クリップ

投稿2021/08/18 17:46

Animatorにて複数の表情の切り替えをAnimetion+アニメーションイベントで呼び出すスクリプトで制御できるようにしたいのですが。

発生している問題

スクリプトで制御するブレンドシェイプ(ここではA,B,Cとする)があり

アニメーションAで制御するブレンドシェイプ(D,E,F)があるとして

この条件だとアニメーションイベントから呼びだした関数でブレンドシェイプの
変更ができるのですが。

アニメーションB(ブレンドシェイプA,B,Dの様にスクリプト制御してるやつが混ざってる)をアニメーター中に
追加するとスクリプトで変更が出来なくなります。

もちろんそこに遷移してる状態では無く、下の様にトランジションをつないでなくても発生します。

イメージ説明

アニメーションイベントの呼び出し方は下の様にしています
イメージ説明

呼び出してるはstartLv7()になります。

using

1using System.Collections.Generic; 2using UnityEngine; 3 4public class RandomMoph22 : MonoBehaviour 5{ 6 public Animator anim; 7 public SkinnedMeshRenderer mophObject; 8 public Material tereMat; 9 public float actionTime; 10 private float countTime; 11 12 // Start is called before the first frame update 13 void Start() 14 { 15 16 } 17 18 // Update is called once per frame 19 void Update() 20 { 21 22 23 } 24 25 public void startLv7() 26 { 27 StartCoroutine("Facelv7"); 28 } 29 30 // ランダム判定用関数 31 IEnumerator Facelv7() 32 { 33 34 // 無限ループ開始 35 while (true) 36 { 37 38 tereMat.color = Color.red; 39 float scaleVal = Random.Range(80.0f, 90.0f); 40 float scaleVal2 = Random.Range(70.0f, 90.0f); 41 float scaleVal3 = Random.Range(10f, 20f); 42 43 mophObject.SetBlendShapeWeight(4, scaleVal); 44 mophObject.SetBlendShapeWeight(7, scaleVal3); 45 46 mophObject.SetBlendShapeWeight(20, scaleVal3); 47 48 mophObject.SetBlendShapeWeight(91, scaleVal2); 49 mophObject.SetBlendShapeWeight(92, scaleVal2); 50 51 countTime += 0.2f; 52 53 yield return new WaitForSeconds(0.1f); 54 55 Debug.Log(scaleVal2); 56 57 //ここでリセット 58 if (countTime >= actionTime) 59 { 60 61 tereMat.color = Color.white; 62 mophObject.SetBlendShapeWeight(4, 0f); 63 mophObject.SetBlendShapeWeight(7, 0f); 64 mophObject.SetBlendShapeWeight(20, 0f); 65 mophObject.SetBlendShapeWeight(91, 0f); 66 mophObject.SetBlendShapeWeight(92, 0f); 67 anim.SetTrigger("ResetTrigger"); 68 countTime = 0; 69 break; 70 } 71 72 } 73 } 74 75} 76

アニメーションとスクリプトなどで同時に制御したいのですが
この方法では、アニメーター内にスクリプトで制御するブレンドシェイプにかぶりがあった場合
干渉しできなくなるのでしょうか?
それとも根本的な間違いがあるのでしょうか?

補足情報(FW/ツールのバージョンなど)

皆様のご知恵お貸しください、どうぞよろしくお願いいたします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

イベント関数の実行順序 - Unity マニュアル」の図をご覧いただきたいのですが、コルーチン内のyield return new WaitForSeconds(0.1f);の再開タイミングはGame logicセクションの上の方で、一方Animatorによるアニメーション更新はその下のInternal animation updateセクションで行われるはずです。
おそらくこのために、スクリプト上で設定したウェイトよりもAnimatorが設定したウェイトの方が優先されてしまうのではないでしょうか。

Internal animation updateよりも後、かつレンダリングより前のタイミングでコルーチン実行再開ができればいいんじゃないかと思いますが、どうやらそういった目的にかなうYieldInstructionはなさそうな感じですね。
コルーチン内で処理が完結しておらず見苦しいかもしれませんが、下記のような形ではどうでしょうか?

lang

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class RandomMoph22 : MonoBehaviour 6{ 7 public Animator anim; 8 public SkinnedMeshRenderer mophObject; 9 public Material tereMat; 10 public float actionTime; 11 private float countTime; 12 13 // Start is called before the first frame update 14 void Start() 15 { 16 } 17 18 // Update is called once per frame 19 void Update() 20 { 21 } 22 23 public void startLv7() 24 { 25 StartCoroutine("Facelv7"); 26 } 27 28 // ブレンドシェイプインデックスとウェイトを対応づけるマップを用意する 29 private Dictionary<int, float> weights = new Dictionary<int, float>(); 30 31 // ランダム判定用関数 32 IEnumerator Facelv7() 33 { 34 // 無限ループ開始 35 while (true) 36 { 37 38 tereMat.color = Color.red; 39 float scaleVal = Random.Range(80.0f, 90.0f); 40 float scaleVal2 = Random.Range(70.0f, 90.0f); 41 float scaleVal3 = Random.Range(10f, 20f); 42 43 // コルーチン内ではSetBlendShapeWeightを行わず、ウェイトを更新するだけにする 44 weights.Clear(); 45 weights[4] = scaleVal; 46 weights[7] = scaleVal3; 47 weights[20] = scaleVal3; 48 weights[91] = scaleVal2; 49 weights[92] = scaleVal2; 50 51 countTime += 0.2f; 52 53 yield return new WaitForSeconds(0.1f); 54 55 Debug.Log(scaleVal2); 56 57 //ここでリセット 58 if (countTime >= actionTime) 59 { 60 61 tereMat.color = Color.white; 62 63 // コルーチン内ではSetBlendShapeWeightを行わず、ウェイトを更新するだけにする 64 weights.Clear(); 65 weights[4] = 0f; 66 weights[7] = 0f; 67 weights[20] = 0f; 68 weights[91] = 0f; 69 weights[92] = 0f; 70 71 anim.SetTrigger("ResetTrigger"); 72 countTime = 0; 73 break; 74 } 75 } 76 } 77 78 // LateUpdateのタイミングでSetBlendShapeWeightを行う 79 void LateUpdate() 80 { 81 foreach (KeyValuePair<int, float> indexWeightPair in weights) 82 { 83 mophObject.SetBlendShapeWeight(indexWeightPair.Key, indexWeightPair.Value); 84 } 85 } 86}

投稿2021/08/23 10:59

Bongo

総合スコア10811

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

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

MethCat

2021/08/31 02:52

ご返答遅れてしまい申し訳ございません、ご回答ありがとうございます! ご指摘の通り、実行のタイミングをLateUpdate内でやるとしっかり値が上書きされました。 正直、全てスクリプトで制御しても問題なかったのでスクリプトだけでアニメーションを実装したんですが、これで今後組み合わせで実行できます、ご親切に参考スクリプトも頂いて本当にありがとうございます。 ただ再生をしてないアニメーションが存在しているだけでそのブレンドシェイプが書き換えられなかったのかはまだ謎ですが(恐らくアニメーター内での処理で先に再生してないブレンドシェイプも取得している状態?)実装には問題なさそうです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問