【Unity】八叉树 优化场景

122 篇文章 2 订阅
7 篇文章 3 订阅

BStandShaderResources/OcTree1.unitypackage at master · AMikeW/BStandShaderResources (github.com)

 

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class DcTreeManager : MonoBehaviour
{
    public DcTreeNode MainDcTreeNode;
    private Camera camera;
    private Plane[] plane;
    void Start()
    {
        Renderer[] renderers = this.transform.GetComponentsInChildren<Renderer>();
        List<Renderer> rendererList = new List<Renderer>();
        rendererList.AddRange(renderers);
        if (renderers != null && renderers.Length > 0)
        {
            MainDcTreeNode = new DcTreeNode(new Bounds(Vector3.zero, new Vector3(25, 25, 25)), 0);
            MainDcTreeNode.GenerateChildNodes(rendererList, true);
        }
        else
        {
            Debug.LogError("一个renderers都没有");
        }
        camera = Camera.main;
    }

    private void Update()
    {
        MainDcTreeNode.RefreshVisiable((bounds) =>
        {
            plane = GeometryUtility.CalculateFrustumPlanes(this.camera);
            return GeometryUtility.TestPlanesAABB(plane, bounds);
        });
    }

    private void OnDrawGizmos()
    {
        if (UnityEditor.EditorApplication.isPlaying)
        {
            MainDcTreeNode.Draw((bounds) => { Gizmos.DrawWireCube(bounds.center, bounds.size); });
        }
    }

}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DcTreeNode
{
    static Dictionary<int, Vector3> side2Dir = new Dictionary<int, Vector3>()
    {
        [0] = new Vector3(-1, -1, -1).normalized, //lb+ lb代表left bottom左下 +代表正面
        [1] = new Vector3(-1, 1, -1).normalized, //lt+
        [2] = new Vector3(1, -1, -1).normalized, //rb+
        [3] = new Vector3(1, 1, -1).normalized, //rt+
        [4] = new Vector3(-1, -1, 1).normalized, //lb- 左下 背面
        [5] = new Vector3(-1, 1, 1).normalized, //lt-
        [6] = new Vector3(1, -1, 1).normalized, //rb-
        [7] = new Vector3(1, 1, 1).normalized, //rt-
    };

    static Dictionary<int, Color> side2Color = new Dictionary<int, Color>()
    {
        [0] = Color.red, //lb+  同上
        [1] = Color.yellow, //lt+
        [2] = Color.green, //rb+
        [3] = Color.blue, //rt+
        [4] = Color.cyan, //lb-
        [5] = Color.gray, //lt-
        [6] = Color.black, //rb-
        [7] = Color.white, //rt-
    };
    private int side;
    private Bounds nodeBounds;
    private List<DcTreeNode> childNodes;
    private List<Renderer> containRenderers;
    public DcTreeNode(Bounds bounds, int side)
    {
        childNodes = new List<DcTreeNode>();
        nodeBounds = bounds;
        this.side = side;
    }

    public void Draw(Action<Bounds> action)
    {
        Gizmos.color = side2Color[side];
        action(nodeBounds);
        foreach (var v in childNodes)
        {
            v.Draw(action);
        }
    }
    public void RefreshVisiable(Func<Bounds, bool> func)
    {
        bool isOn = func(nodeBounds);
        if (isOn)
        {
            foreach (var v in childNodes)
            {
                v.RefreshVisiable(func);
            }
        }
        if (containRenderers != null)
        {
            foreach (var v in containRenderers)
            {
                v.enabled = isOn;
            }
        }
    }
    /// <summary>
    /// 生成8个子节点
    /// </summary>
    public void GenerateChildNodes(List<Renderer> renderers, bool isFirst = false)
    {
        containRenderers = renderers;

        List<Renderer> tempAlreadyAddRenderers = new List<Renderer>();

        float halfSize = this.nodeBounds.size.x * 0.5f;
        float length = new Vector3(halfSize, halfSize, halfSize).magnitude / 2;
        for (int i = 0; i < 8; i++)
        {
            Bounds bounds = new Bounds();
            bounds.size = this.nodeBounds.size * 0.5f;
            bounds.center = this.nodeBounds.center + side2Dir[i] * length;
            List<Renderer> tempNodeRenderers = new List<Renderer>();
            foreach (var v in containRenderers)
            {
                if (bounds.Contains(v.bounds.min) && bounds.Contains(v.bounds.max))
                {
                    tempNodeRenderers.Add(v);
                }
            }
            foreach (var v in tempNodeRenderers)
            {
                containRenderers.Remove(v);
            }
            DcTreeNode node;
            if (isFirst)
            {
                node = new DcTreeNode(bounds, i);
            }
            else
            {
                node = new DcTreeNode(bounds, side);
            }
            childNodes.Add(node);
            if (tempNodeRenderers.Count > 0)
            {
                node.GenerateChildNodes(tempNodeRenderers);
            }
        }
    }
}

实现思路:生成一个适当的Bounds盒子区域进行开始八叉树遍历,每一次切割出等体积的8个子方块,必须满足至少有一个物体AABB盒完全包含在当前八叉树节点Bounds才进行切割8个子节点。

这里的切割方式是最简单无脑的所以很简单,一般都要有一些算法支持 不然会有很多空隙导致搜索变慢。(可自行优化)

Unity是一款功能强大的游戏开发引擎,可以轻松创建各种类型的游戏和应用程序。八叉树是一种用于空间划分和快速查找的数据结构。在Unity中,我们可以基于相机实现一个八叉树来提高场景中物体的渲染效率和碰撞检测性能。 首先,我们需要创建一个空白的脚本,在其中定义八叉树类。在这个类中,我们可以实现以下几个重要方法: 1.构建八叉树:根据场景中的物体位置和相机视野范围,将整个场景划分为小块。可以通过递归实现该方法,将场景划分为足够小的部分,直到满足某种条件(例如:物体数量小于一定值)。 2.插入物体:将场景中的物体根据其位置插入到相应的叶子节点中。可以通过递归方法实现该过程,逐级检查到达相应的叶子节点。 3.删除物体:如果一个物体移动到了不同的位置,我们需要相应地从八叉树中移除它。可以通过递归方法从根节点开始找到该物体所在的叶子节点,并将其从叶子节点中移除。 4.查询可见物体:根据相机的视野范围,从八叉树中找到所有在视野范围内的物体。可以通过递归方法从根节点开始,根据相机视锥体与每个节点的相交关系进行判断。 通过基于相机的八叉树,我们可以在渲染过程中只渲染与相机视野内相交的物体,提高渲染效率。同时,我们可以通过八叉树对物体进行碰撞检测,只检测与相机视野内相交的物体,提高碰撞检测性能。 通过上述方法,我们可以在Unity中基于相机实现一个八叉树,提高场景中物体的渲染效率和碰撞检测性能,从而优化游戏的整体性能和用户体验。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值