using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using SK.Framework;
///
/// 在RawImage上显示和控制3D模型的查看器
/// 支持以模型为中心的旋转、缩放、平移等基本操作
///
public class RawImageModelViewer : MonoBehaviour
{
[Header("【模型显示设置】")]
[Tooltip("要显示的3D模型预制件")]
public GameObject modelPrefab;
[Header("【UI组件引用】")]
[Tooltip("用于显示模型的RawImage组件")]
public RawImage displayImage;
[Tooltip("渲染纹理,用于将3D模型渲染到UI上")]
public RenderTexture renderTexture;
[Tooltip("专门用于渲染模型到纹理的相机")]
public Camera renderCamera;
[Header("【旋转控制】")]
[Tooltip("旋转灵敏度")]
public float rotationSpeed = 5.0f;
[Tooltip("是否启用旋转功能")]
public bool enableRotation = true;
[Tooltip("垂直旋转角度限制")]
public Vector2 verticalAngleLimit = new Vector2(-80f, 80f);
[Header("【缩放控制】")]
[Tooltip("缩放灵敏度")]
public float zoomSpeed = 5.0f;
[Tooltip("最小缩放距离")]
public float minZoomDistance = 1.0f;
[Tooltip("最大缩放距离")]
public float maxZoomDistance = 20.0f;
[Tooltip("默认缩放距离")]
public float defaultZoomDistance = 5.0f;
[Tooltip("是否启用缩放功能")]
public bool enableZoom = true;
[Header("【平移控制】")]
[Tooltip("平移灵敏度")]
public float panSpeed = 0.5f;
[Tooltip("是否启用平移功能")]
public bool enablePan = true;
[Tooltip("X轴最大平移距离")]
public float maxPanDistanceX = 5.0f;
[Tooltip("Z轴最大平移距离")]
public float maxPanDistanceZ = 5.0f;
[Header("【相机设置】")]
[Tooltip("相机的初始位置偏移")]
public Vector3 cameraOffset = new Vector3(0, 0, -5);
[Tooltip("相机的视野角度")]
public float fieldOfView = 60f;
[Header("【模型设置】")]
[Tooltip("模型的初始旋转")]
public Vector3 modelInitialRotation = Vector3.zero;
[Tooltip("模型的初始缩放")]
public Vector3 modelInitialScale = Vector3.one;
[Header("【平滑设置】")]
[Tooltip("旋转平滑度")]
public float rotationSmoothness = 10.0f;
[Tooltip("缩放平滑度")]
public float zoomSmoothness = 10.0f;
[Tooltip("平移平滑度")]
public float panSmoothness = 10.0f;
// 内部变量
private GameObject displayedModel;
private Transform modelTransform;
private Vector3 modelCenter; // 模型中心点
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 bool isDragging = false;
private bool isPanning = false;
private float childCurrentDistance = 3.0f;
private float childTargetDistance = 3.0f;
void Start()
{
//InitializeModelViewer();
}
void Update()
{
if (displayedModel != null)
{
HandleInput();
UpdateModelPosition();
}
}
///
/// 初始化模型
///
private void InitializeModelViewer()
{
if (modelPrefab == null)
{
Debug.LogWarning("RawImageModelViewer: 未指定模型预制件", this);
return;
}
if (displayImage == null || renderTexture == null || renderCamera == null)
{
Debug.LogWarning("RawImageModelViewer: 请设置必要的UI组件", this);
return;
}
if (renderCamera == null)
{
Debug.LogWarning("RawImageModelViewer: 未指定相机", this);
return;
}
displayedModel = Instantiate(modelPrefab, modelCenter, Quaternion.Euler(modelPrefab.transform.eulerAngles));
Debug.Log(modelPrefab.transform.eulerAngles);
modelTransform = displayedModel.transform;
MonoBehaviour[] scripts = displayedModel.GetComponentsInChildren();
foreach (MonoBehaviour script in scripts)
{
Destroy(script);
}
MeshRenderer[] meshRenderers = displayedModel.GetComponentsInChildren();
foreach (MeshRenderer meshRenderer in meshRenderers)
{
meshRenderer.SetLayer(6);
}
renderCamera.targetTexture = renderTexture;
renderCamera.fieldOfView = fieldOfView;
displayImage.texture = renderTexture;
Bounds bounds = CalculateBounds(displayedModel);
modelCenter = bounds.center;
/*float objectSize = Mathf.Max(modelCenter.x, modelCenter.y, modelCenter.z);
targetDistance = objectSize * 1.5f;
targetDistance = Mathf.Clamp(childTargetDistance, minZoomDistance, maxZoomDistance);
currentDistance = targetDistance;
Vector3 toCamera = (renderCamera.transform.position - modelCenter).normalized;
targetRotation.x = Mathf.Atan2(toCamera.x, toCamera.z) * Mathf.Rad2Deg;
targetRotation.y = Mathf.Asin(toCamera.y) * Mathf.Rad2Deg;*/
ResetView();
}
private void HandleInput()
{
if (IsMouseOverRawImage())
{
// 旋转控制
if (enableRotation)
{
if (Input.GetMouseButtonDown(0))
{
isDragging = true;
lastMousePosition = Input.mousePosition;
}
if (Input.GetMouseButton(0) && isDragging)
{
Vector3 delta = Input.mousePosition - lastMousePosition;
targetRotation.y += delta.x * rotationSpeed * 0.01f;
targetRotation.x -= delta.y * rotationSpeed * 0.01f;
// 限制垂直旋转角度
targetRotation.x = Mathf.Clamp(targetRotation.x, verticalAngleLimit.x, verticalAngleLimit.y);
lastMousePosition = Input.mousePosition;
}
if (Input.GetMouseButtonUp(0))
{
isDragging = false;
}
}
// 平移控制
if (enablePan)
{
if (Input.GetMouseButtonDown(2))
{
isPanning = true;
lastMousePosition = Input.mousePosition;
}
if (Input.GetMouseButton(2) && isPanning)
{
Vector3 delta = Input.mousePosition - lastMousePosition;
Vector3 right = renderCamera.transform.right;
Vector3 up = renderCamera.transform.up;
right.y = 0;
up.y = 0;
// 应用平移限制
Vector3 panDelta = (right * delta.x + up * delta.y) * panSpeed * -0.01f;
ApplyPanWithLimits(panDelta);
lastMousePosition = Input.mousePosition;
}
if (Input.GetMouseButtonUp(2))
{
isPanning = false;
}
}
// 缩放控制
if (enableZoom)
{
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.F))
{
FocusOnModel();
}
}
}
///
/// 更新相机位置
///
private void UpdateModelPosition()
{
// 旋转
currentRotation = Vector3.Lerp(currentRotation, targetRotation, Time.deltaTime * rotationSmoothness);
// 缩放
currentDistance = Mathf.Lerp(currentDistance, targetDistance, Time.deltaTime * zoomSmoothness);
// 平移
currentTargetPositionOffset = Vector3.Lerp(currentTargetPositionOffset, targetPositionOffset, Time.deltaTime * panSmoothness);
// 计算旋转后的相机偏移
Vector3 rotatedOffset = Quaternion.Euler(currentRotation) * cameraOffset.normalized * currentDistance;
Vector3 cameraPosition = modelCenter + currentTargetPositionOffset + rotatedOffset;
//childCurrentDistance = childTargetDistance;
renderCamera.transform.position = cameraPosition;
renderCamera.transform.LookAt(modelCenter + currentTargetPositionOffset);
}
///
/// 检测鼠标
///
private bool IsMouseOverRawImage()
{
if (displayImage == null) return false;
RectTransform rectTransform = displayImage.rectTransform;
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
rectTransform, Input.mousePosition, transform.root.GetComponent