U3D中摄像机绕屏幕中心点旋转缩放平移

之前做的都是摄像机绕某个物体旋转。直接修改的Rotation属性

然后缩放用的是改摄像机FieldOfView的值

最后发觉效果不仅不尽如人意而且平移后会错位。在借鉴了一个别人的摄像机代码后修改成功

按住右键旋转,按住中键平移,滚轮缩放

脚本拖放到摄像机上即可

代码如下

using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FreeCameraController : MonoBehaviour
{
//摄像机绕屏幕中心旋转缩放平移脚本
public float thetaSpeed = 150.0f; //x旋转速度
public float phiSpeed = 80.0f; //垂直旋转速度
public float moveSpeed = 10.0f; //平移速度
public float zoomSpeed = 60.0f; //缩放速度
public float phiBoundMin = 1f; //最低垂直旋转角度
public float phiBoundMax = 89f; //最高垂直旋转角度
public bool useMoveBounds = true; //是否绑定移动范围
public float moveBounds = 220f; //绑定移动范围 四周 还有上面
public float moveLimiyY = 35f; //绑定移动范围 下方
//缩放距离限制 最小,最大
public Vector2 distanceLimit = new Vector2(20f, 600f);
//旋转平滑
public float rotateSmoothing = 0.5f;
//移动平滑
public float moveSmoothing = 0.7f;
//当前距离
public float distance = 2.0f;
//摄像机的初始角度
private Vector2 euler;
//目标旋转角度
public Quaternion targetRot;
//当前朝向的目标
private Vector3 targetLookAt;
//当前摄像机到目标的距离
public float targetDist;
//临时变量
private Vector3 distanceVec = new Vector3(0, 0, 0);
//目标对象的变换
public Transform target;
//绑定屏幕范围
private Rect inputBounds;
public Rect paramInputBounds = new Rect(0, 0, 1, 1);
//中心点
public Vector3 pivotPoint = new Vector3(0, 2, 0);
//当前选中的对象
public static BaseModel selectModel;
//限制鼠标范围 避免点击抖动
private Vector2 limitMouseX = new Vector2(-5, 5);
private Vector2 limitMouseY = new Vector2(-5, 5);
//目标位置
public Vector3 targetPos;
//日志
[Logger]
private IWebLogger logger;
// 是否能操作
bool canOper = false;
//看向目标需要的时间
float LookAtTime = 1.5f;
public void Start()
{
//获取当前摄像机的角度
Vector3 angles = transform.eulerAngles;
euler.x = angles.y;
euler.y = angles.x;
//unity only returns positive euler angles but we need them in -90 to 90
euler.y = Mathf.Repeat(euler.y + 180f, 360f) - 180f;
//创建目标物体
GameObject go = new GameObject("_FreeCameraTarget");
//设置隐藏并不保存
go.hideFlags = HideFlags.HideAndDontSave | HideFlags.HideInInspector;
//设置初始参数
target = go.transform; //设置目标
target.position = pivotPoint; //设置中心点为其实目标位置
targetDist = (transform.position - target.position).magnitude; //获取相机到中心点的距离
targetRot = transform.rotation; //设置目标旋转角度
targetLookAt = target.position; //设置朝向的目标所在位置
//开始时摄像机缓慢看向目标
transform.DOLookAt(targetLookAt, LookAtTime);
SetOper(pivotPoint, LookAtTime);
}
//设置摄像机缓慢看向目标
public void SetOper(Vector3 targetPos, float lookAtTime)
{
canOper = false;
this.targetPos = targetPos;
//开启定时任务
TimeManager.Instance.AddTask(lookAtTime, false, Oper);
TimeManager.Instance.AddTask(lookAtTime+0.2f, false, CanOper);
}
private void Oper()
{
//计算DOLookAt结束后的参数
target.position = targetPos;
targetDist = (transform.position - target.position).magnitude;
targetRot = transform.rotation;
targetLookAt = target.position;
//修正DOLookAt的偏差值
float distanceTemp;
do
{
distanceTemp = distance;
distance = moveSmoothing * targetDist + (1 - moveSmoothing) * distance;
//print("Oper.distance --->" + distance);
} while (distanceTemp != distance);
}
private void CanOper()
{
canOper = true;
}
public void Update()
{
if (!canOper)
{
return;
}
//NOTE: mouse coordinates have a bottom-left origin, camera top-left
inputBounds.x = GetComponent<Camera>().pixelWidth * paramInputBounds.x;
inputBounds.y = GetComponent<Camera>().pixelHeight * paramInputBounds.y;
inputBounds.width = GetComponent<Camera>().pixelWidth * paramInputBounds.width;
inputBounds.height = GetComponent<Camera>().pixelHeight * paramInputBounds.height;
//目标存在 且 在屏幕范围内
if (target && inputBounds.Contains(Input.mousePosition))
{
// 点击 并获取点击物体
if (Input.GetMouseButtonUp(0))
{
// 前端 click() ---> 点击物体
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 2000))
{
Debug.DrawLine(ray.origin, hit.point, Color.red, 0.5f);
//Debug.Log(hit.point);
BaseModel baseModel = hit.collider.gameObject.GetComponent<BaseModel>();
if (baseModel != null)
{
selectModel = baseModel;
logger.Log("id:" + baseModel.Uuid + " prefabName:" + baseModel.BaseData.PrefabName +
" position:" + baseModel.BaseData.Transform.position +
" modelType:" + baseModel.modelType);
// 触发点击事件
if (!baseModel.BaseData.IsNoClick)
{
Sender sender = new Sender();
sender.eventName = BaseEvent.click;
sender.souce = gameObject;
EventCenter.Instance.TriggerEvent(BaseEvent.click, sender, baseModel.Uuid);
}
return;
}
}
}
//获取鼠标在屏幕的x.y值
float dx = Input.GetAxis("Mouse X");
float dy = Input.GetAxis("Mouse Y");
//鼠标偏移量限制,防止抖动
if (dx < limitMouseX.x || dx > limitMouseX.y)
{
//print("鼠标旋转位置:" + MousePosition);
return;
}
if (dy < limitMouseY.x || dy > limitMouseY.y)
{
//print("鼠标旋转位置:" + MousePosition);
return;
}
//点击鼠标右键
bool click1 = Input.GetMouseButton(1);
//点击鼠标左键
bool click0 = Input.GetMouseButton(0);
if (click0)
{
//计算移动量
dx = dx * moveSpeed * 0.005f * targetDist;
dy = dy * moveSpeed * 0.005f * targetDist;
targetLookAt -= transform.up * dy + transform.right * dx;
//使用移动绑定的范围
if (useMoveBounds)
{
targetLookAt.x = Mathf.Clamp(targetLookAt.x, -moveBounds, moveBounds);
//targetLookAt.y = Mathf.Clamp(targetLookAt.y, -moveBounds, moveBounds);
targetLookAt.y = Mathf.Clamp(targetLookAt.y, moveLimiyY, moveBounds);
targetLookAt.z = Mathf.Clamp(targetLookAt.z, -moveBounds, moveBounds);
}
}
else if (click1)
{
//计算旋转角度
dx = dx * thetaSpeed * 0.02f;
dy = dy * phiSpeed * 0.02f;
euler.x += dx;
euler.y -= dy;
//限制垂直旋转角度
euler.y = ClampAngle(euler.y, phiBoundMin, phiBoundMax);
targetRot = Quaternion.Euler(euler.y, euler.x, 0);
}
//当前摄像机到目标的距离 减鼠标滑动距离
targetDist -= Input.GetAxis("Mouse ScrollWheel") * zoomSpeed;
//限制缩放
targetDist = Mathf.Clamp(targetDist, distanceLimit.x, distanceLimit.y);
}
}
public void FixedUpdate()
{
//不可操作的清空下直接return
if (!canOper)
{
return;
}
//计算距离
distance = moveSmoothing * targetDist + (1 - moveSmoothing) * distance;
if (Application.platform == RuntimePlatform.WebGLPlayer)
{
logger.Error("FixedUpdate.distance --->" + distance);
}
//计算旋转角度插值
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, rotateSmoothing);
//计算距离插值
target.position = Vector3.Lerp(target.position, targetLookAt, moveSmoothing);
//设置距离 Z轴
distanceVec.z = distance;
//设置相机最终的位置 目标位置 - 相机当前旋转角度 * 距离Z轴
transform.position = target.position - transform.rotation * distanceVec;
}
/// <summary>
/// 限制角度
/// </summary>
/// <param name="angle"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
static float ClampAngle(float angle, float min, float max)
{
if (angle < -360f) angle += 360f;
if (angle > 360f) angle -= 360f;
return Mathf.Clamp(angle, min, max);
}
}

posted @   Excel2016  阅读(657)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示