[Unity] 利用Culling Group实现LOD和剔除逻辑

注: 至于性能没有做过测试!!!  如果认为有问题那Unity的LodGroup 都没必要用!

官方手册:

https://docs.unity3d.com/2018.2/Documentation/Manual/CullingGroupAPI.html

https://docs.unity3d.com/ScriptReference/CullingGroup.html

https://docs.unity3d.com/ScriptReference/CullingGroupEvent.html

该API于Unity 5.2和之后版本出现

官方文档中提到一个优化:

Mass object movement & CullingGroups

As mentioned in the section on Transform Manipulation, moving large Transform hierarchies has a relatively high CPU cost due to the propagation of change messages. However, in real development environments, it is often impossible to collapse a hierarchy to a modest number of GameObjects.

At the same time, it is good development practice to only run enough behavior to maintain the believability of the game world while eliminating behavior the user will not notice – for example, in a Scene with a large number of characters, it is always more optimal to only run Mesh-skinning and animation-driven Transform movement for characters that are on-screen. There is no reason to waste CPU time calculating purely visual elements of the simulation for characters that are off-screen.

Both of these problems can be neatly addressed with an API first introduced in Unity 5.1: CullingGroups.

Instead of directly manipulating a large group of GameObjects in the scene, change the system to manipulate the Vector3 parameters of a group of BoundingSpheres within a CullingGroup. Each BoundingSphere serves as the authoritative repository for a single game-logical entity’s world-space position, and receives callbacks when the entity moves near/within the frustum of the CullingGroup’s main camera. These callbacks can then be used to activate/deactivate code or components (such as Animators) governing behavior that should only run while the entity is visible.

大量对象移动和剔除群组

如同 Transform Manipulation 那节所述,移动有超大层级结构的 Transform 对象会造成很大的 CPU 消耗。但在现实的环境中,通常不可能将对象结构精简到最少的 GameObjects。

同时,如果可以最好在玩家不发现的前提下,删除玩家看不到的行为。例如,在有大量角色的场景时,只针对屏幕可见范围内的角色计算网格蒙皮(Mesh-skinning)和处理角色动作等等。不需要浪费CPU的资源在计算屏幕外看不到的角色行为。

这两个问题都可以透过 Unity 5.1 导入的 API 来完美解决:CullingGroups。

与其直接操作场景中一大群的 GameObject,而是改变系统操作 CullingGroup 里的一组 BoundingSpheres 的Vector3 参数。每个 BoundingSphere 作为这些 GameObject 在游戏世界中的代表,当 CullingGroup 接近或进入CullingGroup 设定的主镜头的锥体范围内时成员才会收到 callback。然后这些 callback 就可以用来执行启用/停用的程序代码或组件(例如Animators)让物体执行在可见范围内该有的行为。

https://docs.unity3d.com/2018.2/Documentation/Manual/BestPracticeUnderstandingPerformanceInUnity8.html

https://docs.unity3d.com/ScriptReference/CullingGroup.html

https://docs.unity3d.com/2018.2/Documentation/Manual/CullingGroupAPI.html

https://unitycoder.com/blog/2018/10/31/find-nearby-objects-using-cullinggroup/

有两种方式来触发CullingGroup的事件:

  • 相机裁剪
  • 相对距离(相机或主主角相对于目标物体的距离)

这两种方式可以混用,也可以只使用其中一个

应用场景有:

  • 粒子当前不可见时,将其暂停
  • 粒子与相机或主角在不同距离阶段时,使用不同的简化版粒子。
  • ai不在视野内时停止更新

剔除组是Unity API的一部分,它有效地允许我们创建自己的自定义LOD系统,作为一种方法来提出我们自己的动态替换某些游戏玩法或渲染行为的方法。我们可能希望应用LOD的一些示例包括  用具有较少骨骼的版本替换动画角色,应用更简单的着色器,远距离跳过粒子系统生成,简化AI行为等等。它在游戏玩法领域也有其他用途,

例如确定某些敌人出生点当前是否对玩家可见或者Player是否正在接近某些区域。有各种各样的可能性可与Culling Group系统一起使用,值得考虑。当然,花在实施,测试和重新设计场景上的时间可能很重要。

unity_2017_game_optimization_second_edition.pdf : 建议有时间阅读一下此书 http://www.dphgame.com/lib/exe/fetch.php?media=unity_2017_game_optimization_second_edition.pdf

Mesh-based LOD :基于网格的LOD也将耗费我们的磁盘空间以及RAM和CPU;

有些可能真的不要使用这个技术,比如 总是在室内或固定视角的俯视相机,包括实时战略(RTS)和多人在线战斗竞技场(MOBA)游戏。

Unity 的LodGroup 有一个限制, 他优化的是Mesh,根据距离切换到合适的Mesh(顶点和三角面优化)。

例如一个特效的Lod 可能需求是显示不同的GameObjct 节点,除了LodGroup 根据距离切换,可能还要考虑机型的挡位,来决定这个特效到底要显示多少还是完全不显示了。

仅在对象实际可见时才进行处理

在3D游戏中,“可见判断”是一个非常棘手的问题。即使它们实际上不可见,但很多情况下它们都是在3D空间中绘制的,即使像素没有被绘制也是如此。这是OcclusionCulling有可能是你不希望看到通过不需要的部分。

故事中的CullingGroupOcclusionCulling类似,您可以使用该脚本确定相机是否可见并跳过处理。

例如,下面的Gif动画正在跳过不可见字符的动画。

 注: 在Animator的情况下(组件有类似的功能设置),如果Animator剔除模式Culling Mode设置为剔除更新变换Cull Update Transform等,则在超出相机范围时将跳过动画。

此外,不可见物体的停止更新  也可用于诸如停止IK和减少AI更新频率的方法。

此外,因为它基于坐标,所以即使没有Renderer组件也可以操作。相反,即使没有游戏对象被剔除和非Active,它也可以被操作。

因此,我认为如果资源可能在视图范围内,则可以加载和实例化资源,如果资源消失,卸载删除。

在下面的GIF动画中,资源在可见之前加载一点,创建一个对象,并在它变得不可见时被销毁。

按对象的相对距离切换处理

另一个功能是根据相对距离切换处理(当然,还有当它不可见时的处理)。 远处的物体无法详细查看,所以这是一种通过关闭Lookat,动画和其他东西来减轻负荷的方法。

在动画中,颜色根据距离而改变。(1米:白色,5米:绿色,30米:蓝色,看不见:黑色......等, 人实际上高约4米)

功能上接近LOD。它可能更容易使用,因为它比标准LOD更容易调整。

样本Demo

这是一个样本。

using UnityEngine;
using System.Collections;public class CullingGroupSample : MonoBehaviour {private CullingGroup group = null;private BoundingSphere[] bounds;[SerializeField] Transform[] targets = null;void Start(){group = new CullingGroup ();// 设置相机进行剔除group.targetCamera = Camera.main;// 设置用于测量距离和距离水平的中心坐标// 1:1米2:5米3:10米,4:30米,5:100米或更长:看不见的处理group.SetDistanceReferencePoint (Camera.main.transform);group.SetBoundingDistances (new float[]{ 1, 5, 10, 30, 100});// 设置列表以执行可见性确定bounds = new BoundingSphere[targets.Length];for (int i = 0; i < bounds.Length; i++) {bounds [i].radius = 1.5f;}// 注册对列表的引用group.SetBoundingSpheres (bounds);group.SetBoundingSphereCount (targets.Length);// 注册当对象可见性发生变化时的回调group.onStateChanged = OnChange;}void Update(){// 更新已注册对象的坐标for (int i = 0; i < bounds.Length; i++) {bounds [i].position = targets [i].position;}}void OnDestroy(){// 清理工作group.onStateChanged -= OnChange;group.Dispose ();group = null;}void OnChange(CullingGroupEvent ev ){// 仅激活不在视图中的对象targets [ev.index].gameObject.SetActive(ev.isVisible);// 如果范围是2m或更多,则取消激活if (ev.currentDistance > 2) {targets [ev.index].gameObject.SetActive (false);}}}

用法是这样的,只需在 Targets 的Trasnfrom中注册要剔除的对象。

如果生成敌人据点在玩家视野中就不生成敌人

使用CullingGroup,但这次我使用CullingGroup.IsVisible。

似乎管理基于onStateChanged回调无法看到的生成点列表具有较少的计算次数,但由于更容易进行每次计算,因此采用它。

粗略的处理流程如下。

  1. 列出可见的生成点
  2. 从列表中随机设置生成点
  3. 生成敌人
  4. 等0.5秒

设置Level和敌人生成点。

由于生成点调整位置很麻烦,通过在对象上放置图标很容易找到它。

在创建敌人的过程中添加“如果不在视图中就可以生成敌人”的过程。正如我上面所写,CullingGroup的IsVisible收集了错误的坐标。

using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;public class SpawnTest : MonoBehaviour
{private IEnumerator spawnFlow = null;private CullingGroup cullingGroup = null;[SerializeField] Transform[] targetPositions = null;[SerializeField] GameObject spawnObject = null;void Awake(){spawnFlow = SpawnCoroutine();}void OnEnable(){// 创建 cullinggroup 并启动协同程序SetupCullinggroup ();StartCoroutine (spawnFlow);}void OnDisable(){// 清理工作StopCoroutine (spawnFlow);cullingGroup.Dispose ();cullingGroup = null;}void SetupCullinggroup(){// culling group 初始化cullingGroup = new CullingGroup ();cullingGroup.targetCamera = Camera.main;// 注册坐标以生成敌人BoundingSphere[] bounds = new BoundingSphere[targetPositions.Length];for (int i = 0; i < targetPositions.Length; i++) {bounds [i].position = targetPositions [i].position;bounds [i].radius = 1;}cullingGroup.SetBoundingSpheres (bounds);cullingGroup.SetBoundingSphereCount (targetPositions.Length);}IEnumerator SpawnCoroutine(){List<int> countList = new List<int> ();while (true) {// 获取不在视线中的生成点列表countList.Clear ();for (int i = 0; i < targetPositions.Length; i++) {if (cullingGroup.IsVisible (i) == false ) {countList.Add (i);}}if (countList.Count != 0) {var newPos = countList[Random.Range (0, countList.Count)];GameObject.Instantiate (spawnObject, targetPositions [newPos].position, Quaternion.identity);}// 0.5秒等待yield return new WaitForSeconds (0.5f);}}
}

您需要做的就是将TargetObject设置为生成敌人的GameObject,将SpawnPrefab设置为生成敌人。

Demo: https://github.com/tsubaki/CullingGroup_Sample

[Unity]当角色可见时才创建

看不见时

可以看见时

但是比较好的处理可能时   设计一个对象的据点,到达据点(或者距离中心点距离) 来加载对象。 防止对象过多检查费事。   但是这里是演示功能而已。

分离 两个场景, 其中一个根据需要才加载的。 如下图两个场景包含的内容。

运行时行为:

  • 加载默认场景
  • 使用Culling Group执行可见性判断
  • 如果  很可能在视野中,请加载包含需要的场景

用于可见性判断的坐标,坐标放置在Stage场景中  作为标记并引用它。

这次我将能见度判断放在与和 Gimmick中对象相同的位置,但在实践中很难做到,所以我认为将能见度判断放在Gimmick组的四个角上是好的。

场景编辑完之后卸载Gimmick  (避免实际运行时重复加载)

调试脚本:

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;public class CullingGroupSpawn : MonoBehaviour
{[SerializeField] Transform[] positions;void OnDrawGizmos (){
#if UNITY_EDITORUnityEditor.Handles.color = Color.red;foreach (var pos in positions) {UnityEditor.Handles.CircleCap(0, pos.position, UnityEditor.SceneView.currentDrawingSceneView.camera.transform.rotation, pos.localScale.magnitude);}
#endif}
}

using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;public class CullingGroupSpawn : MonoBehaviour
{[SerializeField] Transform[] positions;[SerializeField] string sceneName;  // 要加载的场景名称private CullingGroup cullingGroup = null;void Start (){// cullingGroup初始化cullingGroup = new CullingGroup ();cullingGroup.targetCamera = Camera.main;// 注册 更新可见性状态时 的回调cullingGroup.onStateChanged += OnStateChange;// 注册坐标BoundingSphere[] bounds = new BoundingSphere[positions.Length];for (int i = 0; i < bounds.Length; i++) {bounds [i].position = positions [i].position;bounds [i].radius = positions[i].localScale.magnitude;}cullingGroup.SetBoundingSpheres (bounds);cullingGroup.SetBoundingSphereCount (positions.Length);}void OnStateChange (CullingGroupEvent ev){// 如果看到它,请使用Aditive加载场景// cullinggroup 停止if (ev.hasBecomeVisible) {cullingGroup.enabled = false;var result = SceneManager.LoadSceneAsync (sceneName, LoadSceneMode.Additive);result.priority = 2;}}void OnDestroy (){cullingGroup.Dispose ();cullingGroup = null;}void OnDrawGizmos (){
#if UNITY_EDITORUnityEditor.Handles.color = Color.red;foreach (var pos in positions) {UnityEditor.Handles.CircleCap(0, pos.position, UnityEditor.SceneView.currentDrawingSceneView.camera.transform.rotation, pos.localScale.magnitude);}
#endif}
}

示例没有考虑  卸载部分,     你可以想到生成Prefab而不是Scene的方法。比Scene方法更灵活

CullingGroup可能比LOD更好

因为简单替换特效模型的方式还是有问题:  http://tsubakit1.hateblo.jp/entry/2018/02/04/014149

https://twitter.com/tsubaki_t1/status/959642481523486720?ref_src=twsrc^tfw|twcamp^tweetembed|twterm^959642481523486720&ref_url=http%3A%2F%2Ftsubakit1.hateblo.jp%2Fentry%2F2018%2F02%2F04%2F014149

#unitytips:ParticleSystem性能 - 剔除   https://blogs.unity3d.com/2016/12/20/unitytips-particlesystem-performance-culling/

其他示例:

https://github.com/tsubaki/CullingGroup_Sample

## sample 1停止invisible动画。

## sample 2通过距相机的距离改变行为(颜色)。

(相机会移动)

## sample 3通过距相机的距离改变行为(颜色)。

(对象会移动)

## sample 4不会产生可见的spawner。

参考:

  • #unitytips:ParticleSystem性能 - 剔除   https://blogs.unity3d.com/2016/12/20/unitytips-particlesystem-performance-culling/
  • https://unitycoder.com/blog/2018/10/31/find-nearby-objects-using-cullinggroup/

在#UniteKL18上看到这个提示,使用CullingGroup快速获取附近的物体!(5000个游戏对象,在3米范围内搜索对象)       这些也有TODO 关于性能测试

  • http://hsienwei.github.io/2017/06/05/UnityCullingGroup/
  • 要对CullingGroup 做一个详细的实验:

http://tsubakit1.hateblo.jp/entry/2016/01/07/233000

http://tsubakit1.hateblo.jp/entry/2016/01/11/191341

http://tsubakit1.hateblo.jp/entry/2018/02/04/014149

有两个主要功能,例如“仅在对象实际可见或不可见时进行处理”和“通过与对象的相对距离进行切换处理”。

  • http://tsubakit1.hateblo.jp/entry/2016/01/10/041423

https://github.com/tsubaki/CullingGroup_Sample             动画控制, 根据距离改变颜色可以作为Lod系统的定制。    (关于生成相关联网游戏内都是服务器控制的)

https://github.com/tsubaki/CullingGroupSpawnSample

https://github.com/tsubaki/CullingGroup_Sample

有很多lua 代码使用?   https://github.com/search?q=CullingGroup&type=Code

  • 剔除系统: https://github.com/volvis/AijaiPackage/tree/57b6c9e978a5e3c122f7c71dce146827fda819d1

Unity在HDRP中有使用? https://github.com/Unity-Technologies/ScriptableRenderPipeline/blob/9c99c48a40b154d6aac9720a39572589fcfb342e/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/CullingGroupManager.cs

  • 一个项目在用:Line Of Sight 视线处理部分使用(国人独立开发者)     https://github.com/fuutougames/Project_TPSandRTS/blob/3f52686b4f7a2117f3f1701ba7d7f1311bc65658/Client/Assets/Line%20Of%20Sight/Scripts/LOSManager.cs
  • Realistic Level Design 现实关卡设计: 技术美术  https://github.com/canderson770/Realistic-Level-Design/blob/0cd1f9a1b82ba5609ee402d6aabbcac25efce390/RealisiticLevelProject/Assets/Scripts/ObjectCulling.cs
  • 国人的一个工具:一个CullingGroup的扩展集合,可以用于进行高性能的视野/距离剔除。   https://github.com/tzkt623/------Tezcat-s-Tool-/blob/5eef2a8cadcceed501864953c1d25b136de4a66a/ZTools/ViewCulling/ViewCullingManager.cs

PortalCulling.cs  等等

  • 这个网站的作者:http://ulua.org/     https://github.com/jarjin/NewFramework/tree/3f730ec7e169d26156c62325926da819a426e03b/FirClient/Assets/Scripts/Camera/CullingGroup
  • 这里给出一个警告:    https://zhuanlan.zhihu.com/p/32190878

[Unity] 利用Culling Group实现LOD和剔除逻辑相关推荐

  1. kafka tool 查看指定group下topic的堆积数量_ELK架构下利用Kafka Group实现Logstash的高可用...

    系统运维的过程中,每一个细节都值得我们关注 下图为我们的基本日志处理架构 所有日志由Rsyslog或者Filebeat收集,然后传输给Kafka,Logstash作为Consumer消费Kafka里边 ...

  2. [Unity]利用Mesh在Unity中绘制扇形图片

    背景 最近碰到个功能, 要画一个扇形图案, 如下图: 美术原图: 需求是这个图形跟随角色, 在角色背后, 并且每个角色的扇形角度可能不同. So, NGUI和UGUI很好用的FilledType是用不 ...

  3. C#开发Unity游戏教程之游戏对象的行为逻辑方法

    C#开发Unity游戏教程之游戏对象的行为逻辑方法 游戏对象的行为逻辑--方法 方法(method),读者在第1章新建脚本时就见过了,而且在第2章对脚本做整体上的介绍时也介绍过,那么上一章呢,尽管主要 ...

  4. ML之NBLoR:利用NB(朴素贝叶斯)、LoR(逻辑斯蒂回归)算法(+TfidfVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析—五分类预测

    ML之NB&LoR:利用NB(朴素贝叶斯).LoR(逻辑斯蒂回归)算法(+TfidfVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析-五分类预测 目录 输出结果 ...

  5. ML之NBLoR:利用NB(朴素贝叶斯)、LoR(逻辑斯蒂回归)算法(+CountVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析—五分类预测

    ML之NB&LoR:利用NB(朴素贝叶斯).LoR(逻辑斯蒂回归)算法(+CountVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析-五分类预测 目录 输出结果 ...

  6. NLP之TEA之NB/LoR:利用NB(朴素贝叶斯)、LoR(逻辑斯蒂回归)算法(+TfidfVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析—五分类预测

    NLP之TEA之NB/LoR:利用NB(朴素贝叶斯).LoR(逻辑斯蒂回归)算法(+TfidfVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析-五分类预测 目录 输出结 ...

  7. NLP之TEA之NB/LoR:利用NB(朴素贝叶斯)、LoR(逻辑斯蒂回归)算法(+CountVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析—五分类预测

    NLP之TEA之NB/LoR:利用NB(朴素贝叶斯).LoR(逻辑斯蒂回归)算法(+CountVectorizer)对Rotten Tomatoes影评数据集进行文本情感分析-五分类预测 目录 输出结 ...

  8. 【unity】性能优化之——视锥体剔除(Frustum Culling)(一)

    一.应用背景 在现代游戏中,游戏资源越来越多,游戏场景也越来越大越来越复杂,虽说硬件设备更新迭代很快,性能也日渐强大,但这还远不能缓解复杂繁多的资源带来的性能压力,因而性能优化仍然很有必要.场景资源的 ...

  9. Unity Occlusion Culling 遮挡剔除研究

    本文章由cartzhang编写,转载请注明出处. 所有权利保留.  文章链接:http://blog.csdn.net/cartzhang/article/details/52684127  作者:c ...

  10. Unity场景模型优化技术--LOD和OcclusionCulling

    LOD和Occlusion Culling Lod和遮挡剔除. Occlusion Culling:Occlusion Culling 技术是指当一个物体被其他物体遮挡住而相对当前摄像机为不可见时,可 ...

最新文章

  1. 【整理】ABAP快捷启动Debug三种方式
  2. 315汽车大型排雷现场,数据总结避雷规律
  3. sort和uniq命令
  4. 2019牛客暑期多校训练营(第七场)D Number(思维)
  5. Web Api 基于Zookeeper的服务注册与发现
  6. 【SpringMVC入门】SpringMVC环境搭建、接收参数的几种方式、视图解析器、@ResponseBody
  7. Utils 工具 推送
  8. C# 三种方式实现Socket数据接收(经典)
  9. JavaFX缺少的功能调查:CSS
  10. .NET Micro Framework 用户程序升级说明
  11. 用java画爱心图_C++和Java命令行绘制心形图案
  12. 短视频自媒体成功的秘诀就一个字:真
  13. laravel 数据填充
  14. Xeen的Source Safe 备份
  15. MATLAB更改初始工作路径
  16. WIN7系统VC6中添加OCX出现“不支持此接口” 问题的解决方法
  17. Aras innovator: innovator大家族
  18. JavaScript Navigator
  19. Real-SR超分辨网络
  20. 局域网内帆软BI使用arcgis发布的wms服务

热门文章

  1. html/css椭圆运动
  2. ros buntu安装手册_超详细 ROS安装教程
  3. python隐藏窗口_python怎么隐藏界面?
  4. arcgis 经纬度转大地坐标_MapGIS实现大地坐标到经纬度(地理坐标)的换算
  5. 计算机基础知识实验课教案,高职《计算机网络基础》实验课程教学设计
  6. 双目视觉测距离(三维重建)
  7. Linux图形终端与字符终端
  8. ShadowGun shader 解析(1)
  9. 进程杀手 (prockiller)V2.82绿色版
  10. 海量数据的常见处理算法