Quaternion lookRotation - вверх не работает - PullRequest
1 голос
/ 20 мая 2019

Я пытаюсь заставить птицу вращаться немного «реалистично», то есть вектор вверх должен указывать на угол поворота, я имею в виду, если вы поворачиваете на 90 ° вправо, вектор вверх должен теперь указывать на вектор-вектор.вперед (тот, который у вас был до поворота).

Я пытался с помощью функции, но она только иногда вращается, остальное, он просто перезаписывает vector.up, как если бы он был 0,1,0.

using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;

 public class SmoothPath : MonoBehaviour {

     [System.Serializable]
     public class TrackingSettings
     {
         [HideInInspector]
         public int currentPoint = 0;
         [HideInInspector]
         public int nextPoint = 1;
         public int pathToFollow = 0;
         public GameObject affectedObject;
         public float speed = 10;
         public float rotationSpeed = 12;
         [HideInInspector]
         public Quaternion lastRotation;
         [HideInInspector]
         public Vector3 lastLocation;
     }

     [System.Serializable]
     public class PathsToFollow
     {
         public GameObject pathReference;
         public Transform[] pathPoints;
     }

     public TrackingSettings[] objectsToTrack;
     private TrackingSettings tempObjectToTrack;
     private float timer = 0;

     public PathsToFollow[] pathsToFollow;

     private Quaternion lookRotation;
     private Transform currentNode;
     private Transform nextNode;
     private float distance;

     // Use this for initialization
     void Start()
     {
         foreach (TrackingSettings ts in objectsToTrack)
         {
             ts.currentPoint = 0;
             ts.nextPoint = 1;
             ts.affectedObject.transform.position = pathsToFollow[ts.pathToFollow].pathPoints[0].position;
             ts.lastRotation = ts.affectedObject.transform.rotation;
             ts.lastLocation = ts.affectedObject.transform.position;
             lookRotation = Quaternion.LookRotation(pathsToFollow[ts.pathToFollow].pathPoints[1].position - pathsToFollow[ts.pathToFollow].pathPoints[0].position);
             ts.affectedObject.transform.rotation = lookRotation;

             currentNode = pathsToFollow[ts.pathToFollow].pathPoints[ts.currentPoint];
             nextNode = pathsToFollow[ts.pathToFollow].pathPoints[ts.nextPoint];

             distance = Vector3.Distance(currentNode.position, nextNode.position);
         }
     }

     // Update is called once per frame
     void Update () {
         timer += Time.deltaTime;
         for (int i = 0; i < objectsToTrack.Length; i++)
         {
             tempObjectToTrack = objectsToTrack[i];

             if (Vector3.Distance(tempObjectToTrack.affectedObject.transform.position, nextNode.position) < 0.3f)
             {

                 tempObjectToTrack.currentPoint = tempObjectToTrack.nextPoint;
                 tempObjectToTrack.nextPoint++;
                 //reset if overflow
                 if (tempObjectToTrack.nextPoint == pathsToFollow[tempObjectToTrack.pathToFollow].pathPoints.Length) tempObjectToTrack.nextPoint = 0;

                 timer = 0;

                 //lastNode = pathsToFollow[tempObjectToTrack.pathToFollow].pathPoints[tempObjectToTrack.lastPoint];
                 currentNode = pathsToFollow[tempObjectToTrack.pathToFollow].pathPoints[tempObjectToTrack.currentPoint];
                 nextNode = pathsToFollow[tempObjectToTrack.pathToFollow].pathPoints[tempObjectToTrack.nextPoint];

                 distance = Vector3.Distance(currentNode.position, nextNode.position);

                 float angle = GetAngle(tempObjectToTrack.affectedObject.transform.forward, Vector3.Normalize(nextNode.position - currentNode.position));

                 //set last rotation and location
                 tempObjectToTrack.lastRotation = tempObjectToTrack.affectedObject.transform.localRotation; 
                 tempObjectToTrack.lastLocation = tempObjectToTrack.affectedObject.transform.position;

                 tempObjectToTrack.affectedObject.transform.up = new Vector3(angle / 2, 45, 0);
                 lookRotation = Quaternion.LookRotation(nextNode.position - tempObjectToTrack.affectedObject.transform.position, new Vector3(angle / 2, 45, 0));
                 Debug.Log("Up: " + new Vector3(angle / 2, 45, 0) + " - angle: " + angle);
                 //tempObjectToTrack.affectedObject.transform.localRotation = lookRotation;
             }

             tempObjectToTrack.affectedObject.transform.position = Vector3.SlerpUnclamped(tempObjectToTrack.lastLocation, nextNode.position, timer / distance * tempObjectToTrack.speed);

             tempObjectToTrack.affectedObject.transform.rotation = Quaternion.Slerp (tempObjectToTrack.lastRotation, lookRotation, timer / distance * tempObjectToTrack.rotationSpeed);


         }


     }

     private float GetAngle(Vector3 a, Vector3 b)
     {
         b.y = 0;
         a.y = 0;
         float angle = Vector3.Angle(a, b);
         float sign = Mathf.Sign(Vector3.Dot(Vector3.up, Vector3.Cross(a, b)));

         return angle * sign;
     }
 }

на круговой траектории (4 или более точек в квадрате / раунд), птица иногда указывает правильно, а некоторые другие - нет

1 Ответ

1 голос
/ 20 мая 2019

Я бы не использовал LookRotation для этого, потому что вы не знаете направления, в котором вы хотите, чтобы местный up был прямым. Вот альтернатива, использующая угол непосредственно, чтобы изменить крен:

Сначала мы фиксируем результат GetAngle до + / - 90f.

float angle = GetAngle(tempObjectToTrack.affectedObject.transform.forward, Vector3.Normalize(nextNode.position - currentNode.position));
angle  = Mathf.Clamp(angle,-90f,90f);

Затем мы сталкиваемся с объектом, смотрящим на следующую цель, с локальным up, являющимся глобальным up, затем поворачиваем его на эту величину, умножая его на вращающееся вращение:

lookRotation = Quaternion.LookRotation(nextNode.position - tempObjectToTrack.affectedObject.transform.position, Vector3.up);

// If the direction of roll isn't right, try `-1 * angle` here:

lookRotation = lookRotation * Quaternion.AngleAxis(angle, Vector3.forward);

Затем присвойте Slerp ed lookRotation rotation:

tempObjectToTrack.affectedObject.transform.rotation = Quaternion.Slerp (tempObjectToTrack.lastRotation, lookRotation, timer / distance * tempObjectToTrack.rotationSpeed);
...