EnergyEfficiencyManagement/Assets/Zion/Scripts/ModelViewerOrbitCamera.cs

358 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}