四叉树场景加载

1.4k words

Desc:

用于减少场景中物体的数量

原理

将地图分为存在上限的树,树每个非根节点可以最大存在四个子节点,物体如果存在两个及以上区域的时候,挂载在上一层节点上

实现

接口

INode.cs:

Bounds bound{get;set;}
// 初始化节点
void InsertNodeData(NodeData data);
// 在视角内,检查当前节点是否在摄像机裁剪区域内,不在则调用 Outside 回收
void Inside(Camera camera);
// 不在视角
void Outside(Camera camera);
// 编辑器模式下进行绘制
void DrawBound();

Node.cs:

实现INode接口,定义深度和子节点

Tree.cs:

定义最大层数

NodeData.cs:

存储每个节点的数据,通过编辑器初始化

NodeManager.cs:

持有当前场景中所有节点的引用,控制节点的加载和释放

QuadTreeManager.cs:

在Update中,调用tree的Inside

方法:

拓展 Bounds

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static bool CheckBoundIsInCamera(this Bounds bound, Camera camera, float viewRatio = 1)
{
System.Func<Vector4, int> ComputeOutCode = (projectionPos) =>
{
int _code = 0;
if (projectionPos.x < -projectionPos.w) _code |= 1;
if (projectionPos.x > projectionPos.w) _code |= 2;
if (projectionPos.y < -projectionPos.w) _code |= 4;
if (projectionPos.y > projectionPos.w) _code |= 8;
if (projectionPos.z < -projectionPos.w) _code |= 16;
if (projectionPos.z > projectionPos.w) _code |= 32;
return _code;
};

Vector4 worldPos = Vector4.one;
int code = 63;
for (int i = -1; i <= 1; i += 2)
{
for (int j = -1; j <= 1; j += 2)
{
for (int k = -1; k <= 1; k += 2)
{
worldPos.x = bound.center.x + i * bound.extents.x;
worldPos.y = bound.center.y + j * bound.extents.y;
worldPos.z = bound.center.z + k * bound.extents.z;

code &= ComputeOutCode(camera.projectionMatrix * camera.worldToCameraMatrix * worldPos * viewRatio);
}
}
}
return code == 0 ? true : false;
}

参考

github