372 lines
11 KiB
C#
372 lines
11 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using System.Collections;
|
||
|
||
/// <summary>
|
||
/// RawImage模型控制器
|
||
/// 功能:在RawImage上显示3D模型,并支持旋转和缩放操作
|
||
/// </summary>
|
||
public class RawImageModelController : MonoBehaviour
|
||
{
|
||
[Header("【模型设置】")]
|
||
[Tooltip("要显示的3D模型")]
|
||
[SerializeField] private GameObject model;
|
||
|
||
[Header("【UI组件】")]
|
||
[Tooltip("显示模型的RawImage组件")]
|
||
[SerializeField] private RawImage displayImage;
|
||
[Tooltip("渲染模型的相机")]
|
||
[SerializeField] private Camera renderCamera;
|
||
[Tooltip("渲染纹理,相机将画面渲染到此,再由RawImage显示")]
|
||
[SerializeField] private RenderTexture renderTexture;
|
||
|
||
[Header("【控制设置】")]
|
||
[Tooltip("旋转速度")]
|
||
[SerializeField] private float rotationSpeed = 2.0f;
|
||
[Tooltip("缩放速度")]
|
||
[SerializeField] private float zoomSpeed = 0.5f;
|
||
[Tooltip("最小缩放值")]
|
||
[SerializeField] private float minZoom = 0.5f;
|
||
[Tooltip("最大缩放值")]
|
||
[SerializeField] private float maxZoom = 3.0f;
|
||
[Tooltip("默认缩放值")]
|
||
[SerializeField] private float defaultZoom = 1.0f;
|
||
|
||
[Header("【相机设置】")]
|
||
[Tooltip("相机相对于模型的初始偏移")]
|
||
[SerializeField] private Vector3 cameraOffset = new Vector3(0, 0, 5);
|
||
[Tooltip("相机视野")]
|
||
[SerializeField] private float fieldOfView = 60f;
|
||
|
||
[Header("【初始变换】")]
|
||
[Tooltip("模型的初始旋转")]
|
||
[SerializeField] private Vector3 initialRotation = Vector3.zero;
|
||
[Tooltip("模型的初始缩放")]
|
||
[SerializeField] private Vector3 initialScale = Vector3.one;
|
||
|
||
// 内部状态变量
|
||
private Vector2 currentRotation = Vector2.zero;
|
||
private float currentZoom = 1.0f;
|
||
private float targetZoom = 1.0f;
|
||
private Vector2 lastMousePosition;
|
||
private bool isDragging = false;
|
||
private bool isInitialized = false;
|
||
|
||
/// <summary>
|
||
/// 设置要显示的模型
|
||
/// </summary>
|
||
/// <param name="modelObj">要显示的模型对象</param>
|
||
public void SetModel(GameObject modelObj)
|
||
{
|
||
model = modelObj;
|
||
if (model != null)
|
||
{
|
||
InitializeModel();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前显示的模型
|
||
/// </summary>
|
||
/// <returns>当前模型对象</returns>
|
||
public GameObject GetModel()
|
||
{
|
||
return model;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化组件
|
||
/// </summary>
|
||
void Start()
|
||
{
|
||
Initialize();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化所有组件
|
||
/// </summary>
|
||
private void Initialize()
|
||
{
|
||
if (isInitialized) return;
|
||
|
||
// 验证必要组件
|
||
if (displayImage == null)
|
||
{
|
||
Debug.LogError("RawImageModelController: 未设置Display Image组件!", this);
|
||
return;
|
||
}
|
||
|
||
if (renderCamera == null)
|
||
{
|
||
Debug.LogError("RawImageModelController: 未设置Render Camera!", this);
|
||
return;
|
||
}
|
||
|
||
if (renderTexture == null)
|
||
{
|
||
Debug.LogError("RawImageModelController: 未设置Render Texture!", this);
|
||
return;
|
||
}
|
||
|
||
// 配置渲染相机
|
||
ConfigureRenderCamera();
|
||
|
||
// 设置RawImage的纹理
|
||
displayImage.texture = renderTexture;
|
||
|
||
// 如果已有模型,则初始化
|
||
if (model != null)
|
||
{
|
||
InitializeModel();
|
||
}
|
||
|
||
// 设置初始状态
|
||
currentZoom = defaultZoom;
|
||
targetZoom = defaultZoom;
|
||
currentRotation = new Vector2(initialRotation.y, -initialRotation.x);
|
||
|
||
isInitialized = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 配置渲染相机
|
||
/// </summary>
|
||
private void ConfigureRenderCamera()
|
||
{
|
||
renderCamera.targetTexture = renderTexture;
|
||
renderCamera.fieldOfView = fieldOfView;
|
||
renderCamera.enabled = true; // 默认启用相机
|
||
|
||
// 设置相机的初始位置
|
||
if (model != null)
|
||
{
|
||
renderCamera.transform.position = model.transform.position + cameraOffset;
|
||
renderCamera.transform.LookAt(model.transform);
|
||
}
|
||
else
|
||
{
|
||
renderCamera.transform.position = cameraOffset;
|
||
renderCamera.transform.LookAt(Vector3.zero);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化模型
|
||
/// </summary>
|
||
private void InitializeModel()
|
||
{
|
||
if (model == null) return;
|
||
|
||
// 设置模型的初始状态
|
||
model.transform.localRotation = Quaternion.Euler(initialRotation);
|
||
model.transform.localScale = initialScale;
|
||
|
||
// 将相机定位到模型前方
|
||
renderCamera.transform.position = model.transform.position + cameraOffset;
|
||
renderCamera.transform.LookAt(model.transform);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 每帧更新
|
||
/// </summary>
|
||
void Update()
|
||
{
|
||
if (!isInitialized || model == null) return;
|
||
|
||
HandleInput();
|
||
UpdateModelTransform();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理用户输入
|
||
/// </summary>
|
||
private void HandleInput()
|
||
{
|
||
// 检查鼠标是否在RawImage区域内
|
||
if (IsMouseOverDisplayImage())
|
||
{
|
||
// 旋转控制(鼠标左键拖拽)
|
||
if (Input.GetMouseButtonDown(0))
|
||
{
|
||
isDragging = true;
|
||
lastMousePosition = Input.mousePosition;
|
||
}
|
||
|
||
if (Input.GetMouseButton(0) && isDragging)
|
||
{
|
||
Vector2 currentMousePos = Input.mousePosition;
|
||
Vector2 delta = currentMousePos - lastMousePosition;
|
||
|
||
// 根据鼠标移动增量更新旋转角度
|
||
currentRotation.x += delta.y * rotationSpeed * 0.1f; // 绕X轴旋转
|
||
currentRotation.y -= delta.x * rotationSpeed * 0.1f; // 绕Y轴旋转
|
||
|
||
// 限制垂直旋转角度,避免过度翻转
|
||
currentRotation.x = Mathf.Clamp(currentRotation.x, -85f, 85f);
|
||
|
||
lastMousePosition = currentMousePos;
|
||
}
|
||
|
||
if (Input.GetMouseButtonUp(0))
|
||
{
|
||
isDragging = false;
|
||
}
|
||
|
||
// 缩放控制(鼠标滚轮)
|
||
float scroll = Input.GetAxis("Mouse ScrollWheel");
|
||
if (Mathf.Abs(scroll) > 0.01f)
|
||
{
|
||
// 根据滚轮方向调整目标缩放值
|
||
targetZoom -= scroll * zoomSpeed;
|
||
targetZoom = Mathf.Clamp(targetZoom, minZoom, maxZoom);
|
||
}
|
||
}
|
||
|
||
// 重置视图(R键)
|
||
if (Input.GetKeyDown(KeyCode.R))
|
||
{
|
||
ResetView();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检测鼠标是否在显示图像的区域内
|
||
/// </summary>
|
||
/// <returns>如果鼠标在区域内返回true,否则返回false</returns>
|
||
private bool IsMouseOverDisplayImage()
|
||
{
|
||
if (displayImage == null) return false;
|
||
|
||
RectTransform rect = displayImage.rectTransform;
|
||
Vector2 localPoint;
|
||
|
||
// 将屏幕鼠标坐标转换为UI矩形内的本地坐标
|
||
return RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||
rect, Input.mousePosition, null, out localPoint)
|
||
&& rect.rect.Contains(localPoint);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新模型的变换
|
||
/// </summary>
|
||
private void UpdateModelTransform()
|
||
{
|
||
if (model == null) return;
|
||
|
||
// 平滑插值缩放
|
||
currentZoom = Mathf.Lerp(currentZoom, targetZoom, 5f * Time.deltaTime);
|
||
|
||
// 应用旋转
|
||
Quaternion targetRotation = Quaternion.Euler(currentRotation.x, currentRotation.y, 0);
|
||
model.transform.rotation = targetRotation;
|
||
|
||
// 应用缩放
|
||
model.transform.localScale = initialScale * currentZoom;
|
||
|
||
// 更新相机位置以保持相对距离
|
||
Vector3 cameraDirection = (renderCamera.transform.position - model.transform.position).normalized;
|
||
Vector3 targetCameraPosition = model.transform.position + cameraDirection * (cameraOffset.magnitude * currentZoom);
|
||
renderCamera.transform.position = targetCameraPosition;
|
||
renderCamera.transform.LookAt(model.transform);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置视图到初始状态
|
||
/// </summary>
|
||
public void ResetView()
|
||
{
|
||
currentRotation = new Vector2(initialRotation.y, -initialRotation.x);
|
||
currentZoom = defaultZoom;
|
||
targetZoom = defaultZoom;
|
||
|
||
if (model != null)
|
||
{
|
||
model.transform.localRotation = Quaternion.Euler(initialRotation);
|
||
model.transform.localScale = initialScale;
|
||
}
|
||
|
||
// 重置相机位置
|
||
if (model != null)
|
||
{
|
||
renderCamera.transform.position = model.transform.position + cameraOffset;
|
||
renderCamera.transform.LookAt(model.transform);
|
||
}
|
||
else
|
||
{
|
||
renderCamera.transform.position = cameraOffset;
|
||
renderCamera.transform.LookAt(Vector3.zero);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置旋转速度
|
||
/// </summary>
|
||
/// <param name="speed">新的旋转速度</param>
|
||
public void SetRotationSpeed(float speed)
|
||
{
|
||
rotationSpeed = speed;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置缩放速度
|
||
/// </summary>
|
||
/// <param name="speed">新的缩放速度</param>
|
||
public void SetZoomSpeed(float speed)
|
||
{
|
||
zoomSpeed = speed;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置缩放限制
|
||
/// </summary>
|
||
/// <param name="min">最小缩放值</param>
|
||
/// <param name="max">最大缩放值</param>
|
||
public void SetZoomLimits(float min, float max)
|
||
{
|
||
minZoom = min;
|
||
maxZoom = max;
|
||
targetZoom = Mathf.Clamp(targetZoom, minZoom, maxZoom);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前缩放值
|
||
/// </summary>
|
||
/// <returns>当前缩放值</returns>
|
||
public float GetCurrentZoom()
|
||
{
|
||
return currentZoom;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置当前缩放值
|
||
/// </summary>
|
||
/// <param name="zoom">目标缩放值</param>
|
||
public void SetZoom(float zoom)
|
||
{
|
||
targetZoom = Mathf.Clamp(zoom, minZoom, maxZoom);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启用/禁用控制器
|
||
/// </summary>
|
||
/// <param name="enabled">是否启用</param>
|
||
public void SetEnabled(bool enabled)
|
||
{
|
||
gameObject.SetActive(enabled);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在编辑器中绘制调试信息
|
||
/// </summary>
|
||
void OnValidate()
|
||
{
|
||
if (renderCamera != null)
|
||
{
|
||
// 确保相机设置正确
|
||
if (fieldOfView > 0)
|
||
{
|
||
renderCamera.fieldOfView = fieldOfView;
|
||
}
|
||
}
|
||
}
|
||
} |