Unity——八叉树的原理与实现
八叉树原理
八叉树(Octree)是一种用于在三维空间中进行空间分割的数据结构。它将三维空间递归地划分为八个子空间,每个子空间对应于一个八叉树节点。这种分割方式可以有效地组织和管理场景中的对象,提高检索效率,特别是在进行空间查询时。
以下是八叉树的基本原理:
-
空间划分:
- 初始状态:整个三维空间被表示为一个根节点,该节点包含所有的对象。
- 递归划分:根节点被递归地划分为八个子节点,每个子节点对应于父节点的一个八分之一空间。这个过程会一直持续下去,直到达到预定义的停止条件,例如节点包含的对象数量小于某个阈值或达到最小节点大小。
-
节点结构:
- 每个节点包含一个包围盒(Bounding Box)用于表示该节点所包含的空间范围。
- 节点可能包含零个或多个对象,这些对象是该节点所表示空间范围内的物体。
- 如果节点包含的对象数量达到某个限制,或者达到最小节点大小,不再继续划分,成为叶子节点。
-
添加对象:
- 当需要向八叉树中添加对象时,从根节点开始递归地查找合适的叶子节点。
- 将对象添加到叶子节点中。如果该节点包含的对象数量超过限制,可以考虑划分该节点。
-
查询操作:
- 对于空间查询,从根节点开始,检查查询范围与每个节点的包围盒是否相交。
- 如果相交,进一步检查该节点的子节点。
- 递归地沿着相交的子节点继续查询,直到达到叶子节点。
- 叶子节点包含在查询范围内的对象。
-
优点:
- 空间局部性:八叉树有效地利用了物体在三维空间中的局部性,提高了检索效率。
- 动态场景:适用于动态场景,因为对象的添加和删除只影响八叉树的局部结构。
-
应用领域:
- 游戏开发:用于场景管理、碰撞检测等。
- 计算机图形学:在光照、阴影等方面的优化中有广泛应用。
- 计算机辅助设计(CAD):用于加速物体查询。
代码实现
1.创建项目
2.创建三个C#文件,命名为OctreeNode.cs、Octree.cs和CreateOctree.cs。
OctreeNode.cs具体代码
这个类实现了八叉树节点的功能,包括分割、添加游戏对象和绘制节点的包围盒等操作。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class OctreeNode
{Bounds nodeBounds; // 节点的包围盒float minSize; // 最小节点大小Bounds[] childBounds; // 子节点的包围盒数组OctreeNode[] children = null; // 子节点数组// 构造函数,接受一个包围盒和最小节点大小作为参数public OctreeNode(Bounds b, float minNodeSize){nodeBounds = b;minSize = minNodeSize;float quarter = nodeBounds.size.y / 4.0f;float childLength = nodeBounds.size.y / 2;// 计算子节点的包围盒Vector3 childSize = new Vector3(childLength, childLength, childLength);childBounds = new Bounds[8];// 创建子节点的包围盒childBounds[0] = new Bounds(nodeBounds.center + new Vector3(-quarter, quarter, -quarter), childSize);childBounds[1] = new Bounds(nodeBounds.center + new Vector3(quarter, quarter, -quarter), childSize);childBounds[2] = new Bounds(nodeBounds.center + new Vector3(-quarter, quarter, quarter), childSize);childBounds[3] = new Bounds(nodeBounds.center + new Vector3(quarter, quarter, quarter), childSize);childBounds[4] = new Bounds(nodeBounds.center + new Vector3(-quarter, -quarter, -quarter), childSize);childBounds[5] = new Bounds(nodeBounds.center + new Vector3(quarter, -quarter, -quarter), childSize);childBounds[6] = new Bounds(nodeBounds.center + new Vector3(-quarter, -quarter, quarter), childSize);childBounds[7] = new Bounds(nodeBounds.center + new Vector3(quarter, -quarter, quarter), childSize);}// 将游戏对象添加到节点public void AddObject(GameObject go){DivideAndAdd(go);}// 分割并添加游戏对象public void DivideAndAdd(GameObject go){if (nodeBounds.size.y <= minSize){return; // 如果节点大小小于等于最小节点大小,停止分割}if (children == null){children = new OctreeNode[8];}bool dividing = false;for (int i = 0; i < 8; i++){if (children[i] == null){children[i] = new OctreeNode(childBounds[i], minSize);}// 如果游戏对象的包围盒与子节点的包围盒相交,进行分割if (childBounds[i].Intersects(go.GetComponent<Collider>().bounds)){dividing = true;children[i].DivideAndAdd(go);}}// 如果没有进行分割,将子节点数组设为nullif (dividing == false){children = null;}}// 绘制节点的包围盒public void Draw(){Gizmos.color = new Color(0, 1, 0);Gizmos.DrawWireCube(nodeBounds.center, nodeBounds.size);// 如果子节点不为空,递归绘制子节点if (children != null){for (int i = 0; i < 8; i++){if (children[i] != null){children[i].Draw(); // 递归调用}}}}
}
Octree.cs具体代码
这个类实现主要包括构造函数和将游戏对象添加到八叉树中的方法。八叉树的根节点存储在 rootNode
中,用于表示整个八叉树的结构。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Octree
{public OctreeNode rootNode; // 八叉树的根节点 // 构造函数,接受世界中的游戏对象数组和最小节点大小作为参数public Octree(GameObject[] worldObjects, float minNodeSize){Bounds bounds = new Bounds(); // 用于计算包围盒的 Bounds 对象// 遍历所有游戏对象,计算包围盒以包含它们foreach (GameObject go in worldObjects){bounds.Encapsulate(go.GetComponent<Collider>().bounds);}// 计算包围盒的最大边长float maxSize = Mathf.Max(new float[] { bounds.size.x, bounds.size.y, bounds.size.z });Vector3 sizeVector = new Vector3(maxSize, maxSize, maxSize) * 0.5f;// 将包围盒的最小和最大点调整为形成一个正方体bounds.SetMinMax(bounds.center - sizeVector, bounds.center + sizeVector);// 创建八叉树的根节点,传入包围盒和最小节点大小rootNode = new OctreeNode(bounds, minNodeSize);// 将世界中的游戏对象添加到八叉树中AddObjects(worldObjects);}// 将游戏对象添加到八叉树中public void AddObjects(GameObject[] worldObjects){foreach (GameObject go in worldObjects){rootNode.AddObject(go);}}
}
CreateOctree.cs具体代码
这个类主要用于在启动时创建八叉树对象,并在运行时通过 OnDrawGizmos 方法绘制八叉树的根节点的包围盒。在 Start 方法中,创建了一个 Octree 对象(otree),并通过传入的世界游戏对象数组和最小节点大小进行初始化。在 OnDrawGizmos 方法中,如果应用程序正在运行,则调用八叉树的根节点的 Draw 方法来绘制八叉树的结构。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CreateOctree : MonoBehaviour
{public GameObject[] worldObjects; // 存储世界中的游戏对象数组public int nodeMinsize = 5; // 八叉树的最小节点大小Octree otree; // 八叉树对象// 在启动时调用,用于初始化void Start(){otree = new Octree(worldObjects, nodeMinsize); // 创建八叉树对象并初始化}// 在每一帧更新时调用void OnDrawGizmos(){if (Application.isPlaying){otree.rootNode.Draw(); // 在运行时绘制八叉树的根节点的包围盒}}
}
3.创建一个空物体(Create empty),命名为Octree,添加CreateOctree组件。
4.创建对象,调整位置和缩放比例等。(本实验创建了4个立方体,可根据情况,自由创建其他对象,注:对象一定要有碰撞器 Collier,不如会报错:NullReferenceException: Object reference not set to an instance of an object)
5.把对象添加到 world Objects中。
6.运行项目,效果如下:
参考链接
最浅显易懂的 Unity 八叉树场景管理(保姆级)-CSDN博客
Unity 八叉树空间分割的简单实现,part1, Dividing 3D Space into an Octree_哔哩哔哩_bilibili
Unity 八叉树空间分割的简单实现,part2,Dividing 3D Space into an Octree_哔哩哔哩_bilibili
Unity 八叉树空间分割的简单实现,part3,Dividing 3D Space into an Octree_哔哩哔哩_bilibili
相关文章:

Unity——八叉树的原理与实现
八叉树原理 八叉树(Octree)是一种用于在三维空间中进行空间分割的数据结构。它将三维空间递归地划分为八个子空间,每个子空间对应于一个八叉树节点。这种分割方式可以有效地组织和管理场景中的对象,提高检索效率,特别…...

android 自定义软键盘的显示和隐藏
记一下,以后不用找在InputMethodService中有这两个方法可以看到软键盘显示状态 //软键盘隐藏 override fun onWindowHidden() {super.onWindowHidden() } //软键盘显示 override fun onWindowShown() {super.onWindowShown() } 在activity中可以通过这种方法看到软键盘显示状…...

基于openssl v3搭建ssl安全加固的c++ tcpserver
1 概述 tcp server和tcp client同时使用openssl库,可对通信双方流通的字节序列进行加解密,保障通信的安全。本文以c编写的tcp server和tcp client为例子,openssl的版本为v3。 2 安装openssl v3 2.1 安装 perl-IPC-Cmd openssl项目中的co…...

11.2 Web开发_CSS入门(❤❤)
11.2 Web开发_CSS入门❤❤ 1. CSS简介1.1 基础案例2. CSS书写的位置2.1 行内式2.2 内嵌式2.3 外链式3. CSS基础选择器3.1 标签选择器3.2 id选择器3.3 类选择器3.4 选择器优先级3.5 通配符选择器4. 多类名5. 样式的两种特性5.1 层叠性...

[docker] Docker的数据卷、数据卷容器,容器互联
一、数据卷(容器与宿主机之间数据共享) 数据卷是一个供容器使用的特殊目录,位于容器中。可将宿主机的目录挂载到数据卷上,对数据卷的修改操作立刻可见,并且更新数据不会影响镜像,从而实现数据在宿主机与容…...

ATF(TF-A)安全通告TF-V11——恶意的SDEI SMC可能导致越界内存读取(CVE-2023-49100)
目录 一、ATF(TF-A)安全通告TFV-11 (CVE-2023-49100) 二、透过事务看本质SDEI是干啥的呢? 三、CVE-2023-49100 1、GICv2 systems 2、GICv3 systems 四、漏洞修复 一、ATF(TF-A)安全通告TFV-11 (CVE-2023-49100) Title 恶意的SDEI SMC可能导致越界内存读取&am…...

如何查找SpringBoot应用中的请求路径(不使用idea)
背景 昨天有个同事向我咨询某个接口的物理表是哪个,由于公司业务较多、这块业务的确不是我负责的,也没有使用idea不能全局搜索(eclipse搜不到jar内的字符串),也就回复了不清楚。 除了自己写代码输出servlet的路径和类外,发现了一…...

56. 合并区间 - 力扣(LeetCode)
题目描述 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。 题目示例 输入:intervals [[1,3…...

数据结构篇-03:堆实现优先级队列
本文着重在于讲解用 “堆实现优先级队列” 以及优先级队列的应用,在本文所举的例子中,可能使用优先级队列来解并不是最优解法,但是正如我所说的:本文着重在于讲解“堆实现优先级队列” 堆实现优先级队列 堆的主要应用有两个&…...

linux clickhouse 安装
1、官网下载clickhouse安装包 下载地址, clickhouse分lts和stable版本,lts是长期版本,一般选择安装lts版本。 其中clickhouse-server是clickhouse服务,就是用来访问数据存储数据,clickhouse-client是用来通过命令访问数…...

【游戏客户端开发的进阶路线】
*** 游戏客户端开发的进阶路线 春招的脚步越来越近,我们注意到越来越多的同学们都在积极学习游戏开发,希望能在这个充满活力的行业中大展拳脚。 当我们思考如何成为游戏开发领域的佼佼者时,关键在于如何有效规划学习路径。 🤔 我…...

vue3+naiveUI二次封装的v-model 联动输入框
根据官网说明使用 源码 <template><div class"clw-input pt-3"><n-inputref"input":value"modelValue":type"type":title"title"clearable:disabled"disabled":size"size"placeholder&…...

百度Apollo | 实车自动驾驶:感知、决策、执行的无缝融合
🎬 鸽芷咕:个人主页 🔥 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下…...

DAY31:贪心算法入门455、53、376
理论基础 贪心算法的基本思路是通过局部最优从而达到全局最优,但是有时候局部最优并不一定导致全局最优,这样就需要动态规划的方法。但一部分题目是能通过贪心得到的。贪心的证明一般用到数学归纳法和反证法。在实际的问题中,没有统一的代码…...

LeetCode:376.摆动序列
个人主页:仍有未知等待探索-CSDN博客 专题分栏:算法_仍有未知等待探索的博客-CSDN博客 题目链接:376. 摆动序列 - 力扣(LeetCode) 一、题目 如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称…...

Stable Diffusion插件Recolor实现黑白照片上色
今天跟大家分享一个使用Recolor插件通过SD实现老旧照片轻松变彩色,Recolor翻译过来的含义就是重上色,该模型可以保持图片的构图,它只会负责上色,图片不会发生任何变化。 一:插件下载地址 https://github.com/pkuliyi…...

Android 音频焦点管理
前言 前面写过一篇类似的文章,没写完,今天再详细描述一下。 Android音频焦点申请处理 音频焦点管理的意义 两个或两个以上的 Android 应用可同时向同一输出流播放音频。系统会将所有音频流混合在一起。虽然这是一项出色的技术,但却会给用…...

大模型+自动驾驶
论文:https://arxiv.org/pdf/2401.08045.pdf 大型基础模型的兴起,它们基于广泛的数据集进行训练,正在彻底改变人工智能领域的面貌。例如SAM、DALL-E2和GPT-4这样的模型通过提取复杂的模式,并在不同任务中有效地执行,从…...

openssl3.2 - 测试程序的学习 - test\aesgcmtest.c
文章目录 openssl3.2 - 测试程序的学习 - test\aesgcmtest.c概述笔记能学到的流程性内容END openssl3.2 - 测试程序的学习 - test\aesgcmtest.c 概述 openssl3.2 - 测试程序的学习 aesgcmtest.c 工程搭建时, 发现没有提供 test_get_options(), cleanup_tests(), 需要自己补上…...

C语言——操作符详解2
目录 0.过渡0.1 不创建临时变量,交换两数0.2 求整数转成二进制后1的总数 1.单目表达式2. 逗号表达式3. 下标访问[ ]、函数调用( )3.1 下标访问[ ]3.2 函数调用( ) 4. 结构体成员访问操作符4.1 结构体4.1.1 结构体的申明4.1.2 结构体变量的定义和初始化 4.2 结构体成…...

(免费领源码)java#Springboot#mysql旅游景点订票系统68524-计算机毕业设计项目选题推荐
摘 要 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现实运用中,应用软件的工作…...

帝国cms7.5 支付升级优化版文库范文自动生成word/PDF文档付费复制下载带支付系统会员中心整站模板源码sitemap百度推送+安装教程
帝国cms7.5 支付升级优化版文库范文自动生成word/PDF文档付费复制下载带支付系统会员中心整站模板源码sitemap百度推送+安装教程 (购买本专栏可免费下载栏目内所有资源不受限制,持续发布中,需要注意的是,本专栏为批量下载专用,并无法保证某款源码或者插件绝对可用,介意不…...

【node】关于npm、yarn、npx的区别与使用
文章目录 npm (Node Package Manager):安装依赖运行脚本 npx:执行项目依赖中的命令 yarn:安装依赖eg.使用npx yarn install 的作用 npm (Node Package Manager): 用途: npm 是 Node.js 官方提供的包管理工具,用于安装、管理和分享 JavaScript 代码包。安…...

力扣0099——恢复二叉搜索树
恢复二叉搜索树 难度:中等 题目描述 给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 。 示例1 输入: root [1,3,null,null,2] 输出:[3,1,null,nul…...

机器学习核心算法
目录 逻辑回归 算法原理 决策树 决策树算法概述 树的组成 决策树的训练与测试 切分特征 衡量标准--熵 信息增益 决策树构造实例 连续值问题解决 预剪枝方法 分类与回归问题解决 决策树解决分类问题步骤 决策树解决回归问题步骤 决策树代码实例 集成算法 Baggi…...

libjsoncpp 的编译和交叉编译
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...

【Unity美术】如何用3DsMax做一个水桶模型
👨💻个人主页:元宇宙-秩沅 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 秩沅 原创 👨💻 收录于专栏:Uni…...

如何用一根网线和51单片机做简单门禁[带破解器]
仓库:https://github.com/MartinxMax/Simple_Door 支持原创是您给我的最大动力… 原理 -基础设备代码程序- -Arduino爆破器程序 or 51爆破器程序- 任意选一个都可以用… —Arduino带TFT屏幕——— —51带LCD1602——— 基础设备的最大密码长度是0x7F,因为有一位…...

在 VUE 项目中,使用 Axios 请求数据时,提示跨域,该怎么解决?
在 VUE 项目开发时,遇到个问题,正常设置使用 Axios 库请求数据时,报错提示跨域问题。 那在生产坏境下,该去怎么解决呢? 其可以通过以下几种方式去尝试解决: 1、设置允许跨域请求的响应头 1.1 在响应头中…...

1.【Vue3】前端开发引入、Vue 简介
1. 前端开发引入 1.1 前端开发前置知识 通过之前的学习,已经通过 SpringBoot 和一些三方技术完成了大事件项目的后端开发。接下来开始学习大事件项目的前端开发,前端部分借助两个框架实现: Vue3(一个 JS 框架)基于 …...