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

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

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

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

Unity3D

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

Q&A

解決済

1回答

2007閲覧

ねじれの回転のみ、子への影響量が違う処理について相談です

maniaiidx

総合スコア12

C#

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

Unity3D

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

0グッド

0クリップ

投稿2018/09/13 04:40

編集2018/09/13 04:45

お世話になっております。

Unityでの特殊な回転処理についての相談です。
「親の回転の ねじれ回転のみ、子への影響量が違う」
動きの処理を目指しています。

動画を用意致しました。
https://www.youtube.com/watch?v=NvgO_CuBkYs
左から順に
赤親 子A 子B  子Cと並んでいます。

子Aは、ねじれの影響を全量相殺する
子Bは、ねじれの影響を半分量だけ受ける
子Cは、ただの子で、何も影響を受けていません。

というものです。
(C#スクリプトで、それぞれのQuaternion回転量を参照、計算して処理しています)

動画の0:34までは望んだ動きができています。

ですが、
0:36から先では、
ねじれ軸(X軸)以外の回転操作の結果
子がねじれてしまっている『様に』見えてしまいます。

これは、親のねじれ回転量を参照して計算しているので
当然の動きであることは理解しております。
(動画の最後の状態では、結果子Aは全量相殺、子Bは半分量 という結果になっていますので)

ここからが本題なのですが

これをあたかも、ねじれの回転のみ影響を受けている
様に動く処理を作りたいのです。

言葉で説明するのが難しくて申し訳ないのですが
動画でいいますと、"X軸操作"でのねじれ回転のみ影響量を変えたい感じです。
人間の肩→腕→手の回転の様な動きを目指しています。

こちらの動画の0:22~0:39の様な動きが理想です。
https://www.youtube.com/watch?v=B00PYvrhgeA

煩雑な相談で恐縮です。
もし何か良い方法をご存知の方いらっしゃいましたら
よろしくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

おっしゃることは何となくイメージできるのですが、意図を取り違えている部分もあるかもしれませんので、適宜カスタマイズしてみてください...

あるフレームから次のフレームにかけてルートオブジェクトが回転した時、その回転軸ベクトルをねじれ軸...つまり腕の軸に射影してやれば、そのルートオブジェクトの回転のうちどれだけがねじれ軸周り回転成分であるか分かるのではないでしょうか?

こんなスクリプトをルートオブジェクトにアタッチし、インスペクタでSegmentsに3つの子オブジェクトをセット、それぞれのねじれ解消率を1、0.5、0にして...

C#

1using System; 2using UnityEngine; 3#if UNITY_EDITOR 4using UnityEditor; 5#endif 6 7[ExecuteInEditMode] 8public class CounterTwister : MonoBehaviour 9{ 10 public Segment[] Segments; 11 private Quaternion previousRotation; 12 private Quaternion[] currentSegmentRotations = new Quaternion[0]; 13 14 private void OnEnable() 15 { 16 this.previousRotation = this.transform.rotation; 17 } 18 19 private void Update() 20 { 21 var rootTransform = this.transform; 22 var currentRotation = rootTransform.rotation; 23 24 // 前のフレームとのルートオブジェクトの回転差分を求める 25 var deltaRotation = currentRotation * Quaternion.Inverse(this.previousRotation); 26 float deltaRotationAngle; 27 Vector3 deltaRotationAxis; 28 deltaRotation.ToAngleAxis(out deltaRotationAngle, out deltaRotationAxis); 29 30 // 回転量が0なら何もする必要はない 31 if (deltaRotationAngle == 0.0f) 32 { 33 return; 34 } 35 36 var segmentCount = this.Segments.Length; 37 if (this.currentSegmentRotations.Length < segmentCount) 38 { 39 Array.Resize(ref this.currentSegmentRotations, segmentCount); 40 } 41 42 // 今回は各セグメントが親子関係を作っているので、ねじれを解消する過程で 43 // セグメントを回転させると、他のセグメントも回転してしまう 44 // そこで、ねじれ解消に入る前に各セグメントの現在の回転を覚えておく 45 for (var i = 0; i < segmentCount; i++) 46 { 47 var segmentTransform = this.Segments[i].Transform; 48 if (segmentTransform != null) 49 { 50 this.currentSegmentRotations[i] = segmentTransform.rotation; 51 } 52 } 53 54 // ねじれ解消処理を行う 55 // Segmentsを0から順番に操作していますので、Segmentsには親子関係がルートに近いセグメントほど 56 // 若い番号になるようTransformをセットしてください 57 // さもないと、せっかく設定した子の回転が親の回転設定時に崩れてしまうかもしれません 58 for (var i = 0; i < segmentCount; i++) 59 { 60 var segment = this.Segments[i]; 61 var segmentTransform = segment.Transform; 62 var weight = segment.Weight; 63 64 // セグメントが未設定なら何もする必要はない 65 if (segmentTransform == null) 66 { 67 continue; 68 } 69 70 // ねじれを抽出する軸...さしあたりルートに対するセグメントの相対位置の方角としました 71 var axis = (segmentTransform.position - rootTransform.position).normalized; 72 73 // ルートの差分回転のうち、セグメントのねじれに寄与する成分の割合を求める 74 var twistFactor = Vector3.Dot(deltaRotationAxis, axis); 75 76 // ねじれ軸周りの逆回転を作成する 77 // 回転角にセグメントごとに決めたWeightを掛け、Weightが1に近いほどねじれが解消されるようにする 78 var counterTwist = Quaternion.AngleAxis(-deltaRotationAngle * twistFactor * weight, axis); 79 80 // セグメントに回転を適用する 81 segmentTransform.rotation = counterTwist * this.currentSegmentRotations[i]; 82 } 83 84 this.previousRotation = currentRotation; 85 } 86 87 [Serializable] 88 public struct Segment 89 { 90 public Transform Transform; 91 [Range(0.0f, 1.0f)] public float Weight; 92 } 93 94 // おまけ機能...インスペクタにセグメントのlocalRotationを無回転にするボタンを追加する 95 // 差分回転からねじれ成分のみ抽出してセグメント回転を調整するようにした都合上、ルートの回転を無回転に戻しても 96 // セグメントの回転が元に戻るとは限らなくなりました 97 // いちいちセグメントを選択して戻すのが面倒でしたので、一括設定するボタンを設けました 98#if UNITY_EDITOR 99 [CustomEditor(typeof(CounterTwister))] 100 public class CounterTwisterEditor : Editor 101 { 102 public override void OnInspectorGUI() 103 { 104 if (GUILayout.Button("Set Segment Local Rotations to Zero")) 105 { 106 var counterTwister = target as CounterTwister; 107 108 foreach (var segment in counterTwister.Segments) 109 { 110 var segmentTransform = segment.Transform; 111 if (segmentTransform != null) 112 { 113 segmentTransform.localRotation = Quaternion.identity; 114 } 115 } 116 } 117 118 this.DrawDefaultInspector(); 119 } 120 } 121#endif 122}

シーンビューで操作してみると、下図のように腕を振る動きではねじれ解消回転が発生せず、腕をねじる動きをした時にはねじれ解消回転が起こるようになりました。

プレビュー

投稿2018/09/13 20:16

Bongo

総合スコア10807

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

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

maniaiidx

2018/09/14 04:43

Bongoさん ありがとうございます。 前回の質問に引き続き、詳細かつ丁寧なコードと解説 感謝しております。 そしてまさにツイスト軸操作の回転のみ影響を受ける状態の ご提供ありがとうございました。 大変勉強になります。 そして申し訳ありません、 Bongoさんに頂いたコードはまさに自分が質問した通りの処理でしたが 回転について自分の中でもまだまだ理解が浅く混乱が多く、 求めている結果が自分でも認識できていませんでした。 私のミスです。 腕の動画の例で言いますと 腕の回転を戻した場合、動画のように元に戻るような イメージでいました。 が、確かに回転状況をリアルタイムで変更する必要があるので 元に戻らないのが正解で、戻るというイメージ自体が間違いでした。 この後は、まず"元"(ベストな回転状態)というものをはっきりとさせて 頂きましたコードを参考に、 自動でその回転状態に戻る、 腕のように動くような処理を加えられないか考えてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問