简体   繁体   English

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

[英]Unity3D - C# 360 Orbital Camera Controller (Gimbal Lock Issue)

I have a stationary cube in my scene that I'm orbiting a camera around. 我的场景中有一个固定的立方体,正在绕着摄像机旋转。 I have my MainCamera nested under a GameObject that I'm calling 'OrbitalCamera'. 我的MainCamera嵌套在一个我称为“ OrbitalCamera”的GameObject下。

I setup the script so that a click (or tap) and drag will rotate the camera around the object in space so it feels like you're rotating the cube (ie: if I click the top of a face on the cube, and pull down, I'm rotating the X value) but you'll actually be rotating the camera. 我设置了脚本,以便单击(或点击)并拖动将使摄像机围绕空间中的对象旋转,从而感觉就像您正在旋转多维数据集(即:如果我单击多维数据集上一个面的顶部并拉动向下,我正在旋转X值),但实际上您将在旋转相机。

For the most part, my script works. 在大多数情况下,我的脚本有效。 However, after rotating the Y so much, the camera is upside down and the X gets inverted. 但是,将Y旋转太多后,相机将倒置,X会倒转。 Here's my script: 这是我的脚本:

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);
    }
}

Is there a good method to achieve this type of 360 camera? 有没有很好的方法来实现这种360度相机? I'd like dragging from right to left to always move the camera left and dragging left to right to always move the camera right -- no matter how the camera is oriented. 我想从右向左拖动以始终向左移动相机,而从左向右拖动以始终向右移动相机-无论相机的方向如何。

Perhaps you could clamp the above/below pan at 89 degrees? 也许您可以将上面/下面的锅夹在89度上?

I recently helped a friend make a mouse gimbal, and found allowing freedom beyond 89 degrees was problematic and unnecessary. 我最近帮助一位朋友制作了一个云台,发现允许超过89度的自由度是有问题且不必要的。 It seems like your application is the same, at least for one of the two planes. 看来您的应用程序是相同的,至少对于两个平面之一而言。

In your LateUpdate() call, you could perhaps add: 在您的LateUpdate()调用中,您可以添加:

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

Then, of course, create your clamp function, which should be fairly straight forward: 然后,当然,创建您的钳位函数,应该很简单:

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;
}

A slightly different application, but I'm sure you can see how I've set this up: I apply rotation in two steps. 稍有不同的应用程序,但是我敢肯定您可以看到我的设置方法:我分两步应用旋转。 Step 1 - a simple Rotate() call, Step 2 - clamping some/all of the rotation: 步骤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)); }
}

When I developed an orbital camera, I created 3 objects: 开发轨道相机时,我创建了3个对象:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM