节点代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Node
{
public Bounds bound;
public int myDepth;//当前层数
public Tree tree;
public List<ObjData> datas = new List<ObjData>();//数据
public Node[] childs;//子节点
public Vector2[] bif = new Vector2[]
{
new Vector2(-1,1),
new Vector2(1,1),
new Vector2(-1,-1),
new Vector2(1,-1)
};
public Node(Bounds bound, int myDepth, Tree tree)
{
this.bound = bound;
this.myDepth = myDepth;
this.tree = tree;
}
public void InsertData(ObjData data)
{
//层级没到上限 且 没有子节点 可以创建子节点
if (myDepth < tree.maxDepth && childs == null)
{
CreatChild();
}
if (childs != null)
{
for (int i = 0; i < childs.Length; i++)
{
//判断数据的位置是否归属于该子节点的区域
if (childs[i].bound.Contains(data.pos))
{
//继续去下一层查找
childs[i].InsertData(data);
break;
}
}
}
else
{
datas.Add(data);
}
}
public void CreatChild()
{
//创建树指定的节点
childs = new Node[tree.maxChildCount];
for (int i = 0; i < tree.maxChildCount; i++)
{
//计算相对坐标
Vector3 center = new Vector3(bif[i].x * bound.size.x / 4, 0, bif[i].y * bound.size.z / 4);
//计算大小
Vector3 size = new Vector3(bound.size.x / 2, 0, bound.size.z / 2);
//设置矩阵
Bounds childbound = new Bounds(center + bound.center, size);
//给子节点赋值
childs[i] = new Node(childbound, myDepth + 1, tree);
}
}
public void DrawBound()
{
//有数据画蓝色框框
if (datas.Count != 0)
{
Gizmos.color = Color.blue;
Gizmos.DrawWireCube(bound.center, bound.size - Vector3.one * 0.1f);
}
else//没数据画绿色框框
{
Gizmos.color = Color.green;
Gizmos.DrawWireCube(bound.center, bound.size - Vector3.one * 0.1f);
}
//有子物体让子物体去画
if (childs != null)
{
for (int i = 0; i < childs.Length; ++i)
{
childs[i].DrawBound();
}
}
}
public void TriggerMove(Plane[] planes)
{
//有子物体让子物体去判断是否重叠
if (childs != null)
{
for (int i = 0; i < childs.Length; ++i)
{
childs[i].TriggerMove(planes);
}
}
for (int i = 0; i < datas.Count; i++)
{
//判断矩阵与视锥体6个面是否重叠
datas[i].prefab.SetActive(GeometryUtility.TestPlanesAABB(planes, bound));
}
}
}
树代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tree
{
public Bounds bound;
private Node root;//根
public int maxDepth = 6;//最多层数
public int maxChildCount = 4;//最多分块
public Tree(Bounds bound)
{
this.bound = bound;
this.root = new Node(bound, 0, this);
}
//插入数据
public void InsertData(ObjData data)
{
root.InsertData(data);
}
public void DrawBound()
{
root.DrawBound();
}
public void TriggerMove(Plane[] planes)
{
root.TriggerMove(planes);
}
}
四叉树的使用与视锥体剔除
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreatCube : MonoBehaviour
{
public GameObject cube;
public int n = 10;
public Bounds mainBound;
Tree tree;//树
bool startEnd = false;//是否初始化完毕
public Camera cam;//相机
Plane[] planes;//视锥体的6个面
// Start is called before the first frame update
void Start()
{
Init();
}
public void Init()
{
planes = new Plane[6];//开辟内存
//初始化场景最大分块
Bounds bounds = new Bounds(transform.position, new Vector3(2 * n, 0, 2 * n));
//创建树
tree = new Tree(bounds);
//创建预制体
for (int x = -n; x < n; x++)
{
for (int z = -n; z < n; z++)
{
if (Random.Range(0,10) < 1)
{
GameObject c = Instantiate(cube, transform);
c.transform.position = new Vector3(x, 0, z);
//将预制体数据存入树
tree.InsertData(new ObjData(c, c.transform.position, c.transform.eulerAngles));
}
}
}
startEnd = true;
}
// Update is called once per frame
void Update()
{
if (startEnd)//判断初始化结束后
{
//给视锥体的6个面赋值
GeometryUtility.CalculateFrustumPlanes(cam, planes);
//通过树判断是否显示
tree.TriggerMove(planes);
}
}
private void OnDrawGizmos()
{
if (startEnd)//判断初始化结束后
{
//通过树绘制包围盒
tree.DrawBound();
}
else
{
Gizmos.DrawWireCube(mainBound.center, mainBound.size);
}
}
}