当前位置: 首页 > news >正文

Unity——八叉树的原理与实现

八叉树原理

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

以下是八叉树的基本原理:

  1. 空间划分:

    • 初始状态:整个三维空间被表示为一个根节点,该节点包含所有的对象。
    • 递归划分:根节点被递归地划分为八个子节点,每个子节点对应于父节点的一个八分之一空间。这个过程会一直持续下去,直到达到预定义的停止条件,例如节点包含的对象数量小于某个阈值或达到最小节点大小。
  2. 节点结构:

    • 每个节点包含一个包围盒(Bounding Box)用于表示该节点所包含的空间范围。
    • 节点可能包含零个或多个对象,这些对象是该节点所表示空间范围内的物体。
    • 如果节点包含的对象数量达到某个限制,或者达到最小节点大小,不再继续划分,成为叶子节点。
  3. 添加对象:

    • 当需要向八叉树中添加对象时,从根节点开始递归地查找合适的叶子节点。
    • 将对象添加到叶子节点中。如果该节点包含的对象数量超过限制,可以考虑划分该节点。
  4. 查询操作:

    • 对于空间查询,从根节点开始,检查查询范围与每个节点的包围盒是否相交。
    • 如果相交,进一步检查该节点的子节点。
    • 递归地沿着相交的子节点继续查询,直到达到叶子节点。
    • 叶子节点包含在查询范围内的对象。
  5. 优点:

    • 空间局部性:八叉树有效地利用了物体在三维空间中的局部性,提高了检索效率。
    • 动态场景:适用于动态场景,因为对象的添加和删除只影响八叉树的局部结构。
  6. 应用领域:

    • 游戏开发:用于场景管理、碰撞检测等。
    • 计算机图形学:在光照、阴影等方面的优化中有广泛应用。
    • 计算机辅助设计(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——八叉树的原理与实现

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

android 自定义软键盘的显示和隐藏

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

基于openssl v3搭建ssl安全加固的c++ tcpserver

1 概述 tcp server和tcp client同时使用openssl库&#xff0c;可对通信双方流通的字节序列进行加解密&#xff0c;保障通信的安全。本文以c编写的tcp server和tcp client为例子&#xff0c;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的数据卷、数据卷容器,容器互联

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

ATF(TF-A)安全通告TF-V11——恶意的SDEI SMC可能导致越界内存读取(CVE-2023-49100)

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

如何查找SpringBoot应用中的请求路径(不使用idea)

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

56. 合并区间 - 力扣(LeetCode)

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

数据结构篇-03:堆实现优先级队列

本文着重在于讲解用 “堆实现优先级队列” 以及优先级队列的应用&#xff0c;在本文所举的例子中&#xff0c;可能使用优先级队列来解并不是最优解法&#xff0c;但是正如我所说的&#xff1a;本文着重在于讲解“堆实现优先级队列” 堆实现优先级队列 堆的主要应用有两个&…...

linux clickhouse 安装

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

【游戏客户端开发的进阶路线】

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

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 | 实车自动驾驶:感知、决策、执行的无缝融合

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…...

DAY31:贪心算法入门455、53、376

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

LeetCode:376.摆动序列

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

Stable Diffusion插件Recolor实现黑白照片上色

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

Android 音频焦点管理

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

大模型+自动驾驶

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

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 不创建临时变量&#xff0c;交换两数0.2 求整数转成二进制后1的总数 1.单目表达式2. 逗号表达式3. 下标访问[ ]、函数调用( )3.1 下标访问[ ]3.2 函数调用( ) 4. 结构体成员访问操作符4.1 结构体4.1.1 结构体的申明4.1.2 结构体变量的定义和初始化 4.2 结构体成…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...