【Unity】四叉树八叉树管理和动态加载场景物件

【Unity】四叉树⼋叉树管理和动态加载场景物件
⼀、引⾔:
场景的组织与管理是3d游戏开发中重要的⼀环,unity3d引擎中,只提供了最基本的场景组织,当我们加载场景时,会将场景中的物件及其依赖的资源全部加载出来,这对于较为庞⼤的场景显然是不合理的。可以考虑在进⼊场景时预先将可见范围内的物体加载,之后的其它物件也全部在当进⼊可见区域时加载,但如何才能快速索引到进⼊某区域的物体?因此,我们需要考虑⼀种层次化的场景管理机制,可以快速的索引出指定空间区域内的物体,以实现这种效果。
⼆、⼏何剖分技术:
⼏何剖分技术是⼀种能将场景中的⼏何物体通过层次性机制组织,使⽤时可以快速剔除层次树的整个分⽀,从⽽加快索引⼏何体的过程。四叉树(quad tree)和⼋叉树(octree)是⼀种常⽤的空间剖分⽅法,它将已知的空间分成四/⼋个⼦空间作为节点,每个节点⼜划分成四/⼋个⼦空间,依此递归,直到达到指定深度。
四叉树:
⼋叉树:
三、原理:
地源热泵设计四叉树/⼋叉树的数据结构不算复杂,其节点主要包含如下成员:数据成员Data,节点的包围盒信息Bounds,⽤于确定节点的空间信息(对于2D情况的四叉树,也可以是Rect),⼦节点引⽤。其中树的根节点拥有最⼤的Bounds,其⼦节点的Bounds将其分割成四/⼋个⼦Bounds。这样每次我们需要查某点附近的数据时,可以根据节点的Bounds快速的剔除掉⼤量不需要查的物体。
注意,由于插⼊的数据成员本⾝也包含空间位置和⼤⼩信息,可能出现数据刚好处于节点的边界上,如下:
如图中右上⾓的星星图案,其刚好位于两个节点的边界上,此时的处理⽅法有:
1.两个节点同时包含该数据
2.由⽗节点包含该数据(这样意味着不仅仅只有叶⼦节点可以存储数据)
第⼀种⽅式尽管相对精确,但如果存在特别⼤的物体可能覆盖多个节点,那就需要同时被这些节点引⽤,不容易管理。
本⽂的实现采⽤了第⼆种⽅式,⼀些很⼩的物体也可能出现没有插⼊到叶⼦节点⽽导致范围过⼤,特别的,如果该物体恰巧位于四叉树区域
的正中⼼,则其只能被四叉树的根节点所包含。
另外还可以通过实现松散四叉树的⽅式,不在本⽂讨论范围内,可以查阅相关的⽂档或博客。浙江大学校医院陈文备
四、实现:
1.检索进⼊指定区域的物体
抽象出了⼀个检测器接⼝:
/// <summary>
/// 检测器接⼝,⽤于检测和场景物件的触发
/// </summary>
public interface IDetector
莫麟传奇之四大古国全集{
/// <summary>
/// 是否检测成功
/
// </summary>
/// <param name="bounds">包围盒</param>
/// <returns></returns>
bool IsDetected(Bounds bounds);
/// <summary>
/// 触发器位置
/// </summary>
Vector3 Position { get; }
}
对于场景树中存储的节点和节点下的物体数据,其全部包含了⼀个Bounds数据,⽤于确定该节点或该场景物体的包围盒区域,这样每次进⾏检索时,实际上就是调⽤具体Detector的IsDetected接⼝,并传⼊Bounds,以判断该节点或该场景物体是否可以被检索。
我⽬前实现了两种形式的Detector,⼀种通过简单的设置Detector周围指定范围的六⾯体区域作为可见区域,另⼀种则是基于相机视锥体的判断,两种效果如下:
基于简单的六⾯体区域:
/// <summary>
/// 该触发器根据六⾯体包围盒区域触发
癫克星/// </summary>
public class SceneTransformDetector : SceneDetectorBase
{
public Vector3 detectorSize;
private Bounds m_Bounds;
public override bool IsDetected(Bounds bounds)
{
= Position;
m_Bounds.size = detectorSize;
return bounds.Intersects(m_Bounds);
}
}
基于相机视锥体:
/// <summary>
/// 该触发器根据相机裁剪区域触发
/// </summary>
public class SceneCameraDetector : SceneDetectorBase
{
private Camera m_Camera;
void Start()热闹的菜市场
{
m_Camera = gameObject.GetComponent<Camera>();
}
public override bool IsDetected(Bounds bounds)
{
if (m_Camera == null)
return false;
return bounds.IsBoundsInCamera(m_Camera);
}
}
2.删除区域外的物体
对于场景物体,为每个物体初始化⼀个权重数据,每次物体被检索,权重进⾏累加,超出区域的物体则被推⼊⼀个优先级队列,该优先级队列根据权重排序,权重越⼤,表⽰在场景中滞留的时间越久,说明该物体出现的⼏率⽐较频繁,则删除的时机越靠后。⼀旦物体销毁,权重归零。
北京政治副中心未完善的地⽅
由于待加载的物体是预先计算其包围盒并插⼊四叉树/⼋叉树中,如果涉及到物体的变换,考虑到需要更新物体的包围盒,这将影响原始物体在树中的信息,例如更新后的包围盒超出了物体所在节点的包围盒,导致不得不重新计算物体在树中的位置,因此该demo中暂时不涉及被加载物体会动态变换的情况,即⽬前仅适⽤于静态物体的加载。(当然如果物体的变换不会导致包围盒更新,例如播放⼀些原地不动的动画,则是可以⽀持的)
Demo下载地址请浏览我的博客原⽂:

本文发布于:2024-09-25 18:18:33,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/212459.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:物体   节点   场景   区域   加载   数据
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议