快速相交检测:平面与包围盒

2024-06-16 22:08

本文主要是介绍快速相交检测:平面与包围盒,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

快速相交检测:平面与包围盒

  • 1.前言
  • 2.数学背景
  • 3.计算原理
  • 4.代码

1.前言

   在游戏等实时性要求高的三维程序中,相交检测是一项及其基础又重要的技术,大佬们相继提出各种检测技术。
  当然大多数人的实现方式可能 (确信)是将包围盒的8个点分别带入平面检测,这将要做8组点积。
  今天我来介绍其中一项比较快速的检测方法,在略去相交和内部的判断后可以直接降到四次点积,当然如果使用的是AABB则会变成一次点积,目前我是按照OBB的方式来算的。

2.数学背景

平面方程形式: A x + B y + C z + D = 0 Ax+By+Cz+D =0 Ax+By+Cz+D=0
对于坐标 P ( x 0 , y 0 , z 0 ) P(x_0,y_0,z_0) P(x0,y0,z0)
检验其是否在平面内,可以直接带入平面方程
A x 0 + B y 0 + C z 0 + D Ax_0+By_0+Cz_0+D Ax0+By0+Cz0+D

  • 若结果>0,则在平面外部。
  • 若结果=0,则在正好在平面上。
  • 若结果<0,则在平面内部。

什么?你问我平面还分内外?
这个我也无法解释,毕竟我只是一只鸽子
目前我个人来说,习惯性将平面法向量指向的那一侧称呼为外部,法向量负方向一侧称为内部

3.计算原理

   最重要的步骤是找到包围盒的n顶点和p顶点。
在这里插入图片描述

  • 如果n顶点位于平面外部,则直接返回包围盒在平面外。
  • 如果n顶点位于平面内部,p顶点位于平面外部,返回包围盒与平面相交。
  • 如果n顶点位于平面内部,p顶点位于平面内部,返回包围盒在平面内。

那么n、p顶点如何寻找呢,通过将平面法向量与包围盒的轴方向进行点积,判断点积结果的正负来寻找。

4.代码

ok,按照惯例先放出结果图

  • 0代表在外部
  • 1代表相交
  • -1代表在内部

测试用例包围盒为在点(0,0,0),长为(1,1,1),第一个轴方向为(1,0,0),第二个轴方向为(0,1,0),第二个轴方向为(0,0,1),对就是xyz轴方向
第一个是在点(2,2,2),法向量为(-1,-1,-1)的平面测试
第二个是在点(0.5,0.5,0.5),法向量为(-1,-1,-1)的平面测试
第三个是在点(-2,-2,-2),法向量为(-1,-1,-1)的平面测试
在这里插入图片描述

#include "pch.h"#include <iostream>using namespace std;class vec3
{
public:float x, y, z;
};
class box
{
public:box(vec3 dx,vec3 dy,vec3 dz,vec3 l,vec3 o):dX(dx),dY(dy),dZ(dz),len(l),origin(o){}vec3 dX, dY, dZ;vec3 len;vec3 origin;};float dot(vec3 a, vec3 b)
{return (a.x * b.x + a.y * b.y + a.z * b.z);
}class plane
{
public:plane(vec3 v,vec3 n){a = n.x;b = n.y;c = n.z;d = -(dot(v,n));}public:float check(vec3 x){return (x.x * a + x.y * b + x.z * c + d);}
public:union {struct{float a, b, c;};vec3 n;};float d;};vec3 operator+ (vec3 const& _Left, vec3 const& _Right) noexcept
{return (vec3{ _Left.x + _Right.x , _Left.y + _Right.y , _Left.z + _Right.z });
}vec3 operator* (float _Left, vec3 const& _Right) noexcept
{return (vec3{ _Left* _Right.x , _Left* _Right.y , _Left* _Right.z });
}int check(box _box,plane _plane)
{auto res1 = dot(_plane.n,_box.dX);auto res2 = dot(_plane.n, _box.dY);auto res3 = dot(_plane.n, _box.dZ);char mask_n = 0 | (res1 >= 0 ? 0 : 1) | (res2 >= 0 ? 0 : 2) | (res3 >= 0 ? 0 : 4);vec3 _n = _box.origin;if (mask_n & 1){_n = _n + (_box.len.x * _box.dX);}if (mask_n & 2){_n = _n + (_box.len.y * _box.dY);}if (mask_n & 4){_n = _n + (_box.len.z * _box.dZ);}if (_plane.check(_n) < 0.0){char mask_p = ~mask_n;vec3 _p = _box.origin;if (mask_p & 1){_p = _p + (_box.len.x * _box.dX);}if (mask_p & 2){_p = _p + (_box.len.y * _box.dY);}if (mask_p & 4){_p = _p + (_box.len.z * _box.dZ);}if (_plane.check(_p) < 0.0){// insidereturn (-1);}else{// intersectreturn (1);}}// outside;return 0;
}int main()
{plane p1({ 2,2,2 }, { -1,-1,-1 });plane p2({ 0.5,0.5,0.5 }, { -1,-1,-1 });plane p3({ -2,-2,-2 }, { -1,-1,-1 });box _box({1,0,0},{ 0,1,0},{ 0,0,1 },{1,1,1},{0,0,0});std::cout << check(_box, p1) << std::endl;std::cout << check(_box, p2) << std::endl;std::cout << check(_box, p3) << std::endl;return 0;
}

这篇关于快速相交检测:平面与包围盒的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067682

相关文章

Python多线程实现大文件快速下载的代码实现

《Python多线程实现大文件快速下载的代码实现》在互联网时代,文件下载是日常操作之一,尤其是大文件,然而,网络条件不稳定或带宽有限时,下载速度会变得很慢,本文将介绍如何使用Python实现多线程下载... 目录引言一、多线程下载原理二、python实现多线程下载代码说明:三、实战案例四、注意事项五、总结引

Python脚本轻松实现检测麦克风功能

《Python脚本轻松实现检测麦克风功能》在进行音频处理或开发需要使用麦克风的应用程序时,确保麦克风功能正常是非常重要的,本文将介绍一个简单的Python脚本,能够帮助我们检测本地麦克风的功能,需要的... 目录轻松检测麦克风功能脚本介绍一、python环境准备二、代码解析三、使用方法四、知识扩展轻松检测麦

C#使用Spire.XLS快速生成多表格Excel文件

《C#使用Spire.XLS快速生成多表格Excel文件》在日常开发中,我们经常需要将业务数据导出为结构清晰的Excel文件,本文将手把手教你使用Spire.XLS这个强大的.NET组件,只需几行C#... 目录一、Spire.XLS核心优势清单1.1 性能碾压:从3秒到0.5秒的质变1.2 批量操作的优雅

Mybatis-Plus 3.5.12 分页拦截器消失的问题及快速解决方法

《Mybatis-Plus3.5.12分页拦截器消失的问题及快速解决方法》作为Java开发者,我们都爱用Mybatis-Plus简化CRUD操作,尤其是它的分页功能,几行代码就能搞定复杂的分页查询... 目录一、问题场景:分页拦截器突然 “失踪”二、问题根源:依赖拆分惹的祸三、解决办法:添加扩展依赖四、分页

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

Linux如何快速检查服务器的硬件配置和性能指标

《Linux如何快速检查服务器的硬件配置和性能指标》在运维和开发工作中,我们经常需要快速检查Linux服务器的硬件配置和性能指标,本文将以CentOS为例,介绍如何通过命令行快速获取这些关键信息,... 目录引言一、查询CPU核心数编程(几C?)1. 使用 nproc(最简单)2. 使用 lscpu(详细信

C++ 检测文件大小和文件传输的方法示例详解

《C++检测文件大小和文件传输的方法示例详解》文章介绍了在C/C++中获取文件大小的三种方法,推荐使用stat()函数,并详细说明了如何设计一次性发送压缩包的结构体及传输流程,包含CRC校验和自动解... 目录检测文件的大小✅ 方法一:使用 stat() 函数(推荐)✅ 用法示例:✅ 方法二:使用 fsee

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热