using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.UI; using UnityEngine.EventSystems; public class EnhancedModelViewerOrbitCamera : MonoBehaviour { [Header("观察目标")] [SerializeField] private Transform target; // 要观察的模型 public Transform GetTarget() { return target; } [Header("基础控制开关")] [SerializeField] private bool enableClickToFocus = true; // 是否启用点击子物体聚焦功能 [SerializeField] private bool enableRotation = true; // 是否启用旋转功能 [SerializeField] private bool enablePan = true; // 是否启用平移功能 [SerializeField] private bool enableZoom = true; // 是否启用缩放功能 [SerializeField] private bool enableAutoRotation = false; // 是否启用自动旋转 [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 float maxPanDistanceX = 5.0f; // X轴最大平移距离 [SerializeField] private float maxPanDistanceZ = 5.0f; // Z轴最大平移距离 [SerializeField] private bool showPanBoundary = true; // 是否显示平移边界 [Header("子物体复制体父级")] [SerializeField] private Transform childInstanceParent; // 子物体复制体的父级 [Header("子物体观察模式 - 层级设置")] [SerializeField] private LayerMask selectableLayers = -1; // 可选择图层 [SerializeField] private LayerMask excludedLayers = 0; // 要排除的图层 [Header("子物体观察模式 - 物体类型排除")] [SerializeField] private bool excludeCameras = true; // 是否排除摄像机 [SerializeField] private bool excludeLights = true; // 是否排除灯光 [SerializeField] private bool excludeUI = true; // 是否排除UI元素 [SerializeField] private string[] excludeTags = { "MainCamera", "Light", "UI" }; // 要排除的标签 [SerializeField] private float childMinZoomDistance = 0.5f; // 观察子物体时的最小缩放距离 [SerializeField] private float childMaxZoomDistance = 10.0f; // 观察子物体时的最大缩放距离 [SerializeField] private Color highlightColor = new Color(1f, 0.5f, 0f, 0.3f); // 高亮颜色 [SerializeField] private float highlightFadeSpeed = 5.0f; // 高亮淡出速度 [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 bool isObservingChild = false; private GameObject currentObservedChild = null; private GameObject childInstance = null; // 子物体观察模式下的缩放距离 private float childCurrentDistance = 3.0f; private float childTargetDistance = 3.0f; // 高亮相关 private Renderer[] highlightedRenderers = null; private List originalMaterials = new List(); private List highlightMaterials = new List(); private float highlightTimer = 0f; // 保存原始状态 private Vector3 savedTargetPositionOffset = Vector3.zero; private Vector3 savedTargetRotation = Vector3.zero; private float savedTargetDistance = 5.0f; private float savedCurrentDistance = 5.0f; private bool savedEnableAutoRotation = false; public bool isOpenOnGUI = false; /// /// 当开始观察子物体时触发。参数1: 克隆体, 参数2: 原始物体 /// public System.Action OnChildObservationStarted; /// /// 当结束观察子物体时触发。参数1: 克隆体 (可能为null), 参数2: 原始物体 /// public System.Action OnChildObservationEnded; private enum MouseButton { Left = 0, Right = 1, Middle = 2 } void LateUpdate() { if (target == null) return; if (EventSystem.current.IsPointerOverGameObject()) return; HandleInput(); UpdateCameraPosition(); // 更新高亮效果 UpdateHighlight(); } private void HandleInput() { HandleDesktopInput(); HandleTouchInput(); // 处理子物体观察模式切换 HandleChildObservationMode(); } private void HandleChildObservationMode() { // 按左Shift键退出子物体观察模式 if (Input.GetKeyDown(KeyCode.LeftShift) || Input.GetKeyDown(KeyCode.RightShift)) { ExitChildObservationMode(); } } private void HandleDesktopInput() { // 点击选择子物体 if (enableClickToFocus && Input.GetMouseButtonDown(0) && !isObservingChild) { HandleObjectClick(); } // 在子物体观察模式下,允许旋转和缩放 if (isObservingChild) { if (enableRotation) HandleRotationInput(); if (enableZoom) HandleZoomInput(); } else { // 正常模式下的所有输入 if (enableRotation) HandleRotationInput(); if (enablePan) HandlePanInput(); if (enableZoom) HandleZoomInput(); } // 重置按钮 if (Input.GetKeyDown(KeyCode.R)) { ResetView(); } /* // 自动旋转切换 if (Input.GetKeyDown(KeyCode.A)) { ToggleAutoRotation(!enableAutoRotation); }*/ // 聚焦到模型 if (Input.GetKeyDown(KeyCode.F)) { FocusOnModel(); } } private void HandleObjectClick() { if (!enableClickToFocus) return; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; // 执行射线检测,使用可选择图层 if (Physics.Raycast(ray, out hit, Mathf.Infinity, selectableLayers)) { GameObject hitObject = hit.collider.gameObject; // 检查是否在排除的图层中 if (IsInExcludedLayers(hitObject)) { Debug.Log($"跳过:物体 {hitObject.name} 在排除的图层中"); return; } // 检查是否是要排除的物体类型 if (ShouldExcludeObject(hitObject)) { Debug.Log($"跳过:物体 {hitObject.name} 是需要排除的类型"); return; } // 检查是否点击了目标或目标的子物体 if (hit.collider.transform == target || IsChildOfTarget(hit.collider.transform)) { StartObservingChild(hitObject); } } } private bool IsInExcludedLayers(GameObject obj) { // 检查物体是否在排除的图层中 int layerMask = 1 << obj.layer; return (excludedLayers.value & layerMask) != 0; } private bool ShouldExcludeObject(GameObject obj) { // 检查是否需要排除摄像机 if (excludeCameras && obj.GetComponent() != null) { return true; } // 检查是否需要排除灯光 if (excludeLights && obj.GetComponent() != null) { return true; } // 检查是否需要排除UI元素 if (excludeUI && (obj.GetComponent() != null || obj.GetComponent() != null)) { return true; } // 检查是否有要排除的标签 foreach (string tag in excludeTags) { if (obj.CompareTag(tag)) { return true; } } return false; } private bool IsChildOfTarget(Transform child) { Transform parent = child.parent; while (parent != null) { if (parent == target) { return true; } parent = parent.parent; } return false; } private void HandleRotationInput() { if (!enableRotation) return; if (Input.GetMouseButton((int)rotateButton)) { float horizontal = Input.GetAxis("Mouse X") * rotationSpeed * mouseSensitivity; float vertical = -Input.GetAxis("Mouse Y") * rotationSpeed * mouseSensitivity; if (isObservingChild) { // 子物体观察模式:旋转相机 targetRotation.x += horizontal; targetRotation.y += vertical; } else { // 正常模式:旋转相机 targetRotation.x += horizontal; targetRotation.y += vertical; } targetRotation.y = Mathf.Clamp(targetRotation.y, verticalAngleLimit.x, verticalAngleLimit.y); enableAutoRotation = false; } } private void HandlePanInput() { if (!enablePan) return; if (!isObservingChild && 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; Vector3 panDelta = (right * delta.x + up * delta.y) * panSpeed * 0.01f; ApplyPanWithLimits(panDelta); lastPanPosition = Input.mousePosition; } } private void HandleZoomInput() { if (!enableZoom) return; float scroll = Input.GetAxis("Mouse ScrollWheel"); if (Mathf.Abs(scroll) > 0.01f) { if (isObservingChild) { // 子物体观察模式:调整子物体观察距离 childTargetDistance -= scroll * zoomSpeed; childTargetDistance = Mathf.Clamp(childTargetDistance, childMinZoomDistance, childMaxZoomDistance); } else { // 正常模式:调整模型观察距离 targetDistance -= scroll * zoomSpeed; targetDistance = Mathf.Clamp(targetDistance, minZoomDistance, maxZoomDistance); } } } private void ApplyPanWithLimits(Vector3 panDelta) { Vector3 newOffset = targetPositionOffset - panDelta; newOffset.x = Mathf.Clamp(newOffset.x, -maxPanDistanceX, maxPanDistanceZ); newOffset.z = Mathf.Clamp(newOffset.z, -maxPanDistanceZ, maxPanDistanceZ); targetPositionOffset = newOffset; } 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; if (isObservingChild) { childTargetDistance += deltaMagnitudeDiff * zoomSpeed * 0.01f; childTargetDistance = Mathf.Clamp(childTargetDistance, childMinZoomDistance, childMaxZoomDistance); } else { targetDistance += deltaMagnitudeDiff * zoomSpeed * 0.01f; targetDistance = Mathf.Clamp(targetDistance, minZoomDistance, maxZoomDistance); } } #endif } private void StartObservingChild(GameObject child) { if (isObservingChild || !enableClickToFocus) return; /* target.gameObject.SetActive(false); // 保存当前状态 savedTargetPositionOffset = targetPositionOffset; savedTargetRotation = targetRotation; savedTargetDistance = targetDistance; savedCurrentDistance = currentDistance; savedEnableAutoRotation = enableAutoRotation; currentObservedChild = child; originalTargetPosition = target.position; originalChildPosition = child.transform.position; originalChildRotation = child.transform.rotation; originalParent = child.transform.parent; // 计算子物体的包围盒 Bounds bounds = CalculateBounds(child); Vector3 childCenter = bounds.center; // 复制子物体 childInstance = Instantiate(child, childCenter, child.transform.rotation); //childInstance.transform.SetLocalPositionAndRotation(default, default); // 删除所有子物体上的脚本,避免干扰 MonoBehaviour[] scripts = childInstance.GetComponentsInChildren(); foreach (MonoBehaviour script in scripts) { Destroy(script); } // 隐藏原来的子物体 //child.SetActive(false); // 高亮显示复制出的物体 HighlightObject(childInstance); // 计算适合观察的距离 float objectSize = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z); childTargetDistance = objectSize * 1.5f; childTargetDistance = Mathf.Clamp(childTargetDistance, childMinZoomDistance, childMaxZoomDistance); childCurrentDistance = childTargetDistance; // 设置子物体观察模式参数 isObservingChild = true; targetDistance = childTargetDistance; currentDistance = childTargetDistance; targetPositionOffset = Vector3.zero; enableAutoRotation = false; // 将相机对准子物体中心 Vector3 toCamera = (transform.position - childCenter).normalized; targetRotation.x = Mathf.Atan2(toCamera.x, toCamera.z) * Mathf.Rad2Deg; targetRotation.y = Mathf.Asin(toCamera.y) * Mathf.Rad2Deg; Debug.Log($"开始观察子物体: {child.name}"); // --- 新增:触发开始观察事件 --- if (OnChildObservationStarted != null) { OnChildObservationStarted(childInstance, child); } */ if (SK.Framework.UIView.Get()) { SK.Framework.UIView.Show().ShowDeviceInformation(child); } else { SK.Framework.UIView.Load(SK.Framework.ViewLevel.POP).ShowDeviceInformation(child); } } 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; } private void HighlightObject(GameObject obj) { // 获取所有渲染器 highlightedRenderers = obj.GetComponentsInChildren(); // 保存原始材质并创建高亮材质 originalMaterials.Clear(); highlightMaterials.Clear(); foreach (Renderer renderer in highlightedRenderers) { Material[] originalMats = renderer.materials; originalMaterials.Add(originalMats); Material[] highlightMats = new Material[originalMats.Length]; for (int i = 0; i < originalMats.Length; i++) { Material highlightMat = new Material(originalMats[i]); highlightMat.EnableKeyword("_EMISSION"); highlightMat.SetColor("_EmissionColor", highlightColor); highlightMats[i] = highlightMat; } highlightMaterials.Add(highlightMats); renderer.materials = highlightMats; } highlightTimer = 0f; } private void UpdateHighlight() { if (highlightedRenderers == null || highlightTimer >= 1f) return; highlightTimer += Time.deltaTime * highlightFadeSpeed; // 渐变高亮效果 for (int i = 0; i < highlightedRenderers.Length; i++) { Renderer renderer = highlightedRenderers[i]; Material[] highlightMats = highlightMaterials[i]; for (int j = 0; j < highlightMats.Length; j++) { if (highlightMats[j] != null) { Color emissionColor = Color.Lerp(highlightColor, Color.black, highlightTimer); highlightMats[j].SetColor("_EmissionColor", emissionColor); } } renderer.materials = highlightMats; } // 高亮结束后清理 if (highlightTimer >= 1f) { RestoreOriginalMaterials(); } } private void RestoreOriginalMaterials() { if (highlightedRenderers != null) { for (int i = 0; i < highlightedRenderers.Length; i++) { if (highlightedRenderers[i] != null && i < originalMaterials.Count) { highlightedRenderers[i].materials = originalMaterials[i]; } } } highlightedRenderers = null; originalMaterials.Clear(); highlightMaterials.Clear(); } private void ExitChildObservationMode() { if (!isObservingChild) return; // 删除复制的物体 if (childInstance != null) { Destroy(childInstance); childInstance = null; } // 恢复原子物体的显示 if (currentObservedChild != null) { currentObservedChild.SetActive(true); } // 恢复原始状态 targetPositionOffset = savedTargetPositionOffset; targetRotation = savedTargetRotation; targetDistance = savedTargetDistance; currentDistance = savedCurrentDistance; enableAutoRotation = savedEnableAutoRotation; // 触发结束观察事件 (在清理引用前) if (OnChildObservationEnded != null) { OnChildObservationEnded(childInstance, currentObservedChild); } // 重置状态 isObservingChild = false; currentObservedChild = null; // 恢复原始高亮材质 RestoreOriginalMaterials(); target.gameObject.SetActive(true); Debug.Log("退出子物体观察模式"); } private void UpdateCameraPosition() { if (enableAutoRotation && !isObservingChild) { targetRotation.x += autoRotationSpeed; } // 平滑旋转 currentRotation = Vector3.Lerp(currentRotation, targetRotation, rotationSmoothness * Time.deltaTime); if (isObservingChild) { // 子物体观察模式:平滑子物体观察距离 childCurrentDistance = Mathf.Lerp(childCurrentDistance, childTargetDistance, rotationSmoothness * Time.deltaTime); currentDistance = childCurrentDistance; } else { // 正常模式:平滑模型观察距离 currentDistance = Mathf.Lerp(currentDistance, targetDistance, rotationSmoothness * Time.deltaTime); } // 在子物体观察模式下,不更新平移偏移 if (!isObservingChild) { currentTargetPositionOffset = Vector3.Lerp(currentTargetPositionOffset, targetPositionOffset, rotationSmoothness * Time.deltaTime); } Quaternion rotation = Quaternion.Euler(currentRotation.y, currentRotation.x, 0); // 计算观察中心 Vector3 lookAtPoint = target.position; if (isObservingChild && childInstance != null) { lookAtPoint = childInstance.transform.position; } else { lookAtPoint += currentTargetPositionOffset; } Vector3 position = rotation * new Vector3(0, 0, -currentDistance) + lookAtPoint; transform.position = position; transform.LookAt(lookAtPoint); } public void ResetView() { if (isObservingChild) { ExitChildObservationMode(); } targetRotation = new Vector3(0, 45f, 0); targetDistance = defaultZoomDistance; targetPositionOffset = Vector3.zero; enableAutoRotation = false; } public void FocusOnModel() { if (target != null) { targetPositionOffset = Vector3.zero; } } public void SetTarget(Transform newTarget) { target = newTarget; ResetView(); } public void SetTarget(GameObject newTarget) { if (newTarget != null) { target = newTarget.transform; ResetView(); } } public void SetTargetOffset(Vector3 offset) { targetPositionOffset = new Vector3( Mathf.Clamp(offset.x, -maxPanDistanceX, maxPanDistanceZ), offset.y, Mathf.Clamp(offset.z, -maxPanDistanceZ, maxPanDistanceZ) ); } public void SetZoomDistance(float distance) { if (isObservingChild) { childTargetDistance = Mathf.Clamp(distance, childMinZoomDistance, childMaxZoomDistance); } else { targetDistance = Mathf.Clamp(distance, minZoomDistance, maxZoomDistance); } } public void SetRotation(float horizontal, float vertical) { targetRotation = new Vector3(horizontal, Mathf.Clamp(vertical, verticalAngleLimit.x, verticalAngleLimit.y), 0); } public void ToggleAutoRotation(bool enable) { enableAutoRotation = enable; } public void SetAutoRotationSpeed(float speed) { autoRotationSpeed = speed; } public void SetPanLimits(float maxX, float maxZ) { maxPanDistanceX = Mathf.Max(0, maxX); maxPanDistanceZ = Mathf.Max(0, maxZ); } public float GetCurrentZoomDistance() { return isObservingChild ? childCurrentDistance : currentDistance; } public Vector3 GetCurrentPanOffset() { return currentTargetPositionOffset; } public bool IsObservingChild() { return isObservingChild; } public GameObject GetCurrentObservedChild() { return currentObservedChild; } public void AddExcludedTag(string tag) { if (!System.Array.Exists(excludeTags, t => t == tag)) { System.Array.Resize(ref excludeTags, excludeTags.Length + 1); excludeTags[excludeTags.Length - 1] = tag; } } public void RemoveExcludedTag(string tag) { int index = System.Array.IndexOf(excludeTags, tag); if (index >= 0) { for (int i = index; i < excludeTags.Length - 1; i++) { excludeTags[i] = excludeTags[i + 1]; } System.Array.Resize(ref excludeTags, excludeTags.Length - 1); } } // 新增的公共方法,用于外部控制功能开关 public void SetEnableClickToFocus(bool enable) { enableClickToFocus = enable; if (!enable && isObservingChild) { ExitChildObservationMode(); } } public bool GetEnableClickToFocus() { return enableClickToFocus; } public void SetEnableRotation(bool enable) { enableRotation = enable; } public bool GetEnableRotation() { return enableRotation; } public void SetEnablePan(bool enable) { enablePan = enable; } public bool GetEnablePan() { return enablePan; } public void SetEnableZoom(bool enable) { enableZoom = enable; } public bool GetEnableZoom() { return enableZoom; } void OnGUI() { if (Application.isEditor && isOpenOnGUI) { int yOffset = 10; GUI.Label(new Rect(10, yOffset, 300, 20), $"上帝视角观察器 - 模型查看器"); yOffset += 20; if (target != null) { GUI.Label(new Rect(10, yOffset, 300, 20), $"目标: {target.name}"); } else { GUI.Label(new Rect(10, yOffset, 300, 20), "目标: 未设置 (请在Inspector中指定)"); } yOffset += 20; if (isObservingChild && currentObservedChild != null) { GUI.Label(new Rect(10, yOffset, 300, 20), $"正在观察: {currentObservedChild.name} (子物体模式)"); yOffset += 20; } GUI.Label(new Rect(10, yOffset, 300, 20), $"旋转: ({currentRotation.x:F1}, {currentRotation.y:F1})"); yOffset += 20; GUI.Label(new Rect(10, yOffset, 300, 20), $"距离: {GetCurrentZoomDistance():F1} (范围: {minZoomDistance:F1}-{maxZoomDistance:F1})"); yOffset += 20; if (!isObservingChild) { GUI.Label(new Rect(10, yOffset, 300, 20), $"平移偏移: X={currentTargetPositionOffset.x:F2}, Z={currentTargetPositionOffset.z:F2}"); yOffset += 20; GUI.Label(new Rect(10, yOffset, 300, 20), $"平移限制: X=±{maxPanDistanceX:F1}, Z=±{maxPanDistanceZ:F1}"); yOffset += 20; } GUI.Label(new Rect(10, yOffset, 300, 20), $"自动旋转: {(enableAutoRotation ? "开" : "关")}"); yOffset += 20; GUI.Label(new Rect(10, yOffset, 300, 20), $"点击聚焦: {(enableClickToFocus ? "开" : "关")}"); yOffset += 20; GUI.Label(new Rect(10, yOffset, 300, 20), $"旋转功能: {(enableRotation ? "开" : "关")}"); yOffset += 20; GUI.Label(new Rect(10, yOffset, 300, 20), $"平移功能: {(enablePan ? "开" : "关")}"); yOffset += 20; GUI.Label(new Rect(10, yOffset, 300, 20), $"缩放功能: {(enableZoom ? "开" : "关")}"); yOffset += 20; yOffset += 10; GUI.Label(new Rect(10, yOffset, 400, 20), "控制说明:"); yOffset += 20; if (enableClickToFocus) { GUI.Label(new Rect(10, yOffset, 400, 20), "左键点击: 选择子物体观察 (已排除UI/摄像机/灯光)"); yOffset += 20; } if (isObservingChild) { if (enableRotation) { GUI.Label(new Rect(10, yOffset, 400, 20), "左键拖拽: 旋转子物体"); yOffset += 20; } if (enableZoom) { GUI.Label(new Rect(10, yOffset, 400, 20), "滚轮: 缩小子物体观察距离"); yOffset += 20; } GUI.Label(new Rect(10, yOffset, 400, 20), "Shift键: 退出子物体观察模式"); yOffset += 20; } else { if (enableRotation) { GUI.Label(new Rect(10, yOffset, 400, 20), "左键拖拽: 旋转视角"); yOffset += 20; } if (enablePan) { GUI.Label(new Rect(10, yOffset, 400, 20), "中键拖拽: 平移视角 (有距离限制)"); yOffset += 20; } if (enableZoom) { GUI.Label(new Rect(10, yOffset, 400, 20), "滚轮: 缩放 (有距离限制)"); yOffset += 20; } } GUI.Label(new Rect(10, yOffset, 400, 20), "R键: 重置视角"); yOffset += 20; GUI.Label(new Rect(10, yOffset, 400, 20), "A键: 切换自动旋转"); yOffset += 20; GUI.Label(new Rect(10, yOffset, 400, 20), "F键: 聚焦到模型中心"); yOffset += 20; } } void OnDrawGizmosSelected() { if (target != null && showPanBoundary && !isObservingChild) { Vector3 center = target.position; Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(center, 0.5f); Gizmos.color = new Color(1f, 0.5f, 0f, 0.3f); Vector3 size = new Vector3(maxPanDistanceX * 2, 0.1f, maxPanDistanceZ * 2); Gizmos.DrawWireCube(center, size); Gizmos.color = new Color(0f, 1f, 0f, 0.5f); Vector3 currentOffset = target.position + currentTargetPositionOffset; Gizmos.DrawWireSphere(currentOffset, 0.3f); Gizmos.DrawLine(center, currentOffset); Gizmos.color = Color.red; Vector3 cameraPos = transform.position; Gizmos.DrawLine(currentOffset, cameraPos); DrawBoundaryCorners(center); } } private void DrawBoundaryCorners(Vector3 center) { Gizmos.color = Color.cyan; Vector3[] corners = new Vector3[4]; corners[0] = center + new Vector3(-maxPanDistanceX, 0, -maxPanDistanceZ); corners[1] = center + new Vector3(maxPanDistanceX, 0, -maxPanDistanceZ); corners[2] = center + new Vector3(maxPanDistanceX, 0, maxPanDistanceZ); corners[3] = center + new Vector3(-maxPanDistanceX, 0, maxPanDistanceZ); for (int i = 0; i < 4; i++) { Gizmos.DrawSphere(corners[i], 0.2f); Gizmos.DrawLine(corners[i], corners[(i + 1) % 4]); } } void OnDestroy() { // 清理高亮材质 RestoreOriginalMaterials(); } }