各位朋友,大家好,我是秦元培,欢迎大家关注我的博主,最近博主重点研究了摄像机旋转、缩放等问题,那么今天为大家分享的是一个在3D展示中比较常用的功能,即通过鼠标右键实现旋转、鼠标滚轮实现缩放、鼠标中键实现平移。本文采用的方法依然是在[Unity3D]Unity3D游戏开发之自由视角下的角色控制这篇文章中所采用的方法,所以如果大家对于这部分内容不太了解的话,最好先去看看这篇文章。好了,下面我们将以一个具体的实例来讲解今天的内容。如图,是博主创建的一个简单地场景。我们希望实现通过鼠标右键实现对角色的旋转、鼠标滚轮实现对角色的缩放、鼠标中键实现对角色的平移。


using UnityEngine;
using System.Collections;

public class FreeView : MonoBehaviour
{

    //观察目标
    public Transform Target;

    //观察距离
    public float Distance = 5F;

    //旋转速度
    private float SpeedX = 240;
    private float SpeedY = 120;

    //角度限制
    private float MinLimitY = -180;
    private float MaxLimitY = 180;

    //旋转角度
    private float mX = 0.0F;
    private float mY = 0.0F;

    //鼠标缩放距离最值
    private float MaxDistance = 10;
    private float MinDistance = 1.5F;
    //鼠标缩放速率
    private float ZoomSpeed = 2F;

    //是否启用差值
    public bool isNeedDamping = true;
    //速度
    public float Damping = 10F;

    //存储角度的四元数
    private Quaternion mRotation;

    //定义鼠标按键枚举
    private enum MouseButton
    {
        //鼠标左键
        MouseButton_Left = 0,
        //鼠标右键
        MouseButton_Right = 1,
        //鼠标中键
        MouseButton_Midle = 2
    }

    //相机移动速度
    private float MoveSpeed = 5.0F;
    //屏幕坐标
    private Vector3 mScreenPoint;
    //坐标偏移
    private Vector3 mOffset;

    void Start()
    {
        //初始化旋转角度
        mX = transform.eulerAngles.x;
        mY = transform.eulerAngles.y;
    }

    void LateUpdate()
    {
        //鼠标右键旋转
        if (Target != null && Input.GetMouseButton((int)MouseButton.MouseButton_Right))
        {
            //获取鼠标输入
            mX += Input.GetAxis("Mouse X") * SpeedX * 0.02F;
            mY -= Input.GetAxis("Mouse Y") * SpeedY * 0.02F;
            //范围限制
            mY = ClampAngle(mY, MinLimitY, MaxLimitY);
            //计算旋转
            mRotation = Quaternion.Euler(mY, mX, 0);
            //根据是否插值采取不同的角度计算方式
            if (isNeedDamping)
            {
                transform.rotation = Quaternion.Lerp(transform.rotation, mRotation, Time.deltaTime * Damping);
            }
            else
            {
                transform.rotation = mRotation;
            }
        }

        //鼠标中键平移


        //鼠标滚轮缩放
        Distance -= Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed;
        Distance = Mathf.Clamp(Distance, MinDistance, MaxDistance);

        //重新计算位置
        Vector3 mPosition = mRotation * new Vector3(0.0F, 0.0F, -Distance) + Target.position;

        //设置相机的位置
        if (isNeedDamping)
        {
            transform.position = Vector3.Lerp(transform.position, mPosition, Time.deltaTime * Damping);
        }
        else
        {
            transform.position = mPosition;
        }

    }


    //角度限制
    private float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360) angle += 360;
        if (angle > 360) angle -= 360;
        return Mathf.Clamp(angle, min, max);
    }
}



家是不是觉得这部分代码很熟悉?不错,这里的原理都是一样的,大家只要掌握核心原理就可以了,即首先根据鼠标输入来计算旋转角、然后通过滚轮输入计算距离、最后通过四元数运算计算相机的角度和距离。


。好了,最后我们再来做一个迁移,我们将把这个功能移植到Android平台上,本来想把这部分作为Android手势控制单独写一篇文章的,可是感觉这里的代码都是相似的,再写一篇实在没有必要,所以,就直接给出代码吧!


using UnityEngine;  
    using System.Collections;  
      
    public class MobileInput : MonoBehaviour {  
      
        //观察目标  
        public Transform Target;  
      
        //观察距离  
        public float Distance = 2F;  
      
        //距离最值  
        public float MaxDistance=5F;  
        public float MinDistance=0.5F;  
      
        //缩放速率  
        private float ZoomSpeed=0.15F;  
      
        //旋转速度  
        private float SpeedX=240;  
        private float SpeedY=120;  
        //角度限制  
        private float  MinLimitY = 5;  
        private float  MaxLimitY = 180;  
          
        //旋转角度  
        private float mX=0;  
        private float mY=0;  
      
        //当前手势  
        private Vector2 mPos;  
      
        void Start ()   
        {  
            //允许多点触控  
            Input.multiTouchEnabled=true;  
            //初始化旋转  
            mX=Target.eulerAngles.x;  
            mY=Target.eulerAngles.y;  
        }  
      
        void Update ()   
        {  
            if(!Target) return;  
      
      
            //单点触控  
            if(Input.touchCount==1)  
            {  
                //手指处于移动状态  
                if(Input.touches[0].phase==TouchPhase.Moved)  
                {  
                    mX+=Input.GetAxis("Mouse X") * SpeedX * 0.02F;  
                    mY-=Input.GetAxis("Mouse X") * SpeedY * 0.02F;  
                    mY=ClampAngle(mY,MinLimitY,MaxLimitY);  
                }  
            }  
      
            //多点触控  
            if(Input.touchCount>1)  
            {  
                //两只手指都处于移动状态  
                if(Input.touches[0].phase==TouchPhase.Moved || Input.touches[1].phase==TouchPhase.Moved)  
                {  
                    //计算移动方向  
                    Vector2 mDir=Input.touches[1].position-Input.touches[0].position;  
                    //根据向量的大小判断当前手势是放大还是缩小  
                    if(mDir.sqrMagnitude>mPos.sqrMagnitude){  
                        Distance-=ZoomSpeed;  
                    }else{  
                        Distance+=ZoomSpeed;  
                    }  
                    //限制距离  
                    Distance=Mathf.Clamp(Distance,MinDistance,MaxDistance);  
                    //更新当前手势  
                    mPos=mDir;  
                }  
            }  
      
            //计算相机的角度和位置  
            transform.rotation=Quaternion.Euler(new Vector3(mY,mX,0));  
            transform.position=transform.rotation * new Vector3(0,0,-Distance)+Target.position;  
        }  
      
        //角度限制  
        private float ClampAngle (float angle,float min,float max)   
        {  
            if (angle < -360) angle += 360;  
            if (angle >  360) angle -= 360;  
            return Mathf.Clamp (angle, min, max);  
        }  
    }



以下添加鼠标旋转被选中物体


鼠标旋转被选中的物体


1.X轴在平面坐标是左右方向,这里得到的是左右移动距离
2.移动距离得到了,接下来要考虑以那个轴为中心作旋转
3.这里要实现固定摄像机位置的情况下旋转物体,就以Y轴为中心,所以Rotate(0,mousX,0);



public float roate_Speed=100.0f;//旋转速度  
    void Update()  
    {  
    Transform target_transform = null;//不用绑定对象,下面代码动态获取对象  
    if (Input.GetMouseButton(0))  
                {  
                     
                    //在屏幕上转换坐标:将鼠标点转换成射线  
                    Ray rayObj = Camera.main.ScreenPointToRay(Input.mousePosition);  
                    RaycastHit hitObj;  
                    if (Physics.Raycast(rayObj, out hitObj))  
                    {  
                        //Debug.Log("射线得到的对象名称:" + hitObj.collider.name);  
                        target_transform = hitObj.transform;  
                    }  
      
      
                    if (target_transform != null)  
                    {  
                        //Debug.Log("射线取得对象");  
                        float mousX = Input.GetAxis("Mouse X") * roate_Speed;//得到鼠标移动距离  
                        target_transform.transform.Rotate(new Vector3(0, -mousX, 0));  
                    }  
                    else  
                    {  
                        Debug.Log("无法取得对象");  
                    }  
                }  
    }