【Unity】八叉树 优化场景

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个子节点。

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

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇
下一篇>>