主要功能:移动(鼠标右键+WASD,滚轮按下及滚轮拉近),旋转,正交俯视相机(空格键切换),聚焦功能(给定FocusTarget,并按下F键)。
EditorCamera:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class EditorCamera : BaseCamera
{
#region 3D
private float _smoothMoveSpeed = 5; //位移变化平滑值(作用于所有相机位移操作)
private Vector3 _moveTarget = Vector3.zero; //平移目标值
//zoom
private float _zoomSpeed = 3;
//move
private float _moveSpeed = 0.5f;
private Vector3 _moveOffset = Vector3.zero;
//rotate
private float _rotateSpeed = 3;
//drag
private bool _invertDrag = false;
private float _dragSpeed = 1;
#endregion
#region 2D
//zoom
private bool _invert2DZoom = false;
private float _2DZoomSpeed = 10;
private float _2DZoomSmoothSpeed = 5;
private float _2DZoomOffset = 0;
private float _2DZoomTarget = 0;
#endregion
#region switch projection
public bool IsOrtho()
{
return _camera.orthographic;
}
private bool _isSwitchProjection = false;
private float t = 0;
Matrix4x4 orthMat = Matrix4x4.identity;
Matrix4x4 persMat = Matrix4x4.identity;
#endregion
private Camera _camera;
public Transform FocusTarget { set; get; }
private void Start()
{
_camera = GetComponent<Camera>();
_moveTarget = transform.position;
_2DZoomTarget = _camera.orthographicSize;
}
// perspective projection othographic projection相互切换
public void SwitchProjection()
{
if (!_isSwitchProjection && Input.GetKeyDown(KeyCode.Space))
{
//记录矩阵信息
bool isOrth = _camera.orthographic;
if (isOrth)
{
orthMat = _camera.projectionMatrix;
_camera.orthographic = !isOrth;
persMat = _camera.projectionMatrix;
}
else
{
persMat = _camera.projectionMatrix;
_camera.orthographic = !isOrth;
orthMat = _camera.projectionMatrix;
}
_camera.orthographic = isOrth;
//投影矩阵切换
_isSwitchProjection = true;
if (isOrth)
{
transform.DORotateQuaternion(Quaternion.LookRotation(Vector3.forward), 0.5f).OnComplete(() =>
{
t = 1;
DOTween.To(() => t, x => t = x, 0, 1f).SetEase(Ease.OutCubic).OnComplete(() =>
{
_camera.orthographic = !isOrth;
_isSwitchProjection = false;
});
});
}
else
{
transform.DORotateQuaternion(Quaternion.LookRotation(Vector3.down), 0.5f).OnComplete(() =>
{
t = 0;
DOTween.To(() => t, x => t = x, 1, 1f).SetEase(Ease.OutCubic).OnComplete(() =>
{
_camera.orthographic = !isOrth;
_isSwitchProjection = false;
});
});
}
}
if (_isSwitchProjection)
{
_camera.projectionMatrix = ExtensionMethod.MatrixLerp(persMat, orthMat, t);
}
}
private void Update()
{
SwitchProjection();
Focus(FocusTarget);
}
private void Focus(Transform target)
{
if (Input.GetKeyDown(KeyCode.F) && target != null)
{
//获取物体的尺寸
Vector3 scale = target.localScale;
Quaternion originRotation = target.rotation;
target.rotation = Quaternion.identity;
target.localScale = Vector3.one;
Renderer[] renders = target.GetComponentsInChildren<Renderer>();
Vector3 boundCenter = Vector3.zero;
foreach (var VARIABLE in renders)
{
boundCenter += VARIABLE.bounds.center;
}
boundCenter /= target.childCount;
Bounds bounds = new Bounds(boundCenter, Vector3.zero);
foreach (var VARIABLE in renders)
{
bounds.Encapsulate(VARIABLE.bounds);
}
target.rotation = originRotation;
target.localScale = scale;
//设置相机位置
bounds.size = new Vector3(bounds.size.x * scale.x, bounds.size.y * scale.y, bounds.size.z * scale.z);
float maxLength = Vector3.Distance(bounds.max, bounds.min);
float angle = _camera.fieldOfView / 2 * Mathf.Deg2Rad;
float distance = _camera.aspect > 1
? maxLength / (2 * Mathf.Sin(angle))
: maxLength / (2 * _camera.aspect * Mathf.Sin(angle));
Vector3 targetPos = target.TransformPoint(bounds.center - target.position) - _camera.transform.forward * distance;
_moveTarget = targetPos;
//正交相机时改变size
if (IsOrtho())
{
_2DZoomTarget = maxLength / 2 + 1;
}
}
}
protected override void Move()
{
_moveOffset = Vector3.zero;
if (Input.GetMouseButton(1) && !IsOrtho())
{
Vector3 direction = Vector3.zero;
if (Input.GetKey(_forwardKey))
direction = transform.forward;
if (Input.GetKey(_backKey))
direction = -transform.forward;
if (Input.GetKey(_leftKey))
direction = -transform.right;
if (Input.GetKey(_rightKey))
direction = transform.right;
_moveOffset += direction * _moveSpeed;
}
if (_moveOffset != Vector3.zero)
_moveTarget = transform.position + _moveOffset;
transform.position = Vector3.Lerp(transform.position, _moveTarget, _smoothMoveSpeed * Time.deltaTime);
}
protected override void Rotate()
{
if (Input.GetMouseButton(1) && !IsOrtho())
{
float mouseX = Input.GetAxis(_mouseXStr);
float mouseY = Input.GetAxis(_mouseYStr);
transform.RotateAround(transform.position, Vector3.up, mouseX * _rotateSpeed);
transform.RotateAround(transform.position, -transform.right, mouseY * _rotateSpeed);
}
}
protected override void Zoom()
{
float moveAmount = Input.GetAxis(_mouseScrollWheelStr);
if (moveAmount == 0)
return;
if (IsOrtho())
{
_2DZoomOffset = 0;
int invert = _invert2DZoom ? 1 : -1;
if (moveAmount != 0)
{
_2DZoomOffset += moveAmount * _2DZoomSpeed * invert;
}
if (_2DZoomOffset != 0)
{
_2DZoomTarget = _camera.orthographicSize + _2DZoomOffset;
}
_2DZoomTarget = Mathf.Clamp(_2DZoomTarget, 0.1f, 30);
_camera.orthographicSize = Mathf.Lerp(_camera.orthographicSize, _2DZoomTarget, _2DZoomSmoothSpeed * Time.deltaTime);
}
else
{
_moveOffset = Vector3.zero;
if (moveAmount != 0)
{
_moveOffset += moveAmount * _zoomSpeed * transform.forward;
}
if (_moveOffset != Vector3.zero)
_moveTarget = transform.position + _moveOffset;
transform.position = Vector3.Lerp(transform.position, _moveTarget, _smoothMoveSpeed * Time.deltaTime);
}
}
protected override void Drag()
{
_moveOffset = Vector3.zero;
if (Input.GetMouseButton(2))
{
float invert = _invertDrag ? 1 : -1;
float mouseX = Input.GetAxis(_mouseXStr) * invert;
float mouseY = Input.GetAxis(_mouseYStr) * invert;
float mulpti = IsOrtho() ? _camera.orthographicSize : 1;
_moveOffset += transform.right * mouseX * _dragSpeed * mulpti;
_moveOffset += transform.up * mouseY * _dragSpeed * mulpti;
}
if (_moveOffset != Vector3.zero)
_moveTarget = transform.position + _moveOffset;
transform.position = Vector3.Lerp(transform.position, _moveTarget, _smoothMoveSpeed * Time.deltaTime);
}
}
BaseCamera:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.PlayerLoop;
public abstract class BaseCamera : MonoBehaviour
{
protected KeyCode _forwardKey = KeyCode.W;
protected KeyCode _backKey = KeyCode.S;
protected KeyCode _leftKey = KeyCode.A;
protected KeyCode _rightKey = KeyCode.D;
protected readonly string _mouseXStr = "Mouse X";
protected readonly string _mouseYStr = "Mouse Y";
protected readonly string _mouseScrollWheelStr = "Mouse ScrollWheel";
protected abstract void Rotate();
protected abstract void Move();
protected abstract void Zoom();
protected abstract void Drag();
private void LateUpdate()
{
Rotate();
Move();
Zoom();
Drag();
}
}
|