首页 文章

Unity3D - C#360轨道摄像机控制器(万向节锁定问题)

提问于
浏览
0

我的场景中有一个固定的立方体,我绕着相机转动 . 我将我的MainCamera嵌套在GameObject上,我称之为'OrbitalCamera' .

我设置了脚本,以便单击(或点击)并拖动将相机围绕空间中的对象旋转,这样就像是在旋转立方体(即:如果我单击立方体上的面的顶部,并拉动我正在旋转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相机?我想从右向左拖动以始终向左移动相机并从左向右拖动以始终向右移动相机 - 无论相机如何定向 .

2 回答

  • 0

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

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

    也许你可以将上/下盘夹在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)); }
    }
    

相关问题