3D空间中的AABB(轴向平行包围盒, Aixe align bounding box)的求法

引言

前面的一篇文章中讲述了如何通过模型的顶点来求的模型的包围球,并且还讲述了基本包围体除了包围球之外,还有AABB包围盒。在这一章,将讲述如何根据模型的坐标求得它的AABB盒。

表示方法

AABB盒的表示方法有很多,总结起来有如下的三种情况:

Max-min表示法:使用一个右上角和左下角的点来唯一的定义一个包围体

Center-radious表示法:我们用center点来表示中点,radious是一个数组,保存了包围盒在x方向,y方向,z方向上的半径。

Min-Width表示方法:我们用min来定义左下角的点,使用width来保存在x,y,z方向上的长度。

不同的方法,他们的碰撞检测算法也会有所不同,并且不同的表示方法也会适用在不同的情形下。所以,大家自己设计的时候,需要慎重考虑。

在本文中,将会使用的是Max-min表示方法,如下所示:

class AABB
{
   ....
public:
    VECTOR3 max ;
    VECTOR3 min ;
};

在这种表示方法之下,进行碰撞检测的代码如下所示:

bool AABB::isCollided(AABB* a)
{
	if(max.x < a->min.x || min.x > a->max.x) return false ;
	if(max.y < a->min.y || min.y > a->max.y) return false ;
	if(max.z < a->min.z || min.z > a->min.z) return false ;

	return true ;
}// end for isCollided

AABB盒构造

构造AABB盒的方法有很多种,有的很简单,有的很复杂,这里将介绍两种基本的构造方法,他们也非常的简单,容易掌握。

第一种是固定大小的AABB盒,这种AABB盒在构造完毕之后,不管被包围的物体怎么样的旋转,都不需要在进行重新构造了。

第二种是比较紧凑的一种,利用X,Y和Z轴向上最长和最远的点来构造一个AABB盒。

固定大小AABB盒

正如上面说的那样,固定大小的AABB盒,它需要被包围的物体,不管怎么旋转,都还在这个包围体里面。所以,我们先为这个物体构造一个包围球体,然后在这个包围球体的基础上构建一个AABB盒。这样就能够达到不管怎么旋转,都还在包围体里面。

不过,为这个物体构建一个包围球同样也能够满足这样的要求,所以,就有点鸡肋了。但是,在某些限制条件下,你无法使用包围球,那么就可以使用这样的方法来构建一个固定大小的AABB盒。

这个算法的核心是如何构建一个包围球体,而这个算法我在前面一章中已经讲述了,就不再重复,感兴趣的读者可以去看博客中3D空间包围球(Bounding Sphere)的求法的文章。

在有了包围球之后,我们通过如下的方法就能够计算出固定大小的AABB盒了:

void AABB::computeFixedAABB(Sphere *s)
{
	max.x = s->center.x + s->radious ;
	max.y = s->center.y + s->radious ;
	max.z = s->center.z + s->radious ;
	min.x = s->center.x - s->radious ;
	min.y = s->center.y - s->radious ;
	min.z = s->center.z - s->radious ;
}// end for computeFixedAABB

紧凑点的AABB盒

这个AABB盒的构造方法,是从顶点集中获取X,Y和Z方向上最远的和最近的点,然后利用他们来构建一个AABB盒。这种方法也很简单。我直接上代码来给大家讲解:

void AABB::computeAABBFromOriginalPointSet(VECTOR3* vertices, unsigned int vertex_num)
{
	unsigned int minX_i = 0 , maxX_i = 0 ;
	extrameDistanceAlongDir(MAKE_VECTOR3(1,0,0), vertices, vertex_num, &minX_i, &maxX_i);
	min.x = vertices[minX_i].x ;
	max.x = vertices[maxX_i].x ;

	unsigned int minY_i = 0 , maxY_i = 0;
	extrameDistanceAlongDir(MAKE_VECTOR3(0,1,0),vertices, vertex_num, &minY_i, &maxY_i);
	min.y = vertices[minY_i].y ;
	max.y = vertices[maxY_i].y ;

	unsigned int minZ_i = 0 , maxZ_i = 0;
	extrameDistanceAlongDir(MAKE_VECTOR3(0,0,1),vertices, vertex_num, &minZ_i, &maxZ_i);
	min.z = vertices[minZ_i].z ;
	max.z = vertices[maxZ_i].z ;
}// end for computeAABBFromOriginalPointSet

void AABB::extrameDistanceAlongDir(VECTOR3 dir, VECTOR3* vertices, unsigned int vertex_num, unsigned int* min, unsigned int*max)
{
	float maxProj = FLT_MIN , minProj = FLT_MAX ;
	for(unsigned int i = 0 ; i < vertex_num ; i ++)
	{
		float proj = 0 ;
		Vec3Dot(proj, vertices[i], dir);

		if(proj > maxProj)
		{
			maxProj = proj ;
			*max = i ;
		}

		if(proj < minProj)
		{
			minProj = proj ;
			*min = i ;
		}
	}// end for
}// end for extrameDistanceAlongDir

上面一共有两个函数,第一个函数就是给用户调用的计算AABB盒的方法。用户只需要将模型的顶点集传递进来即可。

第二个函数,是获取在指定的轴向上,哪个点在这个轴向上的投影是最长的和最短的。这个函数很简单,只需要调用一个点积Dot运算就能够求出。

当求出了在X,Y和Z轴向上投影最长和最短的6个点之后,我们就分别取他们对应的轴向上的坐标值来构成Max和min,这样一个AABB盒就构造完毕了。是不是很简单??

AABB类

下面是AABB的完整类:

//--------------------------------------------------------------------------------------------------
// declaration	: Copyright (c), by XJ , 2014 . All right reserved .
// brief		: This file will define the Axie aligned bounding box.
// author		: XJ
// date			: 2014 / 6 / 22
// file			: AABB.h
// version		: 1.0
//---------------------------------------------------------------------------------------------------
#pragma once
#include"XJMath.h"
#include"Sphere.h"

namespace XJCollision
{
	/**
	* brief	: We use the Max-min representation
	*/
	class AABB
	{
	public:
		AABB();
		AABB(VECTOR3 min, VECTOR3 max);

	public:
		/**
		* Compute the fixed AABB
		*/
		void computeFixedAABB(Sphere* s);

		/**
		* Compute the AABB from the original point set
		*/
		void computeAABBFromOriginalPointSet(VECTOR3 *vertices, unsigned int vertex_num);

		/**
		* Collision Detection between two AABB
		*/
		bool isCollided(AABB* a);

	private:
		/**
		* Compute the least and most distance along the specific direction
		*/
		void extrameDistanceAlongDir(VECTOR3 dir, VECTOR3 * vertices, unsigned int vertex_num, unsigned int * min, unsigned int * max);

	public:
		VECTOR3 max ;
		VECTOR3 min ;
	};
};
#include"AABB.h"
#include<cmath>
#include<float.h>
using namespace XJCollision ;

AABB::AABB()
	:max(),
	min()
{

}

AABB::AABB(VECTOR3 _max, VECTOR3 _min)
{
	max.x = _max.x ; max.y = _max.y ; max.z = _max.z ;
	min.x = _min.x ; min.y = _min.y ; min.z = _min.z ;
}

void AABB::computeFixedAABB(Sphere *s)
{
	max.x = s->center.x + s->radious ;
	max.y = s->center.y + s->radious ;
	max.z = s->center.z + s->radious ;
	min.x = s->center.x - s->radious ;
	min.y = s->center.y - s->radious ;
	min.z = s->center.z - s->radious ;
}// end for computeFixedAABB

void AABB::computeAABBFromOriginalPointSet(VECTOR3* vertices, unsigned int vertex_num)
{
	unsigned int minX_i = 0 , maxX_i = 0 ;
	extrameDistanceAlongDir(MAKE_VECTOR3(1,0,0), vertices, vertex_num, &minX_i, &maxX_i);
	min.x = vertices[minX_i].x ;
	max.x = vertices[maxX_i].x ;

	unsigned int minY_i = 0 , maxY_i = 0;
	extrameDistanceAlongDir(MAKE_VECTOR3(0,1,0),vertices, vertex_num, &minY_i, &maxY_i);
	min.y = vertices[minY_i].y ;
	max.y = vertices[maxY_i].y ;

	unsigned int minZ_i = 0 , maxZ_i = 0;
	extrameDistanceAlongDir(MAKE_VECTOR3(0,0,1),vertices, vertex_num, &minZ_i, &maxZ_i);
	min.z = vertices[minZ_i].z ;
	max.z = vertices[maxZ_i].z ;
}// end for computeAABBFromOriginalPointSet

void AABB::extrameDistanceAlongDir(VECTOR3 dir, VECTOR3* vertices, unsigned int vertex_num, unsigned int* min, unsigned int*max)
{
	float maxProj = FLT_MIN , minProj = FLT_MAX ;
	for(unsigned int i = 0 ; i < vertex_num ; i ++)
	{
		float proj = 0 ;
		Vec3Dot(proj, vertices[i], dir);

		if(proj > maxProj)
		{
			maxProj = proj ;
			*max = i ;
		}

		if(proj < minProj)
		{
			minProj = proj ;
			*min = i ;
		}
	}// end for
}// end for extrameDistanceAlongDir

bool AABB::isCollided(AABB* a)
{
	if(max.x < a->min.x || min.x > a->max.x) return false ;
	if(max.y < a->min.y || min.y > a->max.y) return false ;
	if(max.z < a->min.z || min.z > a->min.z) return false ;

	return true ;
}// end for isCollided

程序实例

下面的两种图,分别是使用了第一种和第二种计算方法计算出来的包围盒:

3D空间中的AABB(轴向平行包围盒, Aixe align bounding box)的求法

时间: 2024-09-28 20:28:06

3D空间中的AABB(轴向平行包围盒, Aixe align bounding box)的求法的相关文章

3D空间中射线与轴向包围盒AABB的交叉检测算法

引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法.但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是无法高效的完成.所以,我们需要通过其他的手段来提早剔除一些不可能发生交叉的物体,这种早退的思想,大量的运用在3D游戏技术中.在本篇文章中,我将像大家讲述如何实现射线与轴向包围盒AABB的交叉检测.如果读者不明白什么是轴向包围盒,请看这篇文章. Ray-AABB交叉检测算法 现如今,有很多的Ray-A

3D空间中射线与轴向包围盒AABB的交叉检测算法【转】

引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法.但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是无法高效的完成.所以,我们需要通过其他的手段来提早剔除一些不可能发生交叉的物体,这种早退的思想,大量的运用在3D游戏技术中.在本篇文章中,我将像大家讲述如何实现射线与轴向包围盒AABB的交叉检测.如果读者不明白什么是轴向包围盒,请看这篇文章. Ray-AABB交叉检测算法 现如今,有很多的Ray-A

3D空间中射线与轴向包围盒AABB的交叉检测算法 【转】

http://blog.csdn.net/i_dovelemon/article/details/38342739 引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法. 但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是无法高 效的完成.所以,我们需要通过其他的手段来提早剔除一些不可能发生交叉的物体,这种早退的思想,大量的运用在3D游戏技术中.在本篇文章中,我将像大家讲 述如何实现射线与轴向包围盒A

Delphi接口的底层实现(接口在内存中仍然有其布局,它依附在对象的内存空间中,有汇编解释)——接口的内存结构图,简单清楚,深刻 good

引言 接口是面向对象程序语言中一个很重要的元素,它被描述为一组服务的集合,对于客户端来说,我们关心的只是提供的服务,而不必关心服务是如何实现的:对于服务端的类来说,如果它想实现某种服务,实现与该服务相关的接口即可,它也不必与使用服务的客户端进行过多的交互.这种良好的设计方式已经受到很广泛的应用. 早在Delphi 3的时候就引入了接口的概念,当时完全是因为COM的出现而诞生的,但经过这么多版本的进化,Delphi的接口已经成为Object Pascal语言的一部分,我们完全可以用接口来完成我们的

基于Cocos2d-x的2D空间中的OBB(Orient Bounding Box)碰撞检测算法

基于Cocos2d-x的2D空间中的OBB(Orient Bounding Box)碰撞检测算法 尊重原创:http://cn.cocos2d-x.org/tutorial/show?id=1577

3D空间包围球(Bounding Sphere)的求法

引言 在3D碰撞检測中,为了加快碰撞检測的效率,降低不必要的碰撞检測,会使用基本几何体作为物体的包围体(Bounding Volume, BV)进行測试.基本包围体的碰撞检測相对来说廉价也easy的多,所以假设在基本包围体的碰撞检測中都没有通过的话,那么就没有必要进行更加复杂的碰撞检測了. 而对于不同性质,不同形状的模型,须要依据情况选择不同的包围体,一般来说,包围体分为例如以下的几种: Sphere, AABB, OBB, 8-DOP, Convex Hull这几种常见的. 接下来将向大家讲述

【CVPR2018】PointFusion: Deep Sensor Fusion for 3D Bounding Box Estimation

又一篇3D点云detection的顶会.这篇文章是two stage的方法,非end-to-end.文章的前提是利用faster rcnn得到2D图像的image crop:然后才是本文介绍的PointFusion,即将image crop和对应的3D点云数据作为输入,得到3D box.可以说这篇文章实际2D检测基础上做3D检测. 整个模型如图: 输入:2D 图像块(fatser RCNN检测结果):对应的3D点云 模型: 特征提取: 2D图像用预训练的ResNet50提取2048d的特征 用多

cad二次开发--添加对象到模型空间中

通过实体名来将实体加入到模型空间 AcDbObjectId PostToModelSpace(AcDbEntity *pEnt){ //打开块表 AcDbBlockTable *pBlockTable = NULL; Acad::ErrorStatus es = acdbHostApplicationServices()->workingDatabase() ->getBlockTable(pBlockTable, AcDb::kForRead); //打开块表记录 AcDbBlockTabl

火云开发课堂 - 《使用Cocos2d-x 开发3D游戏》系列 第十四节:包围盒碰撞

<使用Cocos2d-x 开发3D游戏>系列在线课程 第十三节:包围盒碰撞 视频地址:http://edu.csdn.net/course/detail/1330/20814?auto_start=1 交流论坛:http://www.firestonegames.com/bbs/forum.php 工程下载地址:请成为正式学员获取工程 课程截图: 项目实例: 版权声明:本文为博主原创文章,未经博主允许不得转载.