Unity填坑之俯视角相机水平面方向移动

Unity填坑之俯视角相机水平面方向移动


前言

碰到一个需求,就是摄像机是俯视角,即沿X轴旋转了一定角度,同时摄像机还能左右旋转,要求:滑动屏幕时,要让摄像机总是以平行于地面某个高度进行移动。


一、需求分析

一开始以为很简单的需求,如下图俯视角然后移动摄像机,要求移动的平面是地面,相当于地面上有个小人,然后摄像机跟随这个小人,关键就是这里没有小人。玩家在滑屏的时候实现平面移动,且以摄像机视角为参考坐标系。

在这里插入图片描述

在这里插入图片描述

补充一下,就是当玩家向上滑动屏幕时,向黑色水平面方向移动,向下则向红色方向移动。左右滑动,则是紫色,橙色方向移动。

二、解决方案有两种

1.模拟一个小人

以屏幕发射射线的方式,射向地面,通过每次移动都发射两条射线,一条是上一次鼠标所在屏幕位置发射,Camera.main.ScreenPointToRay(gesture.Position - gesture.DeltaMove),一条是本次鼠标所在屏幕发射Camera.main.ScreenPointToRay(gesture.Position)。然后可以用高度与射线向量,或者碰撞的方式,得到两个地面上的位置Position,这两个position相减得出一个向量,就是屏幕在世界空间中要移动的向量,简易代码如下,本例是利用射线向量与高度y值,得到世界坐标下的平面位置。

void OnDragMove(DragGesture gesture)
        {//拖拽移动
            if (gesture.Phase == ContinuousGesturePhase.Started)
            if (gesture.Phase != ContinuousGesturePhase.Updated) return;
            Ray ray1 = Camera.main.ScreenPointToRay(gesture.Position - gesture.DeltaMove);
            Ray ray2 = Camera.main.ScreenPointToRay(gesture.Position);
            Vector3 pos1 = GetPlanePoint(ray1);
            Vector3 pos2 = GetPlanePoint(ray2);
            transform.position -= pos2 - pos1;
        }
public static Vector3 GetPlanePoint(Ray ray, float planeY = 0)
        {
            Vector3 dir = ray.direction;
            if (dir.y.Equals(0)) return Vector3.zero;
            float num = (planeY - ray.origin.y) / dir.y;
            return ray.origin + ray.direction * num;
        }

2.通过四元数旋转的方式

上面第一种方式,有一个最大的弊端,就是当摄像机不是朝向地面时,射线摄入到天空与地面之间,这样移动距离就很大,移动就快到飞起。于是产生了第二种方法。直接通过玩家手指移动,当作摄像机在摄像机平面的移动。以摄像机本地坐标系为准,让其移动X,Z轴,这样摄像机会朝向地面移动,明显不符合需求,于是想到利用俯视角,将以摄像机本地坐标系得到的将要移动的坐标,通过四元数的方式,绕X轴旋转回来,这样就是在摄像机平面移动了。
代码如下:

void OnDragMove(DragGesture gesture)
        {//拖拽移动
            if (gesture.Phase == ContinuousGesturePhase.Started)
            if (gesture.Phase != ContinuousGesturePhase.Updated) return;
            Vector.x = -gesture.DeltaMove.x * moveRatio;
            Vector.y = 0;
            Vector.z = -gesture.DeltaMove.y * moveRatio;
            Vector3 temp2 = transform.TransformPoint(Vector);
            Quaternion quaTemp = Quaternion.AngleAxis(-transform.eulerAngles.x,transform.right);
            temp2= quaTemp * (temp2 - transform.position)+transform.position;
            transform.position = temp2;
        }

先创建一个鼠标移动向量(Vector),这就是以摄像机为本地坐标系将要移动的坐标,即在摄像机本地的XZ轴面移动,然后获取到其在世界坐标系中的坐标,然后获取以摄像机本身X轴,X轴旋转摄像机本身X的反向欧拉角度的四元数:Quaternion.AngleAxis(-transform.eulerAngles.x,transform.right);这将是在世界坐标系中,要围绕旋转的四元数,然后用转换后的世界坐标-摄像机的世界坐标得到相当于归原点的向量,用这个坐标围绕摄像机X轴的四元数进行旋转,得到相对向量,加上摄像机本身的坐标即为摄像机将要到的坐标。
不知道上面讲清楚没有,反正把上面这段代码挂在摄像机下即可。

总结

用了两种方法,平移摄像机,第二种方法没有什么太大弊端,仅此记录。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值