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;
    }
}
相关推荐
先生沉默先6 小时前
3dsMax合并FBX的时候相同的节点会被合并(重命名解决),3Ds MAX创建空物体(虚拟对象或者点)
3d·3dsmax
Death2009 小时前
Qt 3D、QtQuick、QtQuick 3D 和 QML 的关系
c语言·c++·qt·3d·c#
摇曳的树13 小时前
【3D目标检测】激光雷达和相机联合标定(二)——MATLAB联合标定工具使用
数码相机·目标检测·3d
知来者逆14 小时前
V3D——从单一图像生成 3D 物体
人工智能·计算机视觉·3d·图像生成
唐·柯里昂7981 天前
[3D打印]拓竹切片软件Bambu Studio使用
经验分享·笔记·3d
Artistation Game1 天前
九、怪物行为逻辑
游戏·unity·游戏引擎
百里香酚兰1 天前
【AI学习笔记】基于Unity+DeepSeek开发的一些BUG记录&解决方案
人工智能·学习·unity·大模型·deepseek
妙为1 天前
unreal engine5制作动作类游戏时,我们使用刀剑等武器攻击怪物或敌方单位时,发现攻击特效、伤害等没有触发
游戏·游戏引擎·虚幻·碰撞预设
摇曳的树1 天前
【3D目标检测】激光雷达和相机联合标定(一)——ROS同步解包
数码相机·目标检测·3d
dangoxiba1 天前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十三集:制作小骑士的接触地刺复活机制以及完善地图的可交互对象
游戏·unity·visualstudio·c#·游戏引擎