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

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

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

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

Unity3D

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

Unity

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

Q&A

解決済

1回答

3079閲覧

LookAt中Z軸周りを回転できるようにしたい

lamp

総合スコア41

C#

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

Unity3D

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

Unity

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

0グッド

0クリップ

投稿2019/01/03 15:16

transform.LookAt 命令を使うと
引数が二つ、
・Z軸(Forward)を向ける位置
・上方向(デフォルトでVector3.up)が必要になります。

 やりたいことは、Z軸を指定位置に向けて、更にZ軸周りに回転させるという
2種類の回転を行うことです。

LookAtを使うと上方向がロックされtransform.Rotateが効きません。、他に方法があったら教えてほしいです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

RotateでZ周りに回してからLookAtで目標方向に向けても、上方向がそろえられてしまい、最初のRotateによる回転が効いていない...という状況でしょうか?

対策案として思いついたのは...

  • 案1...LookAtを行う前に「上方向がどれだけずれているか」を表す差分回転を求めておいて、LookAt後にそれを再適用する。
  • 案2...LookAtの代わりに、Quaternion.FromToRotationで求めた回転を適用して回転させる。

下記のようなコードで各方法を比較してみました。
modeを切り替えると動作が変化し、LookAtで対策を行わず、KeepZで案1、FromToRotationで案2となります。
なお、比較のために最初のRotateと次の向き合わせの間に待機時間を設けていますが、実際の使用時にはRotateと向き合わせを連続して行えばいいでしょう。

C#

1using System; 2using System.Collections; 3using UnityEngine; 4 5public class RotateAndLookAt : MonoBehaviour 6{ 7 public enum Mode 8 { 9 LookAt, 10 KeepZ, 11 FromToRotation 12 } 13 14 [SerializeField] private Mode mode; 15 [SerializeField] private Vector3 lookAt; 16 [SerializeField] private float rotateZAngle; 17 18 private IEnumerator Start() 19 { 20 var wait = new WaitForSeconds(1.0f); 21 yield return wait; 22 23 // RotateでZ周りに回した後... 24 this.transform.Rotate(0.0f, 0.0f, this.rotateZAngle); 25 yield return wait; 26 27 switch (this.mode) 28 { 29 case Mode.LookAt: 30 // LookAtだと、いくらRotateで回してもLookAt後にはY軸が上方向にそろえられてしまいます 31 this.transform.LookAt(this.lookAt); 32 break; 33 case Mode.KeepZ: 34 // 対策案1...差分回転を保存しておく方法 35 this.LookAtKeepZ(this.lookAt); 36 break; 37 case Mode.FromToRotation: 38 // 対策案2...目標方向への回転をFromToRotationで求める方法 39 this.LookAtFromToRotation(this.lookAt); 40 break; 41 default: 42 throw new ArgumentOutOfRangeException(); 43 } 44 } 45 46 private void LookAtKeepZ(Vector3 worldPosition) 47 { 48 // 仮にtransform.LookAt(transform.position + transform.forward)としたとすると 49 // forwardの向きはそのままに、上方向がそろえられた姿勢になると予想される 50 // 「現在の姿勢」と、その「上方向がそろえられた姿勢」の差分回転を調べておいて... 51 var rotationAroundZ = this.transform.rotation * Quaternion.Inverse(Quaternion.LookRotation(this.transform.forward)); 52 53 // LookAtで目標方向に向ける 54 // この時点では、forwardは目標方向を向いているが、上方向がそろえられてしまっているはず 55 this.transform.LookAt(worldPosition); 56 57 // そこでさらに先ほど調べた差分回転を適用し、上方向を元通りに直す 58 this.transform.rotation *= rotationAroundZ; 59 } 60 61 private void LookAtFromToRotation(Vector3 worldPosition) 62 { 63 // forwardを目標方向に向ける最短回転を求めて... 64 var rotationFromForwardToDestination = Quaternion.FromToRotation( 65 this.transform.forward, 66 worldPosition - this.transform.position); 67 68 // それを現在の姿勢に適用する 69 this.transform.rotation = rotationFromForwardToDestination * this.transform.rotation; 70 } 71 72 private void OnDrawGizmos() 73 { 74 var p = this.transform.position; 75 Debug.DrawRay(p, this.transform.right, Color.red); 76 Debug.DrawRay(p, this.transform.up, Color.green); 77 Debug.DrawRay(p, this.transform.forward, Color.blue); 78 } 79}

回転結果を比較すると下図のようになりました。
7人のユニティちゃんをZ軸周りにそれぞれ-90°、-60°、-30°、0°、30°、60°、90°回転した後、自分自身に対して(1, 1, 1)の方角に回転(Vector3.one + transform.positionを見るように回転)させたものです。

結果

下2つが対策ありの結果ですが、おそらく案2(FromToRotation)よりも案1(KeepZ)の方が適しているのではないかと思います。

ぱっと見たところでは違いがないように感じられるかもしれませんが、左右端のユニティちゃん(RotateでZ周り-90°、および90°回転)や中央(Rotateでは無回転)を比べていただきますと、案2では微妙に左に傾いてしまっているのがお分かりいただけるでしょうか?

一方、案1では中央のユニティちゃんは無対策の場合と同じ姿勢になり、左右端のユニティちゃんは体の軸を中心にちょうど半分が地面に埋まっています。
案1だと「モデルをあらかじめ回転する」→「モデルを空のオブジェクトの子にする」→「親オブジェクトをLookAtで回転する」とした場合と同等の見た目になるはずです。

投稿2019/01/04 00:00

Bongo

総合スコア10816

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

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

lamp

2019/01/04 07:09

すごく詳しく教えていただいて大変ありがとうございます。 LookAtKeepZ、使わせてもらいます。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問