Unity3D - C# 360 轨道相机控制器(云台锁定问题)



我的场景中有一个固定的立方体,我正在绕着摄像机转。我的主摄像机嵌套在我称之为"轨道摄像机"的游戏对象下。

我设置了脚本,以便单击(或点击(和拖动将围绕空间中的对象旋转相机,因此感觉就像您在旋转立方体(即:如果我单击立方体上的面部顶部并向下拉,我正在旋转 X 值(,但您实际上是在旋转相机。

在大多数情况下,我的脚本有效。然而,在旋转Y这么多之后,相机是颠倒的,X被颠倒了。这是我的脚本:

public class OrbitalCamera : MonoBehaviour {
    public bool cameraEnabled;
    [SerializeField] private float touchSensitivity;
    [SerializeField] private float scrollSensitivity;
    [SerializeField] private float orbitDampening;
    protected Transform xFormCamera;
    protected Transform xFormParent;
    protected Vector3 localRotation;
    protected float cameraDistance;
    void Start () {
        cameraEnabled = true;
        xFormCamera = transform;
        xFormParent = transform.parent;
        cameraDistance = transform.position.z * -1;
    }
    void LateUpdate () {
    if (cameraEnabled) {
            // TODO:: FIX PROBLEM WHERE WHEN CAMERA IS ROTATED TO BE UPSIDEDOWN, CONTROLS GET INVERSED
            if (Input.GetMouseButton(0)) {
                if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0) {
                    localRotation.x += Input.GetAxis("Mouse X") * touchSensitivity;
                    localRotation.y -= Input.GetAxis("Mouse Y") * touchSensitivity;
                }
            }
        }
        Quaternion qt = Quaternion.Euler(localRotation.y, localRotation.x, 0);
        xFormParent.rotation = Quaternion.Lerp(xFormParent.rotation, qt, Time.deltaTime * orbitDampening);
    }
}

有没有实现这种360度相机的好方法?我想从右向左拖动以始终向左移动相机,从左拖动到右拖动以始终向右移动相机 - 无论相机如何定向。

也许您可以将上方/下方的平底锅夹在 89 度?

我最近帮一个朋友做了一个鼠标云台,发现允许超过89度的自由度是有问题的,也是不必要的。看起来您的应用程序是相同的,至少对于两个平面中的一个。

在 LateUpdate(( 调用中,您可以添加:

localRotation.x += Input.GetAxis("Mouse X") * touchSensitivity;
localRotation.x = Clamp(localRotation.x);

然后,当然,创建您的钳位函数,这应该相当简单:

float Clamp(float val) // prevent values from ~90 - ~270
{
   int lowVal = 89;
   int highVal = 271;
   int midVal = 180;
   if (val > lowVal & val < highVal)
   {
      if (val > midVal) val = highVal;
      else val = lowVal;
   }
return val;
}

一个略有不同的应用程序,但我相信您可以看到我是如何设置的:我分两步应用旋转。步骤 1 - 一个简单的 Rotate(( 调用, 步骤 2 - 夹紧部分/全部旋转:

using UnityEngine;
public class MouseGimbal : MonoBehaviour
{
   [SerializeField] [Range(0,89)] float maxRotationDegrees = 10.0f; // At 90+ gimbal oddities must be dealt with.
   [SerializeField] bool ClampToMaxRotationDegrees = true; // Disable for free rotation.
   [SerializeField] float rotationSpeed = 10.0f;
   const float fullArc = 360.0f;
   const float halfArc = 180.0f;
   const float nullArc = 0.0f;
   void Update () { Tilt(); }
   void Tilt()
   {
      // Apply the 'pre-clamp' rotation (rotation-Z and rotation-X from X & Y of mouse, respectively).
      if (maxRotationDegrees > 0) { SimpleRotation(GetMouseInput()); }
      // Clamp rotation to maxRotationDegrees.
      if (ClampToMaxRotationDegrees) { ClampRotation(transform.rotation.eulerAngles); }
   }
   void ClampRotation(Vector3 tempEulers)
   {
      tempEulers.x = ClampPlane(tempEulers.x);
      tempEulers.z = ClampPlane(tempEulers.z);
      tempEulers.y = nullArc; // ClampPlane(tempEulers.y); // *See GIST note below...
      transform.rotation = Quaternion.Euler(tempEulers);
      ///Debug.Log(tempEulers);
   }
   float ClampPlane(float plane)
   {
      if (OkayLow(plane) || OkayHigh(plane)) DoNothing(); // Plane 'in range'.
      else if (BadLow(plane)) plane = Mathf.Clamp(plane, nullArc, maxRotationDegrees);
      else if (BadHigh(plane)) plane = Mathf.Clamp(plane, fullArc - maxRotationDegrees, fullArc);
      else Debug.LogWarning("WARN: invalid plane condition");
      return plane;
   }
   Vector2 GetMouseInput()
   {
      Vector2 mouseXY;
      mouseXY.x = -Input.GetAxis("Mouse X"); // MouseX -> rotZ.
      mouseXY.y = Input.GetAxis("Mouse Y"); // MouseY -> rotX.
      return mouseXY;
   }
   void SimpleRotation(Vector2 mouseXY)
   {
      Vector3 rotation = Vector3.zero;
      rotation.x = mouseXY.y * Time.deltaTime * rotationSpeed;
      rotation.z = mouseXY.x * Time.deltaTime * rotationSpeed;
      transform.Rotate(rotation, Space.Self); 
   }
   void DoNothing()           {   }
   bool OkayHigh(float test)  { return (test >= fullArc - maxRotationDegrees && test <= fullArc); }
   bool OkayLow(float test)   { return (test >= nullArc && test <= maxRotationDegrees); }
   bool BadHigh(float test)   { return (test > halfArc && !OkayHigh(test)); }
   bool BadLow(float test)    { return (test < halfArc && !OkayLow(test)); }
}

当我开发轨道相机时,我创建了 3 个对象:

- x_axis (rotate with vertical mouse moviment)
    - y_axis (rotate with horizontal mouse moviment)
        - camera (look_at object) (translated Vector3(0,0,-10))

最新更新