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().worldCamera, out localPoint); return rectTransform.rect.Contains(localPoint); } /// /// 限制平移 /// private void ApplyPanWithLimits(Vector3 panDelta) { Vector3 newOffset = targetPositionOffset - panDelta; // 限制平移范围 newOffset.x = Mathf.Clamp(newOffset.x, -maxPanDistanceX, maxPanDistanceX); newOffset.z = Mathf.Clamp(newOffset.z, -maxPanDistanceZ, maxPanDistanceZ); targetPositionOffset = newOffset; } /// /// 重置视图 /// public void ResetView() { //targetRotation = modelInitialRotation; targetRotation = new Vector3(20,130,0); targetDistance = 1.0f; targetPositionOffset = Vector3.zero; } /// /// 聚焦到模型中心 /// public void FocusOnModel() { if (modelTransform != null) { targetPositionOffset = Vector3.zero; } } /// /// 更换模型 /// public void ChangeModel(GameObject newModelPrefab) { if (newModelPrefab == null) return; // 销毁当前模型 if (displayedModel != null) { DestroyImmediate(displayedModel); } // 创建新模型 modelPrefab = newModelPrefab; InitializeModelViewer(); } /// /// 设置模型的旋转 /// public void SetModelRotation(Vector3 rotation) { if (modelTransform != null) { modelTransform.localRotation = Quaternion.Euler(rotation); currentRotation = rotation; targetRotation = rotation; } } /// /// 设置模型的缩放 /// public void SetModelScale(Vector3 scale) { if (modelTransform != null) { modelTransform.localScale = scale; } } /// /// 设置相机的缩放距离 /// public void SetZoomDistance(float distance) { targetDistance = Mathf.Clamp(distance, minZoomDistance, maxZoomDistance); } /// /// 设置是否启用旋转功能 /// public void SetEnableRotation(bool enable) { enableRotation = enable; } /// /// 设置是否启用缩放功能 /// public void SetEnableZoom(bool enable) { enableZoom = enable; } /// /// 设置是否启用平移功能 /// public void SetEnablePan(bool enable) { enablePan = enable; } /// /// 设置平移限制 /// public void SetPanLimits(float maxX, float maxZ) { maxPanDistanceX = Mathf.Max(0, maxX); maxPanDistanceZ = Mathf.Max(0, maxZ); } private Bounds CalculateBounds(GameObject obj) { Renderer[] renderers = obj.GetComponentsInChildren(); if (renderers.Length == 0) { return new Bounds(obj.transform.position, Vector3.one); } Bounds bounds = renderers[0].bounds; foreach (Renderer renderer in renderers) { bounds.Encapsulate(renderer.bounds); } return bounds; } void OnDestroy() { if (displayedModel != null) { DestroyImmediate(displayedModel); } } }