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;
    }
}
相关推荐
小拉达不是臭老鼠22 分钟前
Unity中的UI系统之UGUI_登陆面板实现
ui·unity
郝学胜-神的一滴31 分钟前
[简化版 GAMES 101] 计算机图形学 11:频域·卷积·抗锯齿
c++·unity·图形渲染·opengl·three·unreal
玖玥拾10 小时前
Cocos学习笔记:滚动视图、关卡系统与本地存储
游戏引擎·cocos2d
元气少女小圆丶17 小时前
SenseGlove Nova 2+Unity开发笔记2
笔记·unity·游戏引擎
Zldaisy3d18 小时前
全球唯一仿真驱动自适应扫描路径新版本发布,金属3D打印工艺开发进入算法时代
算法·3d
Oiiouui19 小时前
Godot(4.x): 游戏管理器: Godot 内注入数据处理与总接口实现
游戏·游戏引擎·godot
大江东去浪淘尽千古风流人物21 小时前
【HaMeR】全Transformer架构的单目3D手部网格重建:ViT-H骨干+跨注意力MANO解码器源码深度解析
深度学习·3d·transformer·vit·手部重建·mano
五月君_21 小时前
继 React、Vue 之后,Three.js 也有 Skills 了!AI 写 3D 终于不“晕”了
javascript·vue.js·人工智能·react.js·3d
神仙别闹21 小时前
基于Object3D 实现光线追踪
数码相机·3d
想不明白的过度思考者21 小时前
Unity学习笔记——虚拟摇杆实现笔记(事件触发器的使用、UGUI 坐标转换)
笔记·学习·unity