using UnityEngine;
public class ModelViewerOrbitCamera : MonoBehaviour
{
[Header("观察目标")]
[SerializeField] private Transform target; // 要观察的模型
[Header("旋转设置")]
[SerializeField] private float rotationSpeed = 5.0f;
[SerializeField] private float autoRotationSpeed = 0.5f;
[SerializeField] private float rotationSmoothness = 5.0f;
[Header("缩放设置")]
[SerializeField] private float zoomSpeed = 5.0f;
[SerializeField] private float minZoomDistance = 1.0f;
[SerializeField] private float maxZoomDistance = 20.0f;
[SerializeField] private float defaultZoomDistance = 5.0f;
[Header("平移设置")]
[SerializeField] private float panSpeed = 0.5f;
[Header("自动旋转")]
[SerializeField] private bool enableAutoRotation = false;
[Header("鼠标控制")]
[SerializeField] private MouseButton rotateButton = MouseButton.Left;
[SerializeField] private MouseButton panButton = MouseButton.Middle;
[SerializeField] private float mouseSensitivity = 1.0f;
[Header("触摸屏控制")]
[SerializeField] private float touchSensitivity = 0.5f;
[Header("边界限制")]
[SerializeField] private Vector2 verticalAngleLimit = new Vector2(10f, 80f);
private Vector3 currentRotation = Vector3.zero;
private Vector3 targetRotation = Vector3.zero;
private float currentDistance = 5.0f;
private float targetDistance = 5.0f;
private Vector3 targetPositionOffset = Vector3.zero;
private Vector3 currentTargetPositionOffset = Vector3.zero;
private Vector3 lastMousePosition = Vector3.zero;
private Vector3 lastPanPosition = Vector3.zero;
private enum MouseButton
{
Left = 0,
Right = 1,
Middle = 2
}
void Start()
{
// 如果未指定目标,尝试查找
if (target == null)
{
// 可以在这里添加自动查找模型的逻辑
// 例如:target = GameObject.Find("Model").transform;
}
// 初始化距离
currentDistance = defaultZoomDistance;
targetDistance = defaultZoomDistance;
// 初始化旋转
Vector3 angles = transform.eulerAngles;
currentRotation = new Vector3(angles.y, angles.x, 0);
targetRotation = currentRotation;
// 计算初始位置
UpdateCameraPosition();
}
void LateUpdate()
{
if (target == null) return;
HandleInput();
UpdateCameraPosition();
}
private void HandleInput()
{
// 处理桌面端输入
HandleDesktopInput();
// 处理移动端输入
HandleTouchInput();
}
private void HandleDesktopInput()
{
// 旋转控制
if (Input.GetMouseButton((int)rotateButton))
{
float horizontal = Input.GetAxis("Mouse X") * rotationSpeed * mouseSensitivity;
float vertical = -Input.GetAxis("Mouse Y") * rotationSpeed * mouseSensitivity;
targetRotation.x += horizontal;
targetRotation.y += vertical;
// 限制垂直角度
targetRotation.y = Mathf.Clamp(targetRotation.y, verticalAngleLimit.x, verticalAngleLimit.y);
// 停止自动旋转
enableAutoRotation = false;
}
// 平移控制
if (Input.GetMouseButton((int)panButton))
{
if (Input.GetMouseButtonDown((int)panButton))
{
lastPanPosition = Input.mousePosition;
}
Vector3 delta = Input.mousePosition - lastPanPosition;
// 计算平移方向(基于相机的右和上方向)
Vector3 right = transform.right;
Vector3 up = transform.up;
right.y = 0; // 保持水平平移
up.y = 0;
targetPositionOffset -= (right * delta.x + up * delta.y) * panSpeed * 0.01f;
lastPanPosition = Input.mousePosition;
}
// 缩放控制
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (Mathf.Abs(scroll) > 0.01f)
{
targetDistance -= scroll * zoomSpeed;
targetDistance = Mathf.Clamp(targetDistance, minZoomDistance, maxZoomDistance);
}
// 重置按钮
if (Input.GetKeyDown(KeyCode.R))
{
ResetView();
}
// 自动旋转切换
if (Input.GetKeyDown(KeyCode.A))
{
enableAutoRotation = !enableAutoRotation;
}
}
private void HandleTouchInput()
{
#if UNITY_IOS || UNITY_ANDROID || UNITY_WEBGL
if (Input.touchCount == 1)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved)
{
Vector2 delta = touch.deltaPosition;
targetRotation.x += delta.x * rotationSpeed * touchSensitivity * 0.1f;
targetRotation.y -= delta.y * rotationSpeed * touchSensitivity * 0.1f;
// 限制垂直角度
targetRotation.y = Mathf.Clamp(targetRotation.y, verticalAngleLimit.x, verticalAngleLimit.y);
}
}
else if (Input.touchCount == 2)
{
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;
targetDistance += deltaMagnitudeDiff * zoomSpeed * 0.01f;
targetDistance = Mathf.Clamp(targetDistance, minZoomDistance, maxZoomDistance);
}
#endif
}
private void UpdateCameraPosition()
{
// 自动旋转
if (enableAutoRotation)
{
targetRotation.x += autoRotationSpeed;
}
// 应用旋转平滑
currentRotation = Vector3.Lerp(currentRotation, targetRotation, rotationSmoothness * Time.deltaTime);
// 应用距离平滑
currentDistance = Mathf.Lerp(currentDistance, targetDistance, rotationSmoothness * Time.deltaTime);
// 应用平移平滑
currentTargetPositionOffset = Vector3.Lerp(currentTargetPositionOffset, targetPositionOffset, rotationSmoothness * Time.deltaTime);
// 计算旋转
Quaternion rotation = Quaternion.Euler(currentRotation.y, currentRotation.x, 0);
// 计算位置
Vector3 position = rotation * new Vector3(0, 0, -currentDistance) + target.position + currentTargetPositionOffset;
// 应用变换
transform.position = position;
transform.LookAt(target.position + currentTargetPositionOffset);
// 可选:使相机稍微向上看
// transform.LookAt(target.position + currentTargetPositionOffset + Vector3.up * 0.5f);
}
// 公共方法
///
/// 重置视角
///
public void ResetView()
{
targetRotation = new Vector3(0, 45f, 0); // 默认视角
targetDistance = defaultZoomDistance;
targetPositionOffset = Vector3.zero;
enableAutoRotation = false;
}
///
/// 聚焦到模型
///
public void FocusOnModel()
{
if (target != null)
{
targetPositionOffset = Vector3.zero;
}
}
///
/// 设置观察目标
///
public void SetTarget(Transform newTarget)
{
target = newTarget;
ResetView();
}
///
/// 设置观察目标
///
public void SetTarget(GameObject newTarget)
{
if (newTarget != null)
{
target = newTarget.transform;
ResetView();
}
}
///
/// 设置观察目标的中心点
///
public void SetTargetOffset(Vector3 offset)
{
targetPositionOffset = offset;
}
///
/// 设置缩放距离
///
public void SetZoomDistance(float distance)
{
targetDistance = Mathf.Clamp(distance, minZoomDistance, maxZoomDistance);
}
///
/// 设置旋转角度
///
public void SetRotation(float horizontal, float vertical)
{
targetRotation = new Vector3(horizontal, Mathf.Clamp(vertical, verticalAngleLimit.x, verticalAngleLimit.y), 0);
}
///
/// 切换自动旋转
///
public void ToggleAutoRotation(bool enable)
{
enableAutoRotation = enable;
}
///
/// 设置自动旋转速度
///
public void SetAutoRotationSpeed(float speed)
{
autoRotationSpeed = speed;
}
// 编辑器调试信息
void OnGUI()
{
if (Application.isEditor)
{
GUI.Label(new Rect(10, 10, 300, 20),
$"上帝视角观察器 - 模型查看器");
if (target != null)
{
GUI.Label(new Rect(10, 30, 300, 20),
$"目标: {target.name}");
}
else
{
GUI.Label(new Rect(10, 30, 300, 20),
"目标: 未设置 (请在Inspector中指定)");
}
GUI.Label(new Rect(10, 50, 300, 20),
$"旋转: ({currentRotation.x:F1}, {currentRotation.y:F1})");
GUI.Label(new Rect(10, 70, 300, 20),
$"距离: {currentDistance:F1}");
GUI.Label(new Rect(10, 90, 300, 20),
$"自动旋转: {(enableAutoRotation ? "开" : "关")}");
GUI.Label(new Rect(10, 120, 400, 20),
"控制说明:");
GUI.Label(new Rect(10, 140, 400, 20),
"左键拖拽: 旋转视角");
GUI.Label(new Rect(10, 160, 400, 20),
"中键拖拽: 平移视角");
GUI.Label(new Rect(10, 180, 400, 20),
"滚轮: 缩放");
GUI.Label(new Rect(10, 200, 400, 20),
"R键: 重置视角");
GUI.Label(new Rect(10, 220, 400, 20),
"A键: 切换自动旋转");
}
}
// 在Scene视图中绘制辅助线
void OnDrawGizmosSelected()
{
if (target != null)
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(target.position + currentTargetPositionOffset, 0.5f);
Gizmos.DrawLine(target.position + currentTargetPositionOffset, transform.position);
}
}
}