Canvas 模式是UI与3D混合模式(Render model=Screen space-Camera)
实现在3D模型标记,旋转跟随是UI不在3D物体下
代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ClickHandler : MonoBehaviour
{public Transform object3D; // 总体模型public GameObject imgUIPrefab;public Canvas canvas;public float fadeSpeed = 2.0f; // 淡入淡出的速度private bool isRotating = false;private GameObject clickedObject;private Vector3 lastMousePosition;private Vector3 delta;private Dictionary<GameObject, GameObject> generatedUIs = new Dictionary<GameObject, GameObject>();private void Update(){if (Input.GetMouseButtonDown(0)){lastMousePosition = Input.mousePosition;isRotating = true;Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){clickedObject = hit.collider.gameObject;// 检查是否为小模型if (clickedObject.CompareTag("Model")){isRotating = false;if (!HasGeneratedUI(clickedObject.name)){// 创建UIGameObject imgUI = CreateUIForModel(clickedObject);if (imgUI != null){// 添加到字典中generatedUIs.Add(imgUI, clickedObject);}}}}UpdateImgUIPosition();}if (Input.GetMouseButtonUp(0)){isRotating = false;}if (isRotating){delta = Input.mousePosition - lastMousePosition;float rotationSpeed = 0.5f;object3D.Rotate(Vector3.up, delta.x * -rotationSpeed, Space.World);UpdateImgUIPosition();}lastMousePosition = Input.mousePosition;}private GameObject CreateUIForModel(GameObject model){// 获取被点击物体的中心点位置Vector3 modelCenter = model.transform.position;// 将模型的世界坐标转换为屏幕坐标Vector3 screenPoint = Camera.main.WorldToScreenPoint(modelCenter);// 将屏幕坐标转换为Canvas内的局部坐标RectTransform canvasRect = canvas.GetComponent<RectTransform>();Vector2 canvasLocalPoint;RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, screenPoint, Camera.main, out canvasLocalPoint);// 设置预制体的位置为Canvas内的局部坐标,将Z轴位置设置为-150Vector3 prefabPosition = new Vector3(canvasLocalPoint.x, canvasLocalPoint.y,-150f);// 实例化Img UI预制件,并设置其位置为转换后的局部坐标GameObject imgUI = Instantiate(imgUIPrefab, prefabPosition, Quaternion.identity);imgUI.name = model.name; // 生成UI名字为3D模型名字imgUI.transform.SetParent(canvas.transform, false); // 设置Img UI的父对象为Canvas,确保其显示在屏幕上return imgUI;}private void UpdateImgUIPosition(){foreach (var uiEntry in generatedUIs){GameObject ui = uiEntry.Key;GameObject matchedModel = uiEntry.Value;bool isOccluded = IsObjectOccluded(matchedModel);// ui.SetActive(!isOccluded); // 如果模型被遮挡,则隐藏UI;否则显示UI// 如果模型被遮挡,则UI淡出 否则淡入Image uiImage = ui.GetComponent<Image>();Color color = uiImage.color;float targetAlpha = isOccluded ? 0.0f : 1.0f;color.a = Mathf.MoveTowards(color.a, targetAlpha, Time.deltaTime * fadeSpeed);uiImage.color = color;if (!isOccluded){// 获取匹配模型的中心点位置Vector3 modelCenter = matchedModel.transform.position;// 将模型的世界坐标转换为屏幕坐标Vector3 screenPoint = Camera.main.WorldToScreenPoint(modelCenter);// 将屏幕坐标转换为Canvas内的局部坐标RectTransform canvasRect = canvas.GetComponent<RectTransform>();Vector2 canvasLocalPoint;RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect, screenPoint, Camera.main, out canvasLocalPoint);Vector3 prefabPosition = new Vector3(canvasLocalPoint.x, canvasLocalPoint.y, -150f);// 更新UI的位置ui.GetComponent<RectTransform>().anchoredPosition = prefabPosition;}}}private bool HasGeneratedUI(string name){foreach (var ui in generatedUIs.Keys){if (ui.name == name){return true;}}return false;}private bool IsObjectOccluded(GameObject obj){// 获取摄像机到物体的方向Vector3 directionToTarget = obj.transform.position - Camera.main.transform.position;// 发射射线Ray ray = new Ray(Camera.main.transform.position, directionToTarget);RaycastHit hit;// 射线检测是否有其他碰撞器位于射线路径上if (Physics.Raycast(ray, out hit, directionToTarget.magnitude)){// 如果射线击中的物体不是目标物体,则表示目标物体被遮挡if (hit.collider.gameObject != obj){return true;}}return false;}
}