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

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

新規登録して質問してみよう
ただいま回答率
85.46%
Unity3D

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

Unity

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

Q&A

1回答

941閲覧

Unityでモーションデータの関節ごとに、変形を制御できるようにしたい

szm.

総合スコア7

Unity3D

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

Unity

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

0グッド

0クリップ

投稿2021/09/19 10:59

編集2021/09/20 08:58

前提・実現したいこと

Unity初心者になります。初めての質問失礼いたします。

3Dモデルのモーションデータをデフォルメし、制御することを可能にするためのアプリケーションを開発しています。

現在はモーションを制御する際に全ての関節角度やスピードに変形を加えているのですが、関節ごとに変形を制御できるようにしたいと思っております。

ex)モーションデータにおける、
右肘の角度の大きさ1.5, 右肩の角度の大きさ1.2

のように、それぞれ独立して制御を可能にしたいと思っています。

試したこと

モーションデータのの全ての関節角度、モーションスピードを変数で変形させました。

実際のコード

このように変数に応じて、モーションの全関節角度の大きさと

using System.Collections; using System.Collections.Generic; using UnityEngine; namespace AmplifyAnimation { [RequireComponent(typeof(Animator))] public class MotionDSfin : MonoBehaviour { public bool applyRootMotion = true; [Range(0.7f, 1.3f)] public float amplitude = 1.0f; private Animator animator; private HumanPoseHandler poseHandler; private HumanPose pose; private Vector3 rootPosition; private Quaternion rootRotation; private float[] initialMuscles; private void Awake() { this.animator = this.GetComponent<Animator>(); // ポーズを取得・操作するためのハンドラーを取得する this.poseHandler = new HumanPoseHandler(this.animator.avatar, this.transform); // 初期状態でのマッスル値を覚えておき、これを基準の姿勢とする var t = this.transform; this.rootPosition = t.position; this.rootRotation = t.rotation; t.SetPositionAndRotation(Vector3.zero, Quaternion.identity); this.poseHandler.GetHumanPose(ref this.pose); t.SetPositionAndRotation(this.rootPosition, this.rootRotation); this.initialMuscles = this.pose.muscles.Clone() as float[]; } private void OnAnimatorMove() { var t = this.transform; this.rootPosition = t.position; this.rootRotation = t.rotation; if (!this.applyRootMotion) { return; } // もしルートモーションの適用が必要なら、このタイミングで処理しておく // このとき、動く量をamplitudeに応じて増減させる amplitude = 1.0f + IFMScaredD.getFavsd() / 3; var deltaPosition = Vector3.LerpUnclamped( Vector3.zero, this.animator.deltaPosition, this.amplitude); var deltaRotation = Quaternion.SlerpUnclamped( Quaternion.identity, this.animator.deltaRotation, this.amplitude); this.rootPosition += deltaPosition; this.rootRotation = deltaRotation * this.rootRotation; } private void LateUpdate() { var t = this.transform; // Animatorが設定した現在のポーズを取得し... t.SetPositionAndRotation(Vector3.zero, Quaternion.identity); this.poseHandler.GetHumanPose(ref this.pose); t.SetPositionAndRotation(this.rootPosition, this.rootRotation); // 初期ポーズとの差分をamplitudeに応じて増幅して... amplitude = 1.0f + IFMScaredD.getFavsd() / 2; var muscles = this.pose.muscles; for (var i = 0; i < muscles.Length; i++) { muscles[i] = Mathf.LerpUnclamped(this.initialMuscles[i], muscles[i], this.amplitude); } // 修正したポーズを適用する this.poseHandler.SetHumanPose(ref this.pose); } } }

追記:
モーションのスピードに関してのコードが抜けていたので追記させていただきます。

using System.Collections; using System.Collections.Generic; using UnityEngine; public class motionSpeedSD: MonoBehaviour { public float speed; Animator m_Animator; // Start is called before the first frame update void Start() { m_Animator = gameObject.GetComponent<Animator>(); } // Update is called once per frame void Update() { m_Animator.speed = 1.0f + IFMScaredD.getFavsd() / 2; } }

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

Unityのバージョン:2019.4.3f1
使用しているスクリプト:fungus
3Dモデル:ユニティちゃん

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

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

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

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

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

guest

回答1

0

これは単に、スクリプトの下記部分で...

lang

1 for (var i = 0; i < muscles.Length; i++) 2 { 3 muscles[i] = Mathf.LerpUnclamped(this.initialMuscles[i], muscles[i], this.amplitude); 4 }

個々のマッスルにそれぞれ適切な値をセットしてやればいいかと思います。
各マッスルの名称はHumanTrait.MuscleNameを使って調べられるでしょう。

たとえば下記のような形にしてみてはいかがでしょうか。なお、ご提示いただいたコードではIFMScaredDという名称の型から設定値を取得しているようでしたが、これは詳細が不明だったためコメントアウトしています。あくまでもご参考までの一例ということで、実際にはご質問者さんのプログラムに合わせて自由に改変してしまってください。

lang

1using System; 2using System.Linq; 3using UnityEngine; 4 5namespace AmplifyAnimation 6{ 7 [RequireComponent(typeof(Animator))] 8 public class MotionDSfin : MonoBehaviour 9 { 10 public bool applyRootMotion = true; 11 12 // amplitudeをルートモーション移動用、回転用、マッスル用に分ける 13 [Range(0.7f, 1.3f)] public float rootPositionAmplitude = 1.0f; 14 [Range(0.7f, 1.3f)] public float rootRotationAmplitude = 1.0f; 15 public MuscleAmplitude[] muscleAmplitudes; 16 17 private Animator animator; 18 private float[] initialMuscles; 19 private HumanPose pose; 20 private HumanPoseHandler poseHandler; 21 private Vector3 rootPosition; 22 private Quaternion rootRotation; 23 24 // マッスル用Amplitudeは単にfloatの配列であってもいいのですが、インスペクター上で 25 // どの部位に該当するか判断しやすくする目的で、下記のような構造体にしました 26 // ただし、これだけだとインスペクター上で配列の要素数や順番、nameを 27 // 書き換えることができてしまい、それをやられるとインスペクター上の設定と 28 // マッスルの対応が狂ってしまいます(インスペクター上で「Reset」を行えば、 29 // 一応初期状態に戻すことはできます) 30 // それを防止するには、独自のEditorを作ってインスペクターの表示を 31 // カスタマイズしてやる必要があるかと思います 32 [Serializable] 33 public struct MuscleAmplitude 34 { 35 public string name; 36 [Range(0.7f, 1.3f)] public float value; 37 } 38 39 private void Reset() 40 { 41 this.muscleAmplitudes = HumanTrait.MuscleName.Select(name => new MuscleAmplitude { name = name, value = 1.0f }).ToArray(); 42 } 43 44 private void Awake() 45 { 46 this.animator = this.GetComponent<Animator>(); 47 48 // ポーズを取得・操作するためのハンドラーを取得する 49 this.poseHandler = new HumanPoseHandler(this.animator.avatar, this.transform); 50 51 // 初期状態でのマッスル値を覚えておき、これを基準の姿勢とする 52 var t = this.transform; 53 this.rootPosition = t.position; 54 this.rootRotation = t.rotation; 55 t.SetPositionAndRotation(Vector3.zero, Quaternion.identity); 56 this.poseHandler.GetHumanPose(ref this.pose); 57 t.SetPositionAndRotation(this.rootPosition, this.rootRotation); 58 this.initialMuscles = this.pose.muscles.Clone() as float[]; 59 } 60 61 private void OnAnimatorMove() 62 { 63 var t = this.transform; 64 this.rootPosition = t.position; 65 this.rootRotation = t.rotation; 66 if (!this.applyRootMotion) 67 { 68 return; 69 } 70 71 // もしルートモーションの適用が必要なら、このタイミングで処理しておく 72 // このとき、動く量をamplitudeに応じて増減させる 73 //amplitude = 1.0f + (IFMScaredD.getFavsd() / 3); 74 var deltaPosition = Vector3.LerpUnclamped( 75 Vector3.zero, 76 this.animator.deltaPosition, 77 this.rootPositionAmplitude); 78 var deltaRotation = Quaternion.SlerpUnclamped( 79 Quaternion.identity, 80 this.animator.deltaRotation, 81 this.rootRotationAmplitude); 82 this.rootPosition += deltaPosition; 83 this.rootRotation = deltaRotation * this.rootRotation; 84 } 85 86 private void LateUpdate() 87 { 88 var t = this.transform; 89 90 // Animatorが設定した現在のポーズを取得し... 91 t.SetPositionAndRotation(Vector3.zero, Quaternion.identity); 92 this.poseHandler.GetHumanPose(ref this.pose); 93 t.SetPositionAndRotation(this.rootPosition, this.rootRotation); 94 95 // 初期ポーズとの差分をamplitudeに応じて増幅して... 96 //amplitude = 1.0f + (IFMScaredD.getFavsd() / 2); 97 var muscles = this.pose.muscles; 98 for (var i = 0; i < muscles.Length; i++) 99 { 100 // ここで、i番目のマッスルにはi番目のAmplitudeを適用する 101 muscles[i] = Mathf.LerpUnclamped(this.initialMuscles[i], muscles[i], this.muscleAmplitudes[i].value); 102 } 103 104 // 修正したポーズを適用する 105 this.poseHandler.SetHumanPose(ref this.pose); 106 } 107 } 108}

投稿2021/09/19 19:49

Bongo

総合スコア10807

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問