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

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

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

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

Unity

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

Q&A

解決済

1回答

1027閲覧

スクリプトによるモーションとアニメーターコントローラーによるモーションを混合させたい

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Unity

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

1グッド

1クリップ

投稿2021/03/16 09:57

編集2021/03/17 02:07

前提・実現したいこと

アニメーターコントローラーで作成したモーションに,スクリプトによるモーションが加算合成されたモーションを実現したいのですが,方法が不明です.

キャラクターに下図の様なIdle状態のモーションをさせるアニメーターコントローラーを指定したアニメーターがアタッチされています.
イメージ説明
さらに,例えばこの様な腕を回転させ続けるスクリプトを作り,これもアタッチしました.

C#

1using UnityEngine; 2 3public class Bones : MonoBehaviour 4{ 5 [SerializeField] Animator _animator; 6 // Update is called once per frame 7 void Update() 8 { var arm=_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm); 9 arm.Rotate(new Vector3(3.14f,0,0)); 10 } 11}

発生している問題・エラーメッセージ

  • アニメーターとスクリプトを二つともアタッチした状態ではアニメーターしか有効となりません.
  • アニメーターのコントローラーを「なし(Runtime Animator Controller)」とすると,スクリプトが有効となります.

二つが合成されたものを実現する為にはどの様な方法があるのでしょうか?宜しくお願い致します.

追記 LateUpdate()を試した際の挙動

ところで,以前UnityのSetIKPositionWeight()…等の関数によるIK機能をスクリプトにて試した時には,アニメーターコントローラーによる既存のアニメーションとミックスされた結果となりました.この点について調べて見ると,

処理順番は、Update()関数⇒Animation再生⇒BoneLocalRotation()関数⇒IK処理⇒LateUpdate()関数となっており…

  1. との事でしたから,順序が先なので上書きされてしまったのだろうと思い,試しに先ほどの腕回転スクリプトをUpdate()ではなくLateUpdate()内に記述してみましたが,やはり反映されませんでした. 継続的に指定単位量ずつ回り続ける最初の1フレーム分のみ回った状態でスタートして,それ以降変化なしでした.

  2. しかし,LookAt関数で向きを変更しようとする時,実行中にターゲットオブジェクトを移動させると正しく継続的に反映されました.

以下のサイトではアニメーション中のLookAtを試していますが,これはUpdate()中に書くと上手く行かないのでLateUpdate()に書こう,と述べられていました.
Unity でアニメーションさせながらスクリプトでモデルを動かす

C#

1using UnityEngine; 2 3public class Bones : MonoBehaviour 4{ 5 [SerializeField] Animator _animator; 6 [SerializeField] GameObject _target; 7 Transform arm; 8 9 void LateUpdate() 10 { 11 arm=_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm); 12 arm.Rotate(new Vector3(90,0,0)); //90度回った状態でスタートしてそれ以降変化なし(最初の1フレーム分しか機能していない?) 13 arm.LookAt(_target.transform);//こちらは実行中に_targetオブジェクトを移動させると正しく機能する 14 } 15} 16

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

Unity 2020.3.0f1(LTS)

potetiniku👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

自己解決しました.

  • AnimatorによるアニメーションはUpdate()後に処理されるので,上書きされない為にLateUpdate()を利用する必要があるというのは正しい
  • 問題は,Animatorは毎フレーム,そのアニメーション処理を行う際に最初にオブジェクトを初期状態の姿勢にリセットしている

参照:【Unity】Animatorで動かすオブジェクトをスクリプトでも動かす際の注意

Mecanimの場合は面倒くさいことに、AnimationControllerの中にrotationもしくはpositionを動かしているカーブが含まれている場合、今回作成したColorのような「回転処理を設定していないアニメーション」に対しても「初期値に戻すアニメーション」を設定するみたいです。

その為,追記で述べた「LateUpdate()での変形処理が最初の1フレームしか実行されていない」様に見えたのは,LateUpdate()前に初期位置に戻された状態からAnimator処理を行っているので,毎回処理はされているが,前フレームでの回転分が失われる為に変化が1フレーム分しか無いように見えていたのだと思われます.

(また,LookAtの場合は問題無く実行されていたのは,Rotateは現在の回転状態を起点としてあとどれだけ動かすのかという処理であるのに対して,LookAtは現在の状態に関係なくターゲットオブジェクトを見る方向を新たに代入する処理である為でしょう.)

なので,上記のサイトを参考に,スタート時点からの累積回転量を記憶しておく様にする事で解決しました.

C#

1using UnityEngine; 2 3public class Bones : MonoBehaviour 4{ 5 [SerializeField] Animator _animator; 6 7 Transform arm; 8 Quaternion r;//スタート時点からの累積回転量 9 10 void Start() 11 { 12 arm=_animator.GetBoneTransform(HumanBodyBones.LeftUpperArm); 13 r= Quaternion.identity; 14 } 15 void LateUpdate() 16 { 17 r = r* Quaternion.AngleAxis (3.14f, new Vector3(1.0f,0,0)); 18 arm.rotation =arm.rotation* r; 19 } 20}

投稿2021/03/17 02:04

編集2021/03/17 06:38
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問