算法与游戏之AABB碰撞盒算法
来源:互联网 发布:windows文件名最大长度 编辑:程序博客网 时间:2024/05/21 18:31
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。
AABB(Axis-Aligned Bounding Box)包围盒被称为轴对其包围盒。其在坐标系中的表示如下图:
在Cocos2d-x 3.x版本中,为开发者提供了AABB类,用于保存包围盒的最大顶点与最小顶点的信息,并且为每个Sprite3D对象提供了获取AABB包围盒的接口,在AABB类同时提供了判断碰撞检测的方法。有一点需要注意的是,AABB类中一开始保存的最大顶点与最小顶点的信息实际上是物体坐标系中的信息,在碰撞检测时需要将其转换成世界坐标系中的点,可通过AABB类中的transform()方法来完成。下面对AABB的源码进行分析:
#include "3d/CCAABB.h"NS_CC_BEGINAABB::AABB(){ reset();}AABB::AABB(const Vec3& min, const Vec3& max){ set(min, max);}AABB::AABB(const AABB& box){set(box._min,box._max);}//获取包围盒中心点坐标Vec3 AABB::getCenter(){ Vec3 center;center.x = 0.5f*(_min.x+_max.x);center.y = 0.5f*(_min.y+_max.y);center.z = 0.5f*(_min.z+_max.z);return center;}//获取包围盒八个顶点信息void AABB::getCorners(Vec3 *dst) const{ assert(dst);// 朝着Z轴正方向的面// 左上顶点坐标 dst[0].set(_min.x, _max.y, _max.z);// 左下顶点坐标 dst[1].set(_min.x, _min.y, _max.z);// 右下顶点坐标 dst[2].set(_max.x, _min.y, _max.z);// 右上顶点坐标 dst[3].set(_max.x, _max.y, _max.z);// 朝着Z轴负方向的面// 右上顶点坐标 dst[4].set(_max.x, _max.y, _min.z);// 右下顶点坐标. dst[5].set(_max.x, _min.y, _min.z);// 左下顶点坐标. dst[6].set(_min.x, _min.y, _min.z);// 左上顶点坐标. dst[7].set(_min.x, _max.y, _min.z);}//判断两个包围盒是否碰撞bool AABB::intersects(const AABB& aabb) const{//就是各轴互相是否包含,(aabb 包含当前包围盒)|| (当前的包围盒包含 aabb)return ((_min.x >= aabb._min.x && _min.x <= aabb._max.x) || (aabb._min.x >= _min.x && aabb._min.x <= _max.x)) && ((_min.y >= aabb._min.y && _min.y <= aabb._max.y) || (aabb._min.y >= _min.y && aabb._min.y <= _max.y)) && ((_min.z >= aabb._min.z && _min.z <= aabb._max.z) || (aabb._min.z >= _min.z && aabb._min.z <= _max.z));}//判断点和包围盒是否碰撞bool AABB::containPoint(const Vec3& point) const{if (point.x < _min.x) return false;if (point.y < _min.y) return false;if (point.z < _min.z) return false;if (point.x > _max.x) return false;if (point.y > _max.y) return false;if (point.z > _max.z) return false;returntrue;}//生成一个新的包围盒同时容纳两个包围盒,新的包围盒的_min 各轴要是其他两个最小的那个,_max各轴要是其他两个最大的那个void AABB::merge(const AABB& box){//计算新的最小点坐标 _min.x = std::min(_min.x, box._min.x); _min.y = std::min(_min.y, box._min.y); _min.z = std::min(_min.z, box._min.z);//计算新的最大点坐标 _max.x = std::max(_max.x, box._max.x); _max.y = std::max(_max.y, box._max.y); _max.z = std::max(_max.z, box._max.z);}//设置最大顶点与最小顶点void AABB::set(const Vec3& min, const Vec3& max){this->_min = min;this->_max = max;}//顶点复位初始化信息void AABB::reset(){_min.set(99999.0f, 99999.0f, 99999.0f);_max.set(-99999.0f, -99999.0f, -99999.0f);}//检测坐标信息是否有误bool AABB::isEmpty() const{return _min.x > _max.x || _min.y > _max.y || _min.z > _max.z;}//由给定点坐标点重新确定最大最小的坐标向量void AABB::updateMinMax(const Vec3* point, ssize_t num){for (ssize_t i = 0; i < num; i++) {// 左边点.if (point[i].x < _min.x) _min.x = point[i].x;//最低点if (point[i].y < _min.y) _min.y = point[i].y;// 最远点.if (point[i].z < _min.z) _min.z = point[i].z;// 右边最大点if (point[i].x > _max.x) _max.x = point[i].x;// 最高点if (point[i].y > _max.y) _max.y = point[i].y;// 最近点if (point[i].z > _max.z) _max.z = point[i].z; }}//通过给定的变换矩阵对包围盒进行变换void AABB::transform(const Mat4& mat){ Vec3 corners[8];//保存包围盒八个顶点//朝向z轴正方向的面// 左-顶-前 corners[0].set(_min.x, _max.y, _max.z);// 左-低-前 corners[1].set(_min.x, _min.y, _max.z);// 右-低-前. corners[2].set(_max.x, _min.y, _max.z);// 右-顶-前 corners[3].set(_max.x, _max.y, _max.z); //朝向z轴负方向的面// 右-顶-背面. corners[4].set(_max.x, _max.y, _min.z);// 右-底-背面. corners[5].set(_max.x, _min.y, _min.z);// 左-底-背面. corners[6].set(_min.x, _min.y, _min.z);// 左-顶-背面. corners[7].set(_min.x, _max.y, _min.z);//顶点变换for (int i = 0; i <8; i++) mat.transformPoint(&corners[i]); //mat 是变换矩阵,变换&corners[i] 向量。//复位最大顶点最小顶点 reset();//重新计算最大最小点信息 updateMinMax(corners, 8);}
当然在AABB类中也使用了矩阵转换函数,因为场景中的物体是可以移动旋转的,下面把AABB碰撞盒的变换函数给大家展示一下:
void AABB::transform(const Mat4& mat){Vec3corners[8];// 左-顶-前.corners[0].set(_min.x, _max.y, _max.z);// 左-底-前面.corners[1].set(_min.x, _min.y, _max.z);// 右-底-前.corners[2].set(_max.x, _min.y, _max.z);// 右-顶-前面.corners[3].set(_max.x, _max.y, _max.z);// 右-顶-背面.corners[4].set(_max.x, _max.y, _min.z);// 右-底-背面.corners[5].set(_max.x, _min.y, _min.z);// 左-底-背面.corners[6].set(_min.x, _min.y, _min.z);// 左-顶-背面.corners[7].set(_min.x, _max.y, _min.z);// 重新计算点的最大和最小值for (int i = 0; i <8; i++)mat.transformPoint(&corners[i]);reset();updateMinMax(corners, 8);}
物体在游戏场景中并不是静止不动的,而是可以移动、旋转的,它自身的碰撞盒也要根据物体的变化而变换。在函数的最后是碰撞盒顶点的更新函数如下所示:
void AABB::updateMinMax(const Vec3*point, ssize_tnum){ for (ssize_t i = 0; i < num; i++) { // 左边最大点. if(point[i].x<_min.x) _min.x = point[i].x; // 最低的点. if(point[i].y<_min.y) _min.y = point[i].y; // 最远的点. if(point[i].z<_min.z) _min.z = point[i].z; // 右边最大点. if(point[i].x>_max.x) _max.x = point[i].x; // 最高的点. if (point[i].y>_max.y) _max.y = point[i].y; // 最近的点. if(point[i].z>_max.z) _max.z = point[i].z; }}
AABB碰撞盒的每个顶点都需要随时更新变换位置,相比于OBB碰撞盒盒,AABB碰撞盒算法更简单,在程序上更容易实现,它应用在场景中的效果如下图:
总结:
AABB碰撞盒其实就是一个立方体,它在程序中计算效率比较高,但是在碰撞检测方面做得比较粗糙,比如一把水壶,它用AABB立方体包围后,会有很多空隙,检测效果并不是很理想,但是运算性能非常好。
0 3
- 算法与游戏之AABB碰撞盒算法
- 算法与游戏之OBB碰撞算法
- 三维物体AABB碰撞检测算法
- 三维拾取Ray-AABB碰撞检测算法
- AABB包围盒算法
- 《实时碰撞检测算法技术》读书笔记(二):轴对齐包围盒(AABB)的计算与更新
- aabb与oob包围盒 碰撞检测
- JAVA智能设备基于OpenGL的3D开发技术 之AABB碰撞检测算法论述
- C++游戏开发之碰撞检测算法
- AABB碰撞盒
- 理解AABB包围盒算法
- 理解AABB包围盒算法
- 光线与包围盒(AABB)的相交检测算法
- 光线与包围盒(AABB)的相交检测算法
- 光线与包围盒(AABB)的相交检测算法
- AABB外接盒碰撞检测
- [算法][包围盒]球,AABB,OBB
- 游戏碰撞之OBB算法实现(java代码实现)
- [Mysql] Decimal用法
- 点滴故事-写在我个人网站的0岁生日
- Arrays:用于操作数组工具类,数组转集合,集合转数
- AIDL的理解与使用详解
- c++程序设计模式之factory模式
- 算法与游戏之AABB碰撞盒算法
- AndroidStudio 获取sha1
- Ubuntu Windows双系统切换技巧
- 微信开发-分享页面修改
- C# 学习之旅(一)
- k8s网络插件cni
- 紫书例题 10-26 UVa 11440
- Math类中包含基本的数字操作,如指数、对数、平方根和三角函数。
- Redis集群搭建与简单使用