草庐IT

【Unity】相机视锥体剔除算法

魔术师Dix 2023-07-21 原文

        视锥体剔除是Unity常用的剔除方法,其原理就是通过判定目标包围盒与组成相机视锥体的6个平面进行同侧判定,只要在6个平面之间的包围盒即为可见。

        具体原理可见参考以下文章:

        视锥体剔除(Frustum Culling)算法详解

        不过这个文档里面主要讲原理,没有Unity的具体实现。本文根据其原理,给出一个视锥体裁剪的剔除算法的实现。另:当初做这个剔除是为了在 ECS 里面使用的,因此这里的写法都是 ECS 的实现,但是原理是一样的。

1、获取相机平面

        所谓相机的裁剪视锥体,如下图所示:

         其实就是单纯地6个平面,在Unity中调用对应API可以很方便地获取到:

GeometryUtility.CalculateFrustumPlanes(Camera camera, Plane[] planes)

        Unity的原生API是返回一个数组,在ECS里面是不能直接使用的。如有需要,则要提前转换成一个 NativeArray , 用一个 float4 即可缓存每个平面的法线平面方程:

private NativeArray<float4> m_FrustumPlanes;//给Ecs用的裁剪面
private Plane[] CameraSourcePlanes = new Plane[6];//原生获得的裁剪面
private Camera camera//主相机,需要外部传入

private void UpdateFrustumPlanes()
{
    //通过Unity原生API来获取相机裁剪面
    GeometryUtility.CalculateFrustumPlanes(camera, CameraSourcePlanes);
    //这里因为要给ECS用,所以需要转换为Native数据保存。
    for (int i = 0; i < 6; i++)
    {
        var plane = CameraSourcePlanes [i];
        //保存一个平面方程
        m_FrustumPlanes[i] = new float4(plane.normal, plane.distance);
    }
}

        这里只是准备步骤。

2、视锥体剔除算法

       视锥体剔除的结果,只有三种:        

        public enum InsideResult//视锥体检测的结果
        {
            Out,//外侧
            In,//包含在内(指整个包围盒都在相机视锥体内)
            Partial//部分包含
        };

        剔除算法直接上代码了, 原理在上文的连接里面就有:

        /// <summary>
        /// 球状剔除
        /// </summary>
        /// <param name="center">球中心</param>
        /// <param name="radius">半径</param>
        public InsideResult Inside(float3 center, float radius)
        {
            int length = mPlanes.Length;
            bool all_in = true;
            for (int i = 0; i < length; i++)
            {
                float4 plane = mPlanes[i];
                float3 normal = plane.xyz;
                var distance = math.dot(normal, center) + plane.w;
                if (distance < -radius)
                    return InsideResult.Out;

                all_in = all_in && (distance > radius);
            }

            return all_in ? InsideResult.In : InsideResult.Partial;
        }

        球状剔除就是与文章了里的算法对应的,这里的 mPlanes 就是之前的缓存的视锥体法线平面

        这里还是简单说一下原理:将包围盒中心对裁剪面的法线平面投影,点乘的结果就是中心到平面的距离。这个距离有正有负,为正数自然是在平面同侧,为负数则在平面背侧。当然,包围盒是有半径一说,所以求出的距离还需要与半径进行比较,来判定是否整个包围盒都在平面的一侧。

        这里再提供一个方形包围盒的剔除:        

        /// <summary>
        /// 方形包围盒剔除
        /// </summary>
        /// <param name="center">盒子中心</param>
        /// <param name="extents">外延尺寸(size的一半)</param>
        public InsideResult Inside(float3 center, float3 extents)
        {
            int length = mPlanes.Length;
            bool all_in = true;
            for (int i = 0; i < length; i++)
            {
                float4 plane = mPlanes[i];
                float3 normal = plane.xyz;
                float dist = math.dot(normal, center) + plane.w;
                float radius = math.dot(extents, math.abs(normal));
                if (dist <= -radius)
                    return InsideResult.Out;

                all_in &= dist > radius;
            }

            return all_in ? InsideResult.In : InsideResult.Partial;
        }

        这里唯一的区别就是半径的算法不同,盒子是将其 extern 在对应法线平面上进行投影当做半径,当然也可以理解为立方体顶点到中心的向量在法线平面上的投影。这里的算法中使用的 center 和  extents 可以直接从 BoxCollider 中把数据抄过来。

结语

        只要理解了原理,算法相对还是比较简单,性能也还可以,大家可以根据自己的需求进行改造。如果不需要在ECS里面用,或者不需要自己实现的话,直接调用Unity的API也是可以的:       

 GeometryUtility.CalculateFrustumPlanes(mainCamera, mTempCameraPlanes);

        更多Unity的相机视野判定,可以参考下文:

        【Unity】判断 物体/坐标 是否在相机范围内

有关【Unity】相机视锥体剔除算法的更多相关文章

  1. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  2. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  3. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  4. unity---接入Admob - 2

    目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里​编辑 3.解析依赖到项目中

  5. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  6. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  7. 100个python算法超详细讲解:画直线 - 2

    1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva

  8. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  9. 三分钟集成 TapTap 防沉迷 SDK(Unity 版) - 2

    三分钟集成Tap防沉迷SDK(Unity版)一、SDK介绍基于国家对上线所有游戏必须增加防沉迷功能的政策下,TapTap推出防沉迷SDK,供游戏开发者进行接入;允许未成年用户在周五、六、日以及法定节假日晚上8:00-9:00进行游戏,防沉谜时间段进入游戏会弹窗进行提示!开发环境要求:Unity2019.4或更高版本iOS10或更高版本Android5.0(APIlevel21)或更高版本🔗Unity集成Demo参考链接🔗UnityTapSDK功能体验APK下载链接二、集成前准备1.创建应用进入开发者后台,按照提示开始创建应用;2.开通服务在使用TDS实名认证和防沉迷服务之前,需要在上面创建的应

  10. 【Unity大气散射】GAMES104:3A中如何实现大气散射 - 2

    写在前面前两天学习并整理的大气散射基础知识:【Unity大气渲染】关于单次大气散射的理论知识,收获了很多,但不得不承认的是,这其实已经是最早的、90年代的非常古老的方法了,后来也出现了一些优化性的计算思路和方法。因此,我打算先不急着跟各种教程在Unity中实现大气散射,而是再花时间来看看最近的游戏是如何去实现大气渲染的:06.游戏中地形大气和云的渲染(下)|GAMES104-现代游戏引擎:从入门到实践接下来就跟着GAMES104讲地形大气和云渲染的部分学习并做简单的记录,涉及到之前没提到的Mie散射也只选择直接截图PPT的方式记录啦!毕竟对于做作品来说,之后实现出来才是重要的~当然,May佬的

随机推荐