【Unity3D中UI与物体可见性的判断方法】

发布于:2025-04-11 ⋅ 阅读:(48) ⋅ 点赞:(0)

系列文章目录

unity知识点



👉前言

在Unity中,判断UI和3D物体的可见性需要结合渲染逻辑、空间坐标系转换及特定API的使用

博客将会介绍Unity3D中UI与物体可见性的判断方法。
希望这篇博客对Unity的开发者有所帮助。
大家好,我是心疼你的一切,不定时更新Unity开发技巧,觉得有用记得一键三连哦。
欢迎点赞评论哦.下面就让我们进入正文吧 !


提示:以下是本篇文章正文内容,下面案例可供参考

👉一、判断UI的可见性

1-1、第一种

该方法适用于3D Canvas(第三种模式), 和 2D且赋值了相机的Canvas。(第二种模式)
不适合2D没有赋值相机的Canvas(第一种模式)。

    /// <summary>
    /// 判断ui是否能被相机Camera可见
    /// </summary>
    public bool GetUIDisable(Camera cam, RectTransform ui)
    {
        bool value = true;

        Vector3 pos = cam.WorldToScreenPoint(ui.position);
        if (pos.z < 0 || pos.x < 0 || pos.x > Screen.width || pos.y < 0 || pos.y > Screen.height)
            value = false;

        return value;
    }

1-2、通过RectTransform计算可视区域

public static bool IsUIVisible(RectTransform rectTransform) {
    // 获取UI的屏幕范围
    Vector3[] corners = new Vector3[4];
    rectTransform.GetWorldCorners(corners);
    
    // 计算屏幕的有效区域(假设主Canvas覆盖整个屏幕)
    Rect screenRect = new Rect(0, 0, Screen.width, Screen.height);
    
    // 检查所有角是否在屏幕内
    foreach (Vector3 corner in corners) {
        if (!screenRect.Contains(corner)) {
            return false;
        }
    }
    return true;
}

1-3、滚动容器内可见性检测(Scroll View)

动态加载列表项:当UI元素进入ScrollRect可视区域时加载数据。
自动适配布局:隐藏屏幕外的UI元素以优化性能。

public bool IsVisibleInScrollView(ScrollRect scrollRect, RectTransform content) {
    // 获取ScrollRect的可视区域
    Rect viewportRect = scrollRect.viewport.rect;
    Bounds viewportBounds = new Bounds(
        scrollRect.viewport.position, 
        new Vector2(scrollRect.viewport.rect.width, scrollRect.viewport.rect.height)
    );
    
    // 转换目标UI的坐标到Viewport空间
    Vector3[] contentCorners = new Vector3[4];
    content.GetWorldCorners(contentCorners);
    Matrix4x4 viewportMatrix = scrollRect.viewport.worldToLocalMatrix;
    
    // 检查是否与Viewport重叠
    return RectTransformUtility.RectangleContainsScreenPoint(
        scrollRect.viewport, 
        content.position, 
        null // 可指定特定摄像机
    );
}

👉二、判断物体的可见性

3D物体的可见性取决于

  1. 摄像机视锥体(Frustum):物体是否在摄像机视野内。
  2. 渲染器状态:Renderer.isVisible 属性(自动更新)。
  3. 遮挡关系:物体是否被其他物体遮挡(需额外计算)。

2-1、视锥体检测方法

public bool IsInCameraView(Camera camera, GameObject obj) {
    // 获取物体的包围盒
    Bounds bounds = obj.GetComponent<Renderer>().bounds;
    // 创建视锥体平面
    Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);
    // 检查包围盒是否在视锥体内
    return GeometryUtility.TestPlanesAABB(planes, bounds);
}

2-2、遮挡检测(射线检测法)

public bool IsOccluded(GameObject target, Camera camera) {
    Vector3 dir = target.transform.position - camera.transform.position;
    float distance = dir.magnitude;
    Ray ray = new Ray(camera.transform.position, dir.normalized);
    
    if (Physics.Raycast(ray, out RaycastHit hit, distance)) {
        return hit.collider.gameObject != target;
    }
    return false;
}

2-3、使用渲染器回调(自动触发)

自带API

void OnBecameVisible() {
    // 当物体进入任何摄像机视野时触发
}

void OnBecameInvisible() {
    // 当物体离开所有摄像机视野时触发
}

2-4、判断物体中心点的可见性

    public bool GetObjCenterDisable(Camera cam, Transform obj)
    {
        //转化为视角坐标
        Vector3 viewPos = cam.WorldToViewportPoint(obj.position);

        //  z<0代表在相机背后
        if (viewPos.z < 0)
            return false;

        //  距离farClipPlane太远,摄像机看不到了
        if (viewPos.z > cam.farClipPlane)
            return false;

        //  x,y取值在 0~1之外时代表在视角范围外
        if (viewPos.x < 0 || viewPos.y < 0 || viewPos.x > 1 || viewPos.y > 1)
            return false;

        return true;
    }

2-5、判断物体包围盒是否在Camera包围盒内

在范围内就可见,则反之

    /// <summary>
    /// 相机包围盒
    /// </summary>
    private Plane[] _mTempCameraPlanes = new Plane[6];

    private void Update()
    {
        //使用方法;
        print(GetBondsVisable(transform.position, GetComponent<BoxCollider>().size));
    }

    private void LateUpdate()
    {
        //调用Unity的API,获取相机包围盒
        GeometryUtility.CalculateFrustumPlanes(Camera.main, _mTempCameraPlanes);
    }

    /// <summary>
    /// 通过相机包围盒来判定物体是否在视野中。
    /// </summary>
    public bool GetBondsVisable(Vector3 center, Vector3 size)
    {
        Bounds bound = new Bounds(center, size); //这里的Size是半径
        return GeometryUtility.TestPlanesAABB(_mTempCameraPlanes, bound);
    }

2-6、完整方法

结合了2-1、2-2、示例如下:

// 综合判断3D物体是否可见(视锥体 + 遮挡)
public bool IsObjectVisible(GameObject obj, Camera mainCam) {
    if (!IsInCameraView(mainCam, obj)) return false;
    if (IsOccluded(obj, mainCam)) return false;
    return true;
}

请添加图片描述


👉壁纸分享

在这里插入图片描述

👉总结

本次总结的就是UI与物体可见性的判断方法, 有需要会继续增加功能
如能帮助到你,就帮忙点个赞吧,三连更好哦,谢谢
你的点赞就是对博主的支持,有问题记得留言评论哦!
不定时更新Unity开发技巧,觉得有用记得一键三连哦。么么哒!