358 lines
11 KiB
C#
358 lines
11 KiB
C#
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);
|
||
}
|
||
|
||
// 公共方法
|
||
|
||
/// <summary>
|
||
/// 重置视角
|
||
/// </summary>
|
||
public void ResetView()
|
||
{
|
||
targetRotation = new Vector3(0, 45f, 0); // 默认视角
|
||
targetDistance = defaultZoomDistance;
|
||
targetPositionOffset = Vector3.zero;
|
||
enableAutoRotation = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 聚焦到模型
|
||
/// </summary>
|
||
public void FocusOnModel()
|
||
{
|
||
if (target != null)
|
||
{
|
||
targetPositionOffset = Vector3.zero;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置观察目标
|
||
/// </summary>
|
||
public void SetTarget(Transform newTarget)
|
||
{
|
||
target = newTarget;
|
||
ResetView();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置观察目标
|
||
/// </summary>
|
||
public void SetTarget(GameObject newTarget)
|
||
{
|
||
if (newTarget != null)
|
||
{
|
||
target = newTarget.transform;
|
||
ResetView();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置观察目标的中心点
|
||
/// </summary>
|
||
public void SetTargetOffset(Vector3 offset)
|
||
{
|
||
targetPositionOffset = offset;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置缩放距离
|
||
/// </summary>
|
||
public void SetZoomDistance(float distance)
|
||
{
|
||
targetDistance = Mathf.Clamp(distance, minZoomDistance, maxZoomDistance);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置旋转角度
|
||
/// </summary>
|
||
public void SetRotation(float horizontal, float vertical)
|
||
{
|
||
targetRotation = new Vector3(horizontal, Mathf.Clamp(vertical, verticalAngleLimit.x, verticalAngleLimit.y), 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切换自动旋转
|
||
/// </summary>
|
||
public void ToggleAutoRotation(bool enable)
|
||
{
|
||
enableAutoRotation = enable;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置自动旋转速度
|
||
/// </summary>
|
||
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);
|
||
}
|
||
}
|
||
} |