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

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;
}

相关文章:

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

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

spring boot对接clerk 实现用户信息获取

在现代Web应用中&#xff0c;用户身份验证和管理是一个关键的功能。Clerk是一个提供身份验证和用户管理的服务&#xff0c;可以帮助开发者快速集成这些功能。在本文中&#xff0c;我们将介绍如何使用Spring Boot对接Clerk&#xff0c;以实现用户信息的获取。 1.介绍 Clerk提供…...

一种动态地址的查询

背景 当我们注入一个进程&#xff0c;通过函数地址进行call时经常会遇到这样的一个问题。对方程序每周四会自动更新。更新后之前的函数地址就变化了&#xff0c;然后需要重新找地址。所以&#xff0c;我就使用了一个动态查询的方式。 第一步&#xff1a;先为需要call的函数生…...

周雨彤:用角色与生活,诠释审美的艺术

提到内娱审美优秀且持续在线的女演员&#xff0c;周雨彤绝对是其中最有代表性的一个。 独树一帜的表演美学 作为新生代演员中的实力派代表&#xff0c;周雨彤凭借细腻的表演和对角色的深度共情&#xff0c;在荧幕上留下了多个令人难忘的“出圈”形象。在《我在他乡挺好的》中…...

使用jks给空apk包签名

1、在平台官方下载空的apk包&#xff08;上传应用时有提醒下载&#xff09; 2、找到jdk目录&#xff0c;比如C:\Program Files\Java\jdk1.8\bin&#xff0c;并把下载的空包apk和jks文件放到bin下 3、以管理员身份运行cmd&#xff0c;如果不是管理员会签名失败 4、用cd定位到…...

500. 键盘行 771. 宝石与石头 简单 find接口的使用

500. 键盘行1 给你一个字符串数组 words &#xff0c;只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。 请注意&#xff0c;字符串 不区分大小写&#xff0c;相同字母的大小写形式都被视为在同一行。 美式键盘 中&#xff1a; 第一行由字符 "qwer…...

仙剑世界手游新手攻略 仙剑世界能用云手机玩吗

欢迎来到《仙剑世界》手游的仙侠世界&#xff01;作为新手玩家&#xff0c;以下是一些详细的攻略和建议&#xff0c;帮助你快速上手并享受游戏的乐趣。 一、新手职业推荐 1.轩辕&#xff1a;这是一个偏辅助的职业&#xff0c;可以给队友提供输出加成等增益效果&#xff0c;不过…...

[题解]2024CCPC重庆站-小 C 的神秘图形

Sources&#xff1a;K - 小 C 的神秘图形Abstract&#xff1a;给定正整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le 10^5) n(1≤n≤105)&#xff0c;三进制字符串 n 1 , n 2 ( ∣ n 1 ∣ ∣ n 2 ∣ n ) n_1,n_2(|n_1||n_2|n) n1​,n2​(∣n1​∣∣n2​∣n)&#xff0c;按如下方法…...

NPS内网穿透SSH使用手册

1、说明 nps-一款轻量级、高性能、功能强大的内网穿透代理服务器 github地址&#xff1a;https://github.com/ehang-io/nps 官网文档地址&#xff1a;https://ehang-io.github.io/nps/#/?idnps 2、服务端 下载地址&#xff1a;https://github.com/ehang-io/nps/releases 下…...

大幂计算和大阶乘计算【C语言】

大幂计算&#xff1a; #include<stdio.h> long long int c[1000000]{0}; int main() {long long a,b,x1;c[0]1;printf("请输入底数&#xff1a;");scanf("%lld",&a);printf("请输入指数&#xff1a;");scanf("%lld",&b…...

【Linux】详谈 进程控制

目录 一、进程是什么 二、task_struct 三、查看进程 四、创建进程 4.1 fork函数的认识 4.2 2. fork函数的返回值 五、进程终止 5.1. 进程退出的场景 5.2. 进程常见的退出方法 5.2.1 从main返回 5.2.1.1 错误码 5.2.2 exit函数 5.2.3 _exit函数 5.2.4 缓冲区问题补…...

Linux top 命令

作用 top 是一个实时系统监控工具&#xff0c;用于查看系统的资源使用情况和进程状态。 示例 以下是一些常用的 top 命令示例&#xff1a; top &#xff1a;动态显示结果&#xff0c;每 3 秒刷新一次。 top -d 2&#xff1a;动态显示结果&#xff0c;每 2 秒刷新一次。 top …...

Leetcode 424-替换后的最长重复字符

给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符&#xff0c;并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。 在执行上述操作后&#xff0c;返回 包含相同字母的最长子字符串的长度。 题解 可以先做LCR 167/Leetcode 03再做本题 滑动窗口&…...

《StyleDiffusion:通过扩散模型实现可控的解耦风格迁移》学习笔记

paper&#xff1a;2308.07863 目录 摘要 1、介绍 2、相关工作 2.1 神经风格迁移&#xff08;NST&#xff09; 2.2 解耦表示学习&#xff08;DRL&#xff09; 2.3 扩散模型&#xff08;Diffusion Models&#xff09; 3、方法 3.1 风格移除模块 3.2 风格转移模块 3.3 …...

Django 创建表时 “__str__ ”方法的使用

在 Django 模型中&#xff0c;__str__ 方法是一个 Python 特殊方法&#xff08;也称为“魔术方法”&#xff09;&#xff0c;用于定义对象的字符串表示形式。它的作用是控制当对象被转换为字符串时&#xff0c;应该返回什么样的内容。 示例&#xff1a; 我在初学ModelForm时尝…...

图像处理之CSC

CSC 是 Color Space Conversion&#xff08;色彩空间转换&#xff09;的缩写&#xff0c;它涉及图像处理中的亮度、饱和度、对比度和色度等参数的调整。这些参数是图像处理中的核心概念&#xff0c;通常用于描述和操作图像的颜色信息。 以下是亮度、饱和度、对比度和色度与 CS…...

C语言数组之二维数组

C语言 主要内容 数组 二维数组 数组 二维数组 定义 二维数组本质上是一个行列式的组合&#xff0c;也就是说二维数组由行和列两部分组成&#xff0c;属于多维数组。二维数组数据是通过行列进行解读。二维数组可被视为一个特殊的一维数组&#xff0c;相当于二维数组又是一…...

PyTorch 源码学习:阅读经验 代码结构

分享自己在学习 PyTorch 源码时阅读过的资料。本文重点关注阅读 PyTorch 源码的经验和 PyTorch 的代码结构。因为 PyTorch 不同版本的源码实现有所不同&#xff0c;所以笔者在整理资料时尽可能按版本号升序&#xff0c;版本号见标题前[]。最新版本的源码实现还请查看 PyTorch 仓…...

vite+vue3开发低版本浏览器不支持es6语法的问题排坑笔记

重要提示&#xff1a;请首先完整阅读完文章内容后再操作&#xff0c;以免不必要的时间浪费&#xff01;切记&#xff01;&#xff01;&#xff01;在使用vitevue3开发unapp项目时&#xff0c;发现低版本浏览器不兼容es6的语法&#xff0c;如“?.” “??” 等&#xff0c;为了…...

C语言中printf()函数,格式输出符

在 C 语言中&#xff0c;printf() 函数的格式输出符&#xff08;格式说明符&#xff09;用于控制输出的格式和数据类型。以下是常见的格式说明符及其用法&#xff1a; 基本格式符 打印各种类型的值 格式输出符数据类型说明%dint输出有符号十进制整数%uunsigned int输出无符号…...

多智能体视觉幻觉传播的雪球效应与缓解策略

1. 项目背景与核心问题在计算机视觉与多智能体系统交叉领域&#xff0c;视觉幻觉的传播放大现象正成为影响系统可靠性的关键瓶颈。当多个智能体通过视觉感知共享环境信息时&#xff0c;初始微小的感知偏差会像滚雪球一样在群体中不断放大&#xff0c;最终导致灾难性的集体误判—…...

图像细化不止Zhang-Suen:聊聊骨架提取在OCR和手势识别里的实际应用与选型

图像细化不止Zhang-Suen&#xff1a;骨架提取在OCR和手势识别中的实战选型指南 当你在处理一份模糊的历史文档扫描件时&#xff0c;字符笔画粘连得像被雨水晕染开的墨迹&#xff1b;或者开发手势识别系统时&#xff0c;用户手掌轮廓在低光环境下变得异常粗大——这时&#xff0…...

从物联网小设备到工业网关:RT-Thread、FreeRTOS、uC/OS-II选型实战指南(附对比表格)

从物联网小设备到工业网关&#xff1a;RT-Thread、FreeRTOS、uC/OS-II选型实战指南 在智能农业监测系统的开发过程中&#xff0c;我们遇到了一个典型困境&#xff1a;如何为不同层级的设备选择合适的实时操作系统&#xff1f;从田间部署的微型土壤传感器到负责数据汇总的4G边缘…...

CXPatcher:在Mac上解锁CrossOver终极性能的完整指南

CXPatcher&#xff1a;在Mac上解锁CrossOver终极性能的完整指南 【免费下载链接】CXPatcher A patcher to upgrade Crossover dependencies and improve compatibility 项目地址: https://gitcode.com/gh_mirrors/cx/CXPatcher 你是否厌倦了在Mac上运行Windows游戏时遇到…...

Rust的诱惑:安全性、性能与学习曲线的残酷平衡

一、测试视角下的Rust热潮在软件测试领域&#xff0c;我们见证过无数编程语言的兴衰。从Java的企业级统治力&#xff0c;到Python在自动化测试中的崛起&#xff0c;每一种语言都带着独特的优势与痛点。而近年来&#xff0c;Rust以“内存安全无GC”“零成本抽象”等标签强势闯入…...

别再只读原始数据了!用STM32的MPU6050实现简易姿态解算(附卡尔曼滤波浅析)

从MPU6050原始数据到三维姿态解算&#xff1a;STM32实战指南 当你成功驱动MPU6050传感器并获取到加速度和角速度的原始数据时&#xff0c;这只是姿态感知的第一步。真正的挑战在于如何将这些看似杂乱的数据转化为稳定可靠的三维姿态信息——这正是平衡车、无人机等设备实现自主…...

考研数学救命稻草:一阶和二阶微分方程的通解公式,我帮你整理好了(附880/660真题解法)

考研数学微分方程通关手册&#xff1a;从公式推导到880/660真题实战拆解 微分方程作为考研数学&#xff08;数一/数二/数三&#xff09;的必考核心章节&#xff0c;每年在真题中至少占据10-15分权重。但面对纷繁复杂的方程类型和变化多端的题目条件&#xff0c;许多考生常陷入&…...

初次使用模型广场如何根据场景与预算选择合适模型

初次使用模型广场如何根据场景与预算选择合适模型 1. 理解模型筛选的核心维度 在 Taotoken 模型广场中&#xff0c;用户可以通过多个关键维度筛选适合自身需求的模型。首要任务是明确实际应用场景的具体要求。对于文本生成任务&#xff0c;需要关注模型的上下文窗口长度。例如…...

别再死记硬背!用Arduino+74HC595驱动数码管,手把手教你玩转串入并出

用Arduino74HC595驱动数码管&#xff1a;从零开始的串入并出实战指南 数码管作为电子项目中常见的显示器件&#xff0c;其驱动方式一直是初学者面临的第一个挑战。传统直接驱动方法需要占用大量IO口&#xff0c;而使用74HC595这类移位寄存器芯片&#xff0c;只需3个引脚就能控制…...

开源MCP服务器实现AI对话成本优化:文本压缩技术解析与实战

1. 项目概述&#xff1a;一个为开发者设计的AI对话成本“节流器”如果你和我一样&#xff0c;日常重度依赖Claude、Cursor这类AI工具来辅助编程、文档撰写或头脑风暴&#xff0c;那么每个月看到账单上那笔不菲的API调用费用时&#xff0c;心里总会咯噔一下。尤其是在处理长文档…...