Unity3D 八叉树划分空间和可视化

也许更好的阅读体验

成果展示

所有层
第一层

第二层

代码

OctreeNode
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OctreeNode
{
    //空间内包含的物体
    public List<GameObject> areaObjects;
    //空间中心
    public Vector3 center;
    //空间大小
    public float size;
    //子节点个数 
    private int kidCount = 8;
    //子节点
    public OctreeNode[] kids;
    //构造函数
    public OctreeNode (Vector3 center, float size)
    {
        this.center = center;
        this.size = size;
        kids = new OctreeNode[kidCount];
        areaObjects = new List<GameObject>();
    }
    #region 八个子节点中心对应的偏移方向
    public static Vector3[] centerOffset = new Vector3[8] {
        new Vector3 (-1, 1, -1),
        new Vector3 (1, 1, -1),
        new Vector3 (-1, 1, 1),
        new Vector3 (1, 1, 1),
        new Vector3 (-1, -1, -1),
        new Vector3 (1, -1, -1),
        new Vector3 (-1, -1, 1),
        new Vector3 (1, -1, 1)
    };
    #endregion

    #region 空间和内部物体管理
    //空间内物体树
    public int objectCount => areaObjects.Count;
    //把该空间画出来
    public void DrawGizmos ()
    {
        Gizmos.DrawWireCube(center, Vector3.one * size);
    }
    //判断是否包含某个点
    public bool Contains (Vector3 position)
    {
        float halfSize = size / 2.0f;
        return Mathf.Abs(position.x - center.x) <= halfSize &&
            Mathf.Abs(position.y - center.y) <= halfSize &&
            Mathf.Abs(position.z - center.z) <= halfSize;
    }
    //清理空间内物体
    public void Clear ()
    {
        areaObjects.Clear();
    }
    //添加物体
    public void AddGameObject (GameObject obj)
    {
        areaObjects.Add(obj);
    }
    #endregion

}

Orctree
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
using Unity.VisualScripting;
using UnityEngine;

//可视化模式
public enum OctreeDebugMode
{
    AllDepth,
    TargetDepth
}
public class Octree : MonoBehaviour
{

    #region 物体生成和构建八叉树
    //生成物体数
    [Range(0, 500)]
    public int genCount = 500;
    //物体生成范围
    [Range(1, 300)]
    public float range = 100;
    //生成的物体
    public List<GameObject> sceneObjects;
    //Octree最大层数
    [Range(1, 8)]
    public int maxDepth = 3;
    //Octree的根节点
    public OctreeNode root;


    // Start is called before the first frame update
    void Start()
    {
        GenObjects();
        OctreePartition();
    }

    //随机生成一些cube
    private void GenObjects()
    {
        float genRange = range * 0.5f;
        sceneObjects = new List<GameObject>();

        for (int i = 0; i < genCount; ++i)
        {
            GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
            obj.transform.position = new Vector3(Random.Range(-genRange, genRange),
                Random.Range(-genRange, genRange),
                Random.Range(-genRange, genRange));
            obj.hideFlags = HideFlags.HideInHierarchy;
            sceneObjects.Add(obj);
        }
    }
    //进行八叉树划分
    private void OctreePartition ()
    {
        //设定根节点
        Vector3 origin = Vector3.one;
        root = new OctreeNode(Vector3.zero, range);
        root.areaObjects = sceneObjects;
        //往下生成八叉树 根节点层数为1
        GenerateOcetree(root, range, 2);
    }
    //递归往下生成八叉树
    private void GenerateOcetree (OctreeNode root, float range, int depth)
    {
        //depth是当前生成的层数
        if (depth > maxDepth) return;
        //下一层的大小
        float halfRange = range / 2.0f;
        //根节点偏移量
        float rootOffset = halfRange / 2.0f;
        for (int i = 0; i < 8; ++i)
        {
            Vector3 origin = root.center + OctreeNode.centerOffset[i] * rootOffset;
            root.kids[i] = new OctreeNode(origin, halfRange);
        }
        PartitionSceneObjects(root);
        for (int i = 0; i < 8; ++i)
        {
            if (root.kids[i].objectCount >= 2) GenerateOcetree(root.kids[i], halfRange, depth + 1);
        }
    }
    //把空间内物体划分给子节点
    private void PartitionSceneObjects(OctreeNode root)
    {
        foreach (GameObject obj in root.areaObjects)
        {
            foreach (OctreeNode kid in root.kids)
            {
                if (kid.Contains(obj.transform.position))
                {
                    kid.AddGameObject(obj);
                }
            }
        }
    }
    #endregion

    #region 可视化
    //是否显示八叉树
    public bool showOctree = true;
    //可视化类型
    public OctreeDebugMode octreeDebugMode;
    //可视化层数
    [Range(0, 8)]
    public int displayDepth = 3;
    //不同深度的可视化颜色
    public Color[] displayColor;
    private void OnDrawGizmos()
    {
        if (root == null) return;
        if (showOctree && displayDepth <= maxDepth)
        {
            //显示所有深度的空间范围
            if (octreeDebugMode == OctreeDebugMode.AllDepth)
            {
                DrawNode(root, 1);
            }
            //显示指定深度的空间范围(第displayDepth层)
            else if (octreeDebugMode == OctreeDebugMode.TargetDepth)
            {
                if (displayDepth > 0 && displayColor.Length >= displayDepth) 
                {
                    Color color = displayColor[displayDepth - 1];
                    color.a = 0.5f;
                    Gizmos.color = color;
                    DrawTargetDepth(root, displayDepth);
                }
            }
        }
    }
    //绘制所有节点 当前深度为depth
    private void DrawNode(OctreeNode root, int depth)
    {
        if (root == null || depth > maxDepth) return;
        Color color = displayColor[depth - 1];
        color.a = 0.5f;
        Gizmos.color = color;
        root.DrawGizmos();
        foreach (OctreeNode kid in root.kids)
        {
            DrawNode(kid, depth + 1);
        }
    }
    //绘制指定层
    private void DrawTargetDepth (OctreeNode root, int targetDepth)
    {
        --targetDepth;
        if (root == null || targetDepth < 0) return;
        Debug.Log(targetDepth);
        if (targetDepth == 0)
        {
            root.DrawGizmos();
            return;
        }
        foreach (OctreeNode kid in root.kids)
        {
            DrawTargetDepth(kid, targetDepth);
        }
    }
    #endregion
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/743574.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI 收购桌面实时协作公司 Multi;iOS 18 开放 iPhone 镜像测试丨RTE 开发者日报 Vol.231

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

开发RpcProvider的网络服务

首先更改src的CMakeLists.txt的内容为&#xff1a; #当前目录的所有源文件放入SRC_LIST aux_source_directory(. SRC_LIST)#生成SHARED动态库 #add_library(mprpc SHARED ${SRC_LIST})#由于muduo是静态库&#xff0c;为了使用muduo&#xff0c;将mprpc也生成为静态库 add_libr…

2024最新算法:鹅优化算法(GOOSE Algorithm,GOOSE)求解23个函数,MATLAB代码

一、算法介绍 鹅优化算法&#xff08;GOOSE Algorithm&#xff0c;GOOSE)是2024年提出的一种智能优化算法&#xff0c;该算法从鹅的休息和觅食行为获得灵感&#xff0c;当鹅听到任何奇怪的声音或动作时&#xff0c;它们会发出响亮的声音来唤醒群中的个体&#xff0c;并保证它们…

C++ 基础:指针和引用浅谈

指针 基本概念 在C中&#xff0c;指针是存储其他变量的内存地址的变量。 我们在程序中声明的每个变量在内存中都有一个关联的位置&#xff0c;我们称之为变量的内存地址。 如果我们的程序中有一个变量 var&#xff0c;那么&var 返回它的内存地址。 int main() {int var…

A股3000点下方继续跳水,股民都跌懵了。

今天的A股跌懵了&#xff0c;让人几乎无法呼吸&#xff0c;盘面上出现2个重要信号&#xff0c;不废话&#xff0c;直接说重点&#xff1a; 1、今天两市又跳水了&#xff0c;但绝大多数的个股已经拒绝下跌&#xff0c;市场已然处于一个阶段底部&#xff0c;短线反弹随时可能出现…

昇思25天学习打卡营第1天|新手上路

这里写自定义目录标题 打卡昇思MindSpore扫盲快速入门 打卡 昇思MindSpore扫盲 第一节基本是一个mindspore的科普扫盲。大概介绍一通mindspore的一些架构&#xff0c;feature&#xff0c;以及其对比于其他同类框架的优势。简单扫读了一遍大概有点印象直接跳过。 快速入门 这…

面相对象程序设计

面相对象程序设计包含内容如下 局域网聊天程序设网页浏览器设计电子日历记事本的设计 以其中的一个的报告进行举例 1需求与总体设计 1 1.1需求分析 1 1.2总体设计方案 1 1.2&#xff0e;1系统功能分析以及功能表 1 1.3系统类图的关系以及表之间的联系 2 2详细设计 3 2.1 Manag…

python操作excel

1. 引言 在数据处理和自动化办公领域&#xff0c;Python以其简洁的语法和强大的库&#xff0c;成为许多数据科学家和开发者的首选语言。本文将带你一步步学习如何使用Python操作Excel。 2. 环境准备 在开始之前&#xff0c;请确保你的环境中安装了Python和以下库&#xff1a…

数据结构-----【链表:基础】

链表基础 1、链表的理论基础 1&#xff09;基础&#xff1a; 链表&#xff1a;通过指针串联在一起的线性结构&#xff0c;每个节点由两部分组成&#xff0c;一个是数据域&#xff0c;一个是指针域&#xff08;存放指向下一个节点的指针&#xff09;&#xff0c;最后一个指针…

2024年必备的15个免费 SVG 设计资源

在动态设计领域&#xff0c;SVG&#xff08;可缩放矢量图形&#xff09;已成为设计师打造响应迅速、清晰且适应性强的视觉效果的必备工具。 这些设计非常适合幻灯片 PowerPoint 演示文稿、应用程序设计、网站设计、原型设计、社交媒体帖子等。 在这篇文章中&#xff0c;我们将…

LeetCode刷题之HOT100之最小栈

听歌&#xff0c;做题&#xff01; 1、题目描述 2、逻辑分析 拿到题目一脸懵&#xff0c;有点看不懂啥意思&#xff0c;看了题解才知道啥意思。要实现在常数时间内检索到最小元素的栈&#xff0c;需要使用一个辅助栈来每次存入最小值。 使用Deque作为栈的实现是因为它提供了…

最热门的智能猫砂盆好不好用?这期统统告诉你!

身为上班族的我们&#xff0c;常常被工作和出差填满日程。忘记给猫咪铲屎也不是一次两次了。但我们必须意识到&#xff0c;不及时清理猫砂盆不仅会让猫咪感到不适&#xff0c;还可能引发泌尿系统感染、皮肤疾病等健康问题。为了解决这个问题&#xff0c;越来越多的铲屎官开始将…

Unity数据持久化3——Json

概述 基础知识 Json文件格式 Json基本语法 练习 可以搜索&#xff1a;Json在线&#xff0c;复制代码进去解析是否写错了。 Excel转Json C#读取存储Json文件 JsonUtility using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine;[Sy…

使用Birdeye访问Sui上加密市场数据

是一个链上加密交易数据聚合器&#xff0c;于2024年4月开始整合Sui数据。 个人DeFi用户可以在Birdeye的首页找到丰富的数据&#xff0c;包括关于主流区块链上的tokens、交易和交易者钱包的详细信息。 Birdeye提供API和WebSockets数据服务&#xff0c;涵盖token价格和其他DeFi…

【jupyter notebook】解决打不开以及安装扩展插件的问题

文章目录 问题描述问题 1解决问题 2解决 问题描述 问题 1 在自定义的虚拟环境下&#xff0c;安装 jupyter notebook 6.4.12 版本时&#xff0c;报以下错误&#xff1a; 解决 查了一些 解决方法&#xff0c;执行以下命令即可解决&#xff1a; conda install traitlets5.9.0 …

PS系统教程27

Photoshop与Camera Raw Camera本身是作为插件存在的&#xff0c;处理对象Raw格式&#xff08;高清格式的图片标准&#xff09; JPG是压缩格式 Camera是源数据包&#xff0c;无损高清数据包 通道 通道只有黑白灰三种颜色&#xff0c;图层类似于前台&#xff0c;通道就是后台…

代码随想录算法训练营第七十天 | 108.冗余连接、109.冗余连接||

108.冗余连接 文字讲解&#xff1a;108. 冗余连接 | 代码随想录 解题思路 节点A 和节点 B 不在同一个集合&#xff0c;那么就可以将两个 节点连在一起 已经判断 节点A 和 节点B 在在同一个集合&#xff08;同一个根&#xff09;&#xff0c;如果将 节点A 和 节点B 连在一起就…

LabVIEW与PLC通讯方式及比较

LabVIEW与PLC之间的通讯方式多样&#xff0c;包括使用MODBUS协议、OPC&#xff08;OLE for Process Control&#xff09;、Ethernet/IP以及串口通讯等。这些通讯方式各有特点&#xff0c;选择合适的通讯方式可以提高系统的效率和稳定性。以下将详细介绍每种通讯方式的特点、优点…

Typora自动保存和找回未保存文件

在用typora做记录的时候没有手动保存&#xff0c;然后电脑崩了&#xff0c;还好有找回未保存文件功能&#xff0c;在这里存一下。 找到未保存的文件版本后将其内容复制到新文件即可。

【AI落地应用实战】如何高效检索与阅读论文——302.AI学术论文工具评测

一、引言 作为一名学术领域的探索者&#xff0c;我们都知道&#xff0c;检索和阅读论文是我们获取知识、启发思考、验证假设的基石&#xff0c;也是日常学习中必不可少的基本功之一。然而在浩瀚的学术海洋中&#xff0c;如何快速、准确地找到我们需要的论文&#xff0c;就像是…