首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【Unity3D中UI与物体可见性的判断方法】

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

作者头像
心疼你的一切
发布2026-01-20 15:16:06
发布2026-01-20 15:16:06
1140
举报
文章被收录于专栏:人工智能人工智能

👉前言

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

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

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

👉一、判断UI的可见性

1-1、第一种

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

代码语言:javascript
复制
    /// <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计算可视区域

代码语言:javascript
复制
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元素以优化性能。

代码语言:javascript
复制
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、视锥体检测方法

代码语言:javascript
复制
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、遮挡检测(射线检测法)

代码语言:javascript
复制
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

代码语言:javascript
复制
void OnBecameVisible() {
    // 当物体进入任何摄像机视野时触发
}

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

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

代码语言:javascript
复制
    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包围盒内

在范围内就可见,则反之

代码语言:javascript
复制
    /// <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、示例如下:

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

👉三、补充

👉3-1、基于渲染器的可见性属性

MeshRenderer.isVisible属性 原理:Unity会自动更新MeshRenderer.isVisible属性,若该属性为true,表示物体至少被一个摄像机的视锥体包含(即可能可见) 特点: 零开销:直接读取Unity内部计算的可见性结果。 局限性:仅适用于带有MeshRenderer组件的物体,对复杂模型的根节点需遍历子物体检测37。 适用场景:快速判断单个物体的粗略可见性,无需自定义计算。

👉3-2、视口与屏幕空间坐标转换

视口坐标检测(WorldToViewportPoint) 原理:将物体的世界坐标转换为视口坐标系(范围[0,1]),若坐标超出该范围或深度超出相机远裁剪面,则不可见

代码语言:javascript
复制
bool IsCenterVisible(Camera cam, Transform obj) {
    Vector3 viewPos = cam.WorldToViewportPoint(obj.position);
    return (viewPos.z > 0 && viewPos.z < cam.farClipPlane && 
            viewPos.x >= 0 && viewPos.x <= 1 && 
            viewPos.y >= 0 && viewPos.y <= 1);
}

👉3-2、屏幕坐标检测(WorldToScreenPoint)

原理:将UI元素的世界坐标转换为屏幕像素坐标,检查是否在屏幕边界内

代码语言:javascript
复制
bool IsUIVisible(Camera cam, RectTransform ui) {
    Vector3 screenPos = cam.WorldToScreenPoint(ui.position);
    return (screenPos.z > 0 && 
            screenPos.x >= 0 && screenPos.x <= Screen.width &&
            screenPos.y >= 0 && screenPos.y <= Screen.height);
}

适用场景:适用于3D Canvas或带相机的2D UI,但需注意UI的渲染模式(如Screen Space Overlay需直接使用屏幕坐标)

👉总结

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-04-22,如有侵权请联系 [email protected] 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 [email protected] 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 👉前言
  • 👉一、判断UI的可见性
    • 1-1、第一种
    • 1-2、通过RectTransform计算可视区域
    • 1-3、滚动容器内可见性检测(Scroll View)
  • 👉二、判断物体的可见性
    • 2-1、视锥体检测方法
    • 2-2、遮挡检测(射线检测法)
    • 2-3、使用渲染器回调(自动触发)
    • 2-4、判断物体中心点的可见性
    • 2-5、判断物体包围盒是否在Camera包围盒内
    • 2-6、完整方法
  • 👉三、补充
  • 👉3-1、基于渲染器的可见性属性
  • 👉3-2、视口与屏幕空间坐标转换
  • 👉3-2、屏幕坐标检测(WorldToScreenPoint)
  • 👉总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档