引言

前面的一篇文章中讲述了怎样通过模型的顶点来求的模型的包围球,而且还讲述了基本包围体除了包围球之外,还有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盒的方法有非常多种,有的非常easy,有的非常复杂,这里将介绍两种主要的构造方法,他们也非常的简单,easy掌握。

第一种是固定大小的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盒。这样的方法也非常easy。我直接上代码来给大家解说:

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盒的方法。用户仅仅须要将模型的顶点集传递进来就可以。

第二个函数,是获取在指定的轴向上,哪个点在这个轴向上的投影是最长的和最短的。这个函数非常easy,仅仅须要调用一个点积Dot运算就行求出。

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

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)的求法的更多相关文章

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

    引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法.但是,我们应该知道,在游戏开发中,一个模型有很多的三角形构成,如果要对所有的物体,所有的三角形进行这种检测,就算现在的计算机运算能力,也是 ...

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

    http://blog.csdn.net/i_dovelemon/article/details/38342739 引言 在上一节中,我讲述了如何实现射线与三角形的交叉检测算法. 但是,我们应该知道, ...

  3. JAVA智能设备基于OpenGL的3D开发技术 之AABB碰撞检测算法论述

    摘要:无论是PC机的3D还是智能设备应用上,碰撞检测始终是程序开发的难点,甚至可以用碰撞检测作为衡量3D引擎是否完善的标准.现有许多3D碰撞检测算法,其中AABB碰撞检测是一种卓有成效而又经典的检测算 ...

  4. Oracle导入dmp备份文件到不同的表空间中

    原文链接:http://www.2cto.com/database/201211/171081.html 将DMP导入到不同的表空间中 1,用imp导出数据    cmd进入orcle安装目录bin下 ...

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

    引言 接口是面向对象程序语言中一个很重要的元素,它被描述为一组服务的集合,对于客户端来说,我们关心的只是提供的服务,而不必关心服务是如何实现的:对于服务端的类来说,如果它想实现某种服务,实现与该服务相 ...

  6. 三维空间中xoy平面上特定抛物线的正等测投影解析解的一种求法

    背景 背景:为锻炼代同学,老师给了她一个反向工程微信"跳一跳"小游戏的任务,希望做一个一样的出来.跳一跳中,有方块,有小人,小人站在方块上. 这个游戏的玩法是,用手指按住手机屏幕, ...

  7. 浅析Linux用户空间中的Mmap

    一.MMap基础概念 mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系.实现这样的映射关系后,进程就可以采 ...

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

    通过实体名来将实体加入到模型空间 AcDbObjectId PostToModelSpace(AcDbEntity *pEnt){ //打开块表 AcDbBlockTable *pBlockTable ...

  9. oracle表空间中PCTFREE, PCTUSED, INITRANS, MAXTRANX参数的解释

    1. PCTFREE 要形容一个 BLOCK 的运作,我们可以把一个 BLOCK 想成一个水杯.侍者把水倒入放在我们面前的水杯,要多满呢,我们要求他倒 9 分满好了,这时候 PCTFREE 代表着设定 ...

随机推荐

  1. Sql还原数据库出现3154错误

    要先知道还原的数据库的名字 然后在数据库中新建一个那个名字的数据库, his 是数据库的名字!! RESTORE DATABASE his FROM DISK = 'E:\RDHL文件\HIS相关文档 ...

  2. 线程锁的概念函数EnterCriticalSection和LeaveCriticalSection的使用方法

    线程锁的概念函数EnterCriticalSection和LeaveCriticalSection的使用方法 注:使用结构CRITICAL_SECTION 需增加头文件#include “afxmt. ...

  3. 转载:ecshop自定义销量

    转自:http://www.phpally.com/ecshop%E8%87%AA%E5%AE%9A%E4%B9%89%E9%94%80%E9%87%8F/ 本补丁以假乱真,对网站销售有一定帮助,计算 ...

  4. WPF DataGrid_SelectChanged获取单元内容

    private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)        {          ...

  5. CSS检测的高像素密度屏幕设备

    iPhone4尽管是640px解析度,但它的屏幕宽度(device-width)目前只有320px和iPhone3G相同.只是iPhone4S的像素密度2. 然后使用meta viewport什么时候 ...

  6. JSF教程(9)——生命周期之Process Validations Phase

    在这个过程其中JSF的实现者使用processValidators方法处理全部在tree中的组件中注冊的验证器.验证的过程就是通过每一个组件已有的规则对其已经保存的值进行校验,同一时候也对输入的值进行 ...

  7. js如果你想删除您问

    if (confirm("OK删除?") == true)

  8. jquey :eq(1)

    $("#div_Goods .datagrid-row .numberbox:eq(1)") $("#div_Goods .datagrid-row .numberbox ...

  9. Eclipse+Maven创建webapp项目<二> (转)

    Eclipse+Maven创建webapp项目<二> 1.开启eclipse,右键new——>other,如下图找到maven project 2.选择maven project,显 ...

  10. jspsmart(支持中文下载)

    将excel文件从jsp页面导入到数据库,先将文件上传到server,然后读取,最后删除掉上传//要加encType="multipart/form-data"<form a ...