Unity实现在3D模型标记

Canvas 模式是UI与3D混合模式(Render model=Screen space-Camera)

实现在3D模型标记,旋转跟随是UI不在3D物体下

代码:

csharp 复制代码
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))
                    {
                        // 创建UI
                        GameObject 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轴位置设置为-150
        Vector3 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;
    }
}
相关推荐
西红柿炖牛腩35416 小时前
Three.js 模型体积优化:Draco/Meshopt 压缩与 DRACOLoader 配置的 4 个步骤
javascript·3d·性能优化
每日出拳老爷子18 小时前
【VR】【Unity】抓走转放系列21|一天搭完门和抽屉工具槽:小场景按这个次序拼装
unity·vr·驱动·排错·snap zone
JAI科研19 小时前
CT重建(二) | 3D高斯泼溅:实时渲染的革命
图像处理·人工智能·计算机视觉·3d·视觉检测·ct重建
李游Leo19 小时前
HarmonyOS 7 + Spatial Recon Kit-C++:3DGS 输入帧内参与位姿的版本一致性门禁【鸿蒙心迹】
c++·3d·harmonyos
HwJack201 天前
【共创稿事节】HarmonyOS 7空间信息层级:焦点、景深与注意力引导
3d·华为·harmonyos·空间计算
淡海水1 天前
02-02-原理篇-分代GC
算法·unity·c#·游戏引擎·.net·gc
小师兄吃牛肉1 天前
ANSYS EMA3D 2025 R2 专业安装详解:系统级电磁兼容与电磁干扰仿真平台全解析
3d
小贺儿开发2 天前
Unity 文物新生 会讲故事的文物展墙
人工智能·科技·unity·ai·视频·互动·演示
HwJack202 天前
【共创稿事节】HarmonyOS 7是3DGS 端侧重建:空间建模类应用的设计机会
3d·华为·harmonyos
I Am a robert girl2 天前
从频率到几何:GA-EIRFS 如何重新思考长尾 3D 检测的采样逻辑
3d·3d目标检测·nuscenes·lidar·数据采样·长尾分布·类别不平衡