C++自研游戏引擎-碰撞检测组件-八叉树AABB检测算法实现

八叉树碰撞检测是一种在三维空间中高效处理物体碰撞检测的算法,其原理可以类比为一个管理三维空间物体的智能系统。这个示例包含两个部分:八叉树部分用于宏观检测,AABB用于微观检测。AABB可以更换为均值或节点检测来提高检测精度。

八叉树的构建

  1. 确定根节点范围
    首先要为整个碰撞检测系统确定一个初始范围,这就像是为所有参与碰撞检测的物体划定一个 “活动区域”。这个范围是一个能够完全容纳所有待检测物体的三维立方体空间,它构成了八叉树的根节点。
  2. 递归分割空间
    为了更高效地管理和查找物体,八叉树会对这个初始的大立方体空间进行递归分割。具体做法是沿着三个坐标轴的中点,将大立方体分割成八个小立方体,每个小立方体对应根节点的一个子节点。之后,系统会检查每个子节点所包含的物体数量:
    若某个子节点中的物体数量小于预设的阈值,就认为该区域内的物体分布较为稀疏,无需再进行分割,这些物体就存储在该节点中。
    若物体数量超过阈值,说明该区域物体较为密集,需要进一步细分。于是会将这个节点的空间继续分割成八个更小的子空间,并对每个子空间重复上述检查过程,直到满足停止条件。
    碰撞检测过程
  3. 插入物体
    在将物体的轴对齐包围盒(AABB)插入八叉树时,系统会从根节点开始判断物体的 AABB 与当前节点的空间是否相交:
    如果不相交,表明该物体不在当前节点所管理的空间范围内,无需在此节点存储该物体。
    如果相交,则将物体插入当前节点。若当前节点已经被分割成子节点,系统会进一步判断物体的 AABB 与哪个子节点的空间相交,并将物体插入对应的子节点中。
  4. 查询碰撞
    当需要检测某个物体(用其 AABB 表示)是否与其他物体发生碰撞时,系统会从八叉树的根节点开始查询:
    若该物体的 AABB 与当前节点的空间不相交,说明该节点及其子节点中的物体都不可能与该物体发生碰撞,无需继续检查该节点及其子树。
    若相交,则检查当前节点中存储的物体的 AABB 与该物体的 AABB 是否相交。
    若当前节点有子节点,系统会递归地对每个子节点进行相同的查询操作,直到遍历完所有可能发生碰撞的节点。
    八叉树碰撞检测的优缺点
    优点
    高效性:通过对三维空间进行递归分割,八叉树将碰撞检测的范围缩小到可能发生碰撞的区域,避免了对所有物体进行两两比较,从而显著减少了不必要的计算,提高了碰撞检测的效率。在处理大量物体的场景中,这种优势更为明显。
    适应性:八叉树能够根据物体在空间中的实际分布情况自适应地进行空间划分,对于物体分布不均匀的场景也能有效地组织和管理物体。
    缺点
    构建和维护成本较高:构建八叉树需要对空间进行递归分割,并将物体分配到相应的节点中,这需要一定的时间和空间开销。特别是在物体频繁移动或新增、删除物体的场景中,需要不断更新八叉树的结构,增加了维护成本。
    存在精度问题:使用 AABB 来近似表示物体可能会导致一定的精度损失,尤其是对于形状复杂的物体,AABB 可能无法精确地描述其外形,从而产生误判。

C++代码

#include <iostream>
#include <vector>
#include <memory>// 定义三维向量结构体
struct Vec3 {float x, y, z;Vec3(float x = 0, float y = 0, float z = 0) : x(x), y(y), z(z) {}
};// 定义 AABB 结构体
struct AABB {Vec3 min;Vec3 max;AABB(const Vec3& min, const Vec3& max) : min(min), max(max) {}// 判断两个 AABB 是否相交bool intersects(const AABB& other) const {return (min.x <= other.max.x && max.x >= other.min.x) &&(min.y <= other.max.y && max.y >= other.min.y) &&(min.z <= other.max.z && max.z >= other.min.z);}
};// 定义八叉树节点类
class OctreeNode {
public:AABB bounds;std::vector<AABB> objects;std::vector<std::unique_ptr<OctreeNode>> children;OctreeNode(const AABB& bounds) : bounds(bounds) {}// 插入 AABB 到节点中void insert(const AABB& object) {if (children.empty()) {if (objects.size() < 8) {objects.push_back(object);} else {split();insert(object);}} else {for (auto& child : children) {if (child->bounds.intersects(object)) {child->insert(object);}}}}// 分割节点void split() {Vec3 center((bounds.min.x + bounds.max.x) / 2, (bounds.min.y + bounds.max.y) / 2, (bounds.min.z + bounds.max.z) / 2);children.resize(8);children[0] = std::make_unique<OctreeNode>(AABB(bounds.min, center));children[1] = std::make_unique<OctreeNode>(AABB(Vec3(center.x, bounds.min.y, bounds.min.z), Vec3(bounds.max.x, center.y, center.z)));children[2] = std::make_unique<OctreeNode>(AABB(Vec3(bounds.min.x, center.y, bounds.min.z), Vec3(center.x, bounds.max.y, center.z)));children[3] = std::make_unique<OctreeNode>(AABB(Vec3(center.x, center.y, bounds.min.z), Vec3(bounds.max.x, bounds.max.y, center.z)));children[4] = std::make_unique<OctreeNode>(AABB(Vec3(bounds.min.x, bounds.min.y, center.z), Vec3(center.x, center.y, bounds.max.z)));children[5] = std::make_unique<OctreeNode>(AABB(Vec3(center.x, bounds.min.y, center.z), Vec3(bounds.max.x, center.y, bounds.max.z)));children[6] = std::make_unique<OctreeNode>(AABB(Vec3(bounds.min.x, center.y, center.z), Vec3(center.x, bounds.max.y, bounds.max.z)));children[7] = std::make_unique<OctreeNode>(AABB(center, bounds.max));for (const auto& object : objects) {for (auto& child : children) {if (child->bounds.intersects(object)) {child->insert(object);}}}objects.clear();}// 检测与指定 AABB 的碰撞void query(const AABB& object, std::vector<AABB>& result) const {if (bounds.intersects(object)) {for (const auto& obj : objects) {if (obj.intersects(object)) {result.push_back(obj);}}for (const auto& child : children) {child->query(object, result);}}}
};// 定义八叉树类
class Octree {
public:std::unique_ptr<OctreeNode> root;Octree(const AABB& bounds) : root(std::make_unique<OctreeNode>(bounds)) {}// 插入 AABB 到八叉树中void insert(const AABB& object) {root->insert(object);}// 检测与指定 AABB 的碰撞std::vector<AABB> query(const AABB& object) const {std::vector<AABB> result;root->query(object, result);return result;}
};// 示例使用
int main() {// 定义八叉树的边界AABB octreeBounds(Vec3(0, 0, 0), Vec3(100, 100, 100));Octree octree(octreeBounds);// 插入一些 AABBoctree.insert(AABB(Vec3(10, 10, 10), Vec3(20, 20, 20)));octree.insert(AABB(Vec3(30, 30, 30), Vec3(40, 40, 40)));// 定义一个查询的 AABBAABB queryAABB(Vec3(15, 15, 15), Vec3(25, 25, 25));// 进行碰撞检测std::vector<AABB> collisions = octree.query(queryAABB);// 输出碰撞结果std::cout << "Collisions found: " << collisions.size() << std::endl;for (const auto& collision : collisions) {std::cout << "Collision: min(" << collision.min.x << ", " << collision.min.y << ", " << collision.min.z << "), max("<< collision.max.x << ", " << collision.max.y << ", " << collision.max.z << ")" << std::endl;}return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring框架中都用到了哪些设计模式?

大家好&#xff0c;我是锋哥。今天分享关于【Spring框架中都用到了哪些设计模式&#xff1f;】面试题。希望对大家有帮助&#xff1b; Spring框架中都用到了哪些设计模式&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring框架中使用了大量的设计模…

Day1 25/2/14 FRI

【一周刷爆LeetCode&#xff0c;算法大神左神&#xff08;左程云&#xff09;耗时100天打造算法与数据结构基础到高级全家桶教程&#xff0c;直击BTAJ等一线大厂必问算法面试题真题详解&#xff08;马士兵&#xff09;】https://www.bilibili.com/video/BV13g41157hK?p3&v…

软考高级《系统架构设计师》知识点(一)

计算机硬件 校验码 码距&#xff1a;就单个编码A:00而言&#xff0c;其码距为1&#xff0c;因为其只需要改变一位就变成另一个编码。在两个编码中&#xff0c;从A码到B码转换所需要改变的位数称为码距&#xff0c;如A:00要转换为B:11&#xff0c;码距为2。一般来说&#xff0c;…

DeepSeek免费部署到WPS或Office

部署到WPS - 通过OfficeAI插件接入&#xff1a; - 准备工作&#xff1a;安装最新版本的WPS Office软件&#xff1b;访问DeepSeek官网&#xff0c;点击右上角的“API开放平台”&#xff0c;登录账号&#xff08;若无账号需先注册&#xff09;&#xff0c;登录成功后&#xff0c;…

基于vue3实现的课堂点名程序

设计思路 采用vue3实现的课堂点名程序&#xff0c;模拟课堂座位布局&#xff0c;点击开始点名按钮后&#xff0c;一朵鲜花在座位间传递&#xff0c;直到点击结束点名按钮&#xff0c;鲜花停留的座位被点名。 课堂点名 座位组件 seat.vue <script setup>//组合式APIimpo…

C语言的物联网

C语言在物联网中的应用 物联网&#xff08;Internet of Things&#xff0c;IoT&#xff09;是一个通过网络将各种物理设备连接起来的系统&#xff0c;使其能够收集和交换数据。随着技术的进步&#xff0c;物联网已经走入了我们的日常生活&#xff0c;并在智能家居、智能城市、…

数论补充 之 前后缀分解问题

文章目录 [0,i-1] 和 [i1,n-1] 共同作用3334,数组的最大因子得分238.除自身以外数组的乘积 对于前缀分解问题&#xff0c;我愿把它分为几个大问题&#xff1a;[0,i] 或 [i,n-1] 或 [l,r],或 [0,i-1] 和 [i1,n-1] 共同作用的问题 一般都是求解区间的和&#xff0c;乘积&#xff…

Winform禁止高分辨下缩放布局成功方法

Windows自动缩放布局会导致窗体上的按钮和文本挤在一起根本看不清楚。 那么该如何解决呢&#xff1f; 具体操作步骤如下&#xff1a; 1、在项目属性上切换到【安全性】菜单&#xff0c;勾选【启用ClickOnce安全设置】&#xff0c;然后立刻取消勾选&#xff1b; 为了生成app.…

matlab齿轮传动

实现齿轮啮合分析&#xff0c;齿轮传动非线性分析&#xff0c;对扭转振动方程组进行求解&#xff0c;可得到齿轮扭转角随时间变化相关参数 列表 齿轮传动非线性分析&#xff0c;对扭转振动方程组进行求解&#xff0c;可得到齿轮扭转角随时间变化相关参数/niu_gou_yuan_Rg.m , …

分享 UniApp 中超好看的卡片阴影样式

在 UniApp 开发中&#xff0c;页面的视觉效果对于提升用户体验至关重要。一个设计精美的卡片样式往往能让页面更加美观和吸引人&#xff0c;而阴影效果则是为卡片增添立体感和层次感的关键元素。今天&#xff0c;我就来和大家分享一个在 UniApp 中实现的卡片阴影样式&#xff0…

教程 | 从零部署到业务融合:DeepSeek R1 私有化部署实战指南

文章目录 1. 什么是 DeepSeek R1&#xff1f;a. 主要介绍a. 版本区别 2. 部署资源要求a. 硬件资源要求 3. 本地安装DeepSeek-R1a. 为什么选择本地部署&#xff1f;b. 部署工具对比c. 演示环境配置d. Ollama安装流程 4. 可视化工具a. 工具对比b. Open-WebUI部署 5. AI API应用a.…

Ubuntu22.04 使用useradd 创建用户时,没有创建家目录时,如何手动创建家目录

测试案例&#xff1a; 使用useradd不加参数创建test目录 如下可以看出使用 useradd 创建用户的时候默认不会创建家目录 rootlocal:~# useradd test rootlocal:~# id test uid1001(test) gid1001(test) groups1001(test) rootlocal:~# cat /etc/passwd | grep test test:x:1001:…

数据结构——队列、哈希存储(2025.2.11)

目录 一、队列 1.定义 2.应用 3.分类 &#xff08;1&#xff09;逻辑结构 &#xff08;2&#xff09;物理结构 顺序队列 链式队列 二、哈希存储 1.定义 2.哈希冲突 &#xff08;1&#xff09;开放定址法 &#xff08;2&#xff09;再哈希法 &#xff08;3&#xf…

【做一个微信小程序】校园地图页面实现

前言 上一个教程我们实现了小程序的一些的功能&#xff0c;有背景渐变色&#xff0c;发布功能有的呢&#xff0c;已支持图片上传功能&#xff0c;表情和投票功能开发中&#xff08;请期待&#xff09;。下面是一个更高级的微信小程序实现&#xff0c;包含以下功能&#xff1a;…

css: 针对属性left/right/top/bottom为啥设置transition动画不起作用

如题&#xff1a; 在css的position中 left/right/top/bottom 这类位置属性值如果考虑使用transition来添加动画&#xff0c;transition它会优先考虑left/top属性&#xff0c;而此时transition触发需要的是数值型属性&#xff0c;如果设置为auto则系统会默认不考虑将位置属性添加…

npm安装时无法访问github域名的解决方法

个人博客地址&#xff1a;npm安装时无法访问github域名的解决方法 | 一张假钞的真实世界 今天在用npm install的时候出现了github项目访问不了的异常&#xff1a; npm ERR! Error while executing: npm ERR! /bin/git ls-remote -h -t https://github.com/nhn/raphael.git np…

J Exp Clin Cancer Res (IF:11.4)|上海九院张建军团队发现SPP1+巨噬细胞在头颈癌中的促肿瘤机制

巨噬细胞是肿瘤免疫微环境&#xff08;TIME&#xff09;的重要组成部分&#xff0c;在不同癌症类型中表现出功能的多样性以及与预后的紧密联系。在多种癌症中&#xff0c;SPP1巨噬细胞已被发现是一种常见的肿瘤相关巨噬细胞&#xff08;TAM&#xff09;亚群&#xff0c;且与不良…

盛铂科技 SCP4006/4018/4040:国产袖珍式功率计 射频微波功率探头 平均功率计

在通信、电子测量等领域&#xff0c;功率计是确保信号稳定、系统高效运行的关键设备。盛铂科技自主研发的 SCP4000 系列自带 USB 接口的袖珍式 CW 信号平均功率计&#xff0c;以其卓越的性能、高性价比和便捷的操作&#xff0c;在众多同类产品中脱颖而出&#xff0c;成为行业内…

【ISO 14229-1:2023 UDS诊断(会话控制0x10服务)测试用例CAPL代码全解析①】

ISO 14229-1:2023 UDS诊断【会话控制0x10服务】_TestCase01 作者&#xff1a;车端域控测试工程师 更新日期&#xff1a;2025年02月14日 关键词&#xff1a;UDS诊断、0x10服务、诊断会话控制、ECU测试、ISO 14229-1:2023 TC10-001测试用例 用例ID测试场景验证要点参考条款预期…

Docker+Jenkins自动化部署SpringBoot项目【详解git,jdk,maven,ssh配置等各种配置,附有示例+代码】

文章目录 DockerJenkins部署SpringBoot项目一.准备工作1.1安装jdk111.2安装Maven 二.Docker安装Jenkins2.1安装Docker2.2 安装Jenkins2.3进入jenkins 三.Jenkins设置3.1安装jenkins插件3.2全局工具配置全局配置jdk全局配置maven全局配置git 3.3 系统配置安装 Publish Over SSH …