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

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

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

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

Unity3D

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

Unity

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

Q&A

1回答

182閲覧

[Unity] Quaternionの1つの要素に倍率をかけたい

borscht

総合スコア0

C#

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

Unity3D

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

Unity

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

0グッド

0クリップ

投稿2025/01/05 04:25

編集2025/01/06 03:11

実現したいこと

RotationConstraintが使いづらかったので自作している中です。
やりたいこととしては、ソースのQuaternionの要素1つに対してウェイトをかけ、補正先に代入したいです。
また、いずれはすべての要素に別々の倍率をかけて値を代入したいです。

本来はRotationConstraintの動きを元に各軸事に倍率をかけられたらいいな~というところから来ています。
(1/6追記)
当初ジンバルロックの記事やUnityドキュメントを見ましてQuaternionは直接いじらないほうがよい、と書いてあったためオイラー角を使用しプログラムを組んでいました。
しかし、オブジェクトAが左回りで動くとき(インスペクター上ではマイナスの値になるとき)、-10度は350度として計算されてしまい、オブジェクトBが右回りで350度回ったことになってしまい、思った動きになりませんでした。(0~180度で計算されるので仕方のないことではありますが・・・)
SerializeObject化させオブジェクトAのインスペクター上の値をそのままオブジェクトBに使用する方法を取りましたが、再生時値が動かず思った動きになりませんでした。

「オブジェクトAの角度Xにウェイトをかけて、オブジェクトBに反映させる」をどの回転方向でも対応できるにはどのようにしたらよいでしょうか?

発生している問題・分からないこと

単純にウェイトをかけてそのままの値を入れてしまうと、ソースとなる角度が大きくなると段々誤差が大きくなり、正しい値を取ることができません。

例)オブジェクトAのXが90度のとき、Quaternionは(0.70711, 0, 0, 0.70711)。
オブジェクトAのXを0.5倍してオブジェクトBのXを45度にしたいので、0.70711 * 0.5 をする。
結果補正先オブジェクトBのQuaternionは(0.35355, 0, 0, 0.93541)になるが、インスペクター上で見ると41.41度となっている。

Quaternionの知識が浅いため単純に掛け算してしまっているので、知識として足りない部分があるかと思いますが、方法がございましたらご教授いただけますと幸いです。

該当のソースコード

C#

1 public class Param 2{ 3 public enum eAxis 4 { 5 X = 0, 6 Y = 1, 7 Z = 2 8 } 9 10 // 参照元 11 [SerializeField] private Transform m_Source; 12 public Transform Source { get { return m_Source; } } 13 [SerializeField] private eAxis m_SourceAxis; 14 public eAxis SourceAxis { get { return m_SourceAxis; } } 15 16 // 補正先の軸 17 [SerializeField] private eAxis m_TargetAxis; 18 public eAxis TargetAxis { get {return m_TargetAxis; } } 19 20 // ウェイト 21 [SerializeField, Range(0, 1.0f)] private float m_Weight; 22 public float Weight { get { return m_Weight; } } 23}

C#

1 // 参照元のQuaternionを取得 2 Quaternion sourceQuat = m_Param.Source.localRotation; 3 4 // 補正先のQuaternionを取得 5 Quaternion targetQuat = this.transform.localRotation; 6 7 8 // 参照する軸を判定 9 float sourceElement = 0.0f; 10 switch (m_Param.SourceAxis) 11 { 12 case Param.eAxis.X: 13 sourceElement = sourceQuat.x; 14 break; 15 16 case Param.eAxis.Y: 17 sourceElement = sourceQuat.y; 18 break; 19 20 case Param.eAxis.Z: 21 sourceElement = sourceQuat.z; 22 break; 23 } 24 25 // 指定した軸に対してWeightをかける 26 sourceElement *= m_Param.Weight; 27 28 // 補正先にいれる 29 switch (m_Param.TargetAxis) 30 { 31 case Param.eAxis.X: 32 targetQuat.x = sourceElement; 33 break; 34 35 case Param.eAxis.Y: 36 targetQuat.y = sourceElement; 37 break; 38 39 case Param.eAxis.Z: 40 targetQuat.z = sourceElement; 41 break; 42 } 43 this.transform.localRotation = targetQuat;

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

Rotationの値をSerializeObject化させインスペクター上の値をそのまま取ってくる方法を取りましたが、再生時値が動かず補正できませんでした。(アニメーションなどつけていたので他に原因はあるかもしれません)

補足

環境
Unity 6000.0.23f1

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

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

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

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

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

fiveHundred

2025/01/06 02:55

どこまで理解されているのかが分からないことと、私の技量的に完璧に実装することが難しそう(出来てもバグだらけになりそう)なので、基本的な情報だけ。 まず、基本的にはQuaternionの各値を直接いじることはしません。 これはUnity公式でも言及しています。 https://docs.unity3d.com/ja/2022.3/ScriptReference/Quaternion.html また、そもそもエディタ上に表示されているのは、Quaternionではなくオイラー角での値です。 これらはtransform.eulerAnglesなどで取得できます。 Quaternionからオイラー角にすることやその逆もできます。 ただ、そのままオイラー角の値を変更するだけだと、ジンバルロックたる問題が発生するので、その対処は必要です。 https://qiita.com/fullmated/items/ac62ebd1206a6487232d 忘れがちな点として、上記URLにもありますが、Quaternion同士の掛け算も可能です。 この場合、15度の回転のQuaternion * 30度の回転のQuaternion の場合は 45度の回転になります。 Quaternion * Vector3も可能です(この場合、回転したVector3になる)。
borscht

2025/01/06 03:14

ありがとうございます。 確かにこちら側がどこまで把握しているか記載がなかったですね。 実現したいことに追記いたしました。基本的な情報のご提供もありがとうございます。 右回りのときはオイラー角でできますが、左回りのときが問題なんですよね。 そもそも左回りだということがeulerAnglesからわかるものなんでしょうか?
fiveHundred

2025/01/06 03:51

そもそも、回転後の向きしか情報が無いのであれば、どちら周りなのかは分からないと思います。 (例えば、-90度回転と270度回転はどちらも結果は同じです)
fana

2025/01/06 05:13 編集

> 例)オブジェクトAのXが90度のとき、Quaternionは(0.70711, 0, 0, 0.70711)。 オブジェクトAのXを0.5倍してオブジェクトBのXを45度にしたいので、0.70711 * 0.5 をする。 ここのところが何言ってるのかよくわからないのですが,仮に「回転量」を半分にしたいという話なのであれば,「特定の要素を 0.5 倍する」という話になることはないでしょう. 回転量としてw成分を見る場合,たしか回転量θに対して w=cos(θ/2) なので,ココを改竄するとすれば cos(θ/4) にしてやる必要があると思いますし,w成分だけ改竄すればそれで済むのか?というとそんなことはなく,回転に用いるならば全体として「単位クォータニオン」にしてやる必要があるわけで,そこは誰がいつどうやってるんですかね?っていう話もありそうですし. [追記] > 結果補正先オブジェクトBのQuaternionは(0.35355, 0, 0, 0.93541)になるが、インスペクター上で見ると41.41度となっている。 41.41度というのは 0.93541 側に対する回転量θですね. つまり「回転量」をいじりたいという話ではなくて,もっと複雑な何かをしようとしている…という話? (0.93541 というのは,最初の要素を 0.5 倍した結果の副作用(誰かが単位化した結果)かな?) という感じで,なんというか, > Quaternionの要素1つに対してウェイトをかけ… …というのが何を実現したい話なのかわかりません. そういう操作をした結果として,回転具合(回転軸や回転量)の変化を想像するのはとても困難であろうと思いますが,何故そんなことをせねばならないのでしょう? (私は Unity を全く知らないのですが,何か Unity 固有の事情の話?)
guest

回答1

0

質問コメントでも指摘されているとおり、クォータニオンの認識が間違っています。
クォータニオンとオイラー角は全く別物ですし、 Quaternion の各メンバをいじらなくても、 Quaternion のメソッドを使えばたいてい事足ります。

RotationConstraint は使ったことはないのでよく知りませんが、「自身の回転」と「ターゲットの回転」を Quaternion.SlerpWeight で補間すれば実現できるのではないでしょうか。
「Freeze Rotation Axes」の設定は、「ターゲットの回転」を設定に合わせて調整すれば実現できそうだけど、ちょっと試してみないとわかりませんね。
とりあえずFreezeAxesのことは考えないで Quaternion.Slerp を使って試してみてはいかがですか。


追記: こんなスクリプトを書いたら、それっぽく動きましたよ。
(別のPCで動かしたので、書き直しているので間違っているかもしれないけど)

csharp

1using UnityEngine; 2 3public class TestScript : MonoBehaviour { 4 [SerializeField] private Transform target; 5 [SerializeField] private float weight; 6 private Quaternion baseRotation; 7 8 private void Start() 9 { 10 this.baseRotation = this.transform.rotation; 11 } 12 13 private void Update() 14 { 15 this.transform.rotation = Quaternion.Slerp(this.baseRotation, 16 this.target.transform.rotation, this.weight); 17 } 18}

投稿2025/01/08 00:10

編集2025/01/09 00:08
katsuko

総合スコア3554

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.34%

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

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

質問する

関連した質問