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); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)