创建类似于球形导航的Google Earth [英] Creating a Google Earth like navigation for a sphere

查看:82
本文介绍了创建类似于球形导航的Google Earth的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是关于Unity3D的. 我想创建一个类似于 Google Earth 的导航,在其中单击并拖动球体,并让摄影机相应地旋转.重要的是,拖动时始终将捕获的点置于鼠标位置下.如果我缩放接近球体,导航也应该起作用.我不想旋转球体本身.就像Google Earth一样.

This question is about Unity3D. I want to create a navigation similar to Google Earth where you click and drag on a sphere and let the camera orbit accordingly. It is important that the point that was grabbed is always under the mouse position while dragging. The navigation should also work if I zoom close to the sphere. I do not want to rotate the sphere itself. Just exactly like Google Earth does it.

如果尝试开始拖动,我的尝试是将鼠标位置投影到球体上.在下一帧中,我执行相同操作,并计算开始拖动和结束拖动位置之间的角度.

My attempt is to project the mouse position to the sphere if I start to drag. On the next frame I do the same and calculate the angle between the start drag and end drag position.

private void RotateCamera(Vector3 dragStart, Vector3 dragEnd)
{
    // calc the rotation of the drag
    float angle = Vector3.Angle(dragStart, dragEnd);
    // rotate the camera around the sphere 
    Camera.main.transform.RotateAround(sphere), Vector3.up, angle);
}

我考虑过使用Unitys RotateAround 方法以计算出的角度旋转摄像机.不幸的是,我没有旋转矢量(在示例中使用Vector3.up显然是错误的). 有人知道如何计算此向量以将其应用于该方法吗?我是否在实施Google Earth导航的正确方向上?

I thought of using Unitys RotateAround method to rotate the camera with the calculated angle. Unfortunately I do not have the rotation vector (using Vector3.up in the example is obviously wrong). Does somebody know how I can calculate this vector to apply it for the method? Am I on the right direction to implement the Google Earth navigation?

谢谢!

更新 我与一个新的解决方案非常接近.我将拖动向量投影到一个向下的平面和一个右侧的平面上,以获取角度.然后,我左右旋转相机.在我到达球体的两极之前,这一直很好.如果我到达杆子,相机会绕自身旋转很多.

UPDATE I am very close with a new solution. I project the drag vectors to a down and a right plane to get the angles. Afterwards I rotate the camera around up and left. This works well until I reach the poles of the sphere. The camera rotates a lot around itself if I reach a pole.

private void RotateCamera(Vector3 dragStart, Vector3 dragEnd)
{
    Vector3 plane = Vector3.down;
    var a = Vector3.ProjectOnPlane(dragStart, plane);
    var b = Vector3.ProjectOnPlane(dragEnd, plane);
    float up = Vector3.SignedAngle(a, b, plane);

    plane = Vector3.right;
    a = Vector3.ProjectOnPlane(dragStart, plane);
    b = Vector3.ProjectOnPlane(dragEnd, plane);
    float left = Vector3.SignedAngle(a, b, plane);

    Camera.main.transform.RotateAround(_sphere, Vector3.up, up);
    Camera.main.transform.RotateAround(_sphere, Vector3.left, left);
}

推荐答案

结果比我想象的要容易.我考虑过计算旋转轴,得出的结论是必须是起始向量和结束向量的叉积.看一下解决方案. RotateCamera 方法是数学魔术发生的地方:)

Turns out that is was easier than I expected. I thought about calculating the rotation axis and came to the conclusion that is must be the cross product of the start and end vector. Take a look at the solution. The RotateCamera method is where the math magic happens :)

public class GoogleEarthControls : MonoBehaviour
{
    private const int SpehreRadius = 1;
    private Vector3? _mouseStartPos;
    private Vector3? _currentMousePos;

    void Start () {
        // init the camera to look at this object
        Vector3 cameraPos = new Vector3(
            transform.position.x, 
            transform.position.y, 
            transform.position.z - 2);

        Camera.main.transform.position = cameraPos;
        Camera.main.transform.LookAt(transform.position);
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0)) _mouseStartPos = GetMouseHit();
        if (_mouseStartPos != null) HandleDrag();
        if (Input.GetMouseButtonUp(0)) HandleDrop();
    }

    private void HandleDrag()
    {
        _currentMousePos = GetMouseHit();
        RotateCamera((Vector3) _mouseStartPos, (Vector3)_currentMousePos);
    }

    private void HandleDrop()
    {
        _mouseStartPos = null;
        _currentMousePos = null;
    }

    private void RotateCamera(Vector3 dragStartPosition, Vector3 dragEndPosition)
    {
        // in case the spehre model is not a perfect sphere..
        dragEndPosition = dragEndPosition.normalized * SpehreRadius;
        dragStartPosition = dragStartPosition.normalized * SpehreRadius;
        // calc a vertical vector to rotate around..
        var cross = Vector3.Cross(dragEndPosition, dragStartPosition);
        // calc the angle for the rotation..
        var angle = Vector3.SignedAngle(dragEndPosition, dragStartPosition, cross);
        // roatate around the vector..
        Camera.main.transform.RotateAround(transform.position, cross, angle);
    }

    /**
     * Projects the mouse position to the sphere and returns the intersection point. 
     */
    private static Vector3? GetMouseHit()
    {
        // make sure there is a shepre mesh with a colider centered at this game object
        // with a radius of SpehreRadius
        RaycastHit hit;
        if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit))
        {
            return hit.point;
        }
        return null;
    }
}

这篇关于创建类似于球形导航的Google Earth的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆