包围盒算法

说白了就是给物体装进一个盒子里,该盒子可以装下物体。目的是为了进行碰撞检测。

种类:

  1. 球状碰撞体
  2. 立方体碰撞体
  3. 胶囊碰撞体
  4. Mesh碰撞体

实现原理是OBB包围盒。

经常使用的两种碰撞算法是OBB包围盒和AABB包围盒算法。

OBB包围盒算法

方向包围盒(Oriented bounding box),简称为OBB。

OBB包围盒特点:始终沿着物体的主方向生成最小的一个矩形包围盒,并且可以随物体旋转,这就决定了它可以用来做精准的碰撞检测。

判断碰撞条件:两个多边形,在所有轴的投影都发生了重叠,则认为发生了碰撞;否则,认为没有发生碰撞。

OBB有很多中表达的方式。

cocos2dx中定义的表达方式为:

Vec3 _center;   // obb center
Vec3 _xAxis;    // x axis of obb, unit vector
Vec3 _yAxis;    // y axis of obb, unit vector
Vec3 _zAxis;    // z axis of obb, unit vector
Vec3 _extentX;  // _xAxis * _extents.x
Vec3 _extentY;  // _yAxis * _extents.y
Vec3 _extentZ;  // _zAxis * _extents.z
Vec3 _extents;  // obb length along each axis

_center :中心点

_xAxis :包围盒X轴方向单位矢量

_yAxis :包围盒Y轴方向单位矢量

_zAxis :包围盒Z轴方向单位矢量

_xAxis、_yAxis、_zAxis 为正交单位向量,定义了当前OBB包围盒的x,y,z轴,用来计算矢量投影的

_extentX :包围盒X轴坐标

_extentY :包围盒Y轴坐标

_extentZ :包围盒Z轴坐标

_extents :定义了OBB包围盒的长、宽、高

这里可以看出来,每一个OBB包围盒需要24个float类型的变量来存储,占了96个字节。这样相比AABB来说,的确会需要额外的内存空间。

减少开销的办法:只存储旋转矩阵的两个轴,只是在测试的时候,利用叉积计算第三个轴。

创建 OBB

cocos2dx 使用了两种创建方式

利用AABB

由一个AABB包围盒来确定最终OBB包围盒。

OBB::OBB(const AABB& aabb)
{reset();_center = (aabb._min + aabb._max);_center.scale(0.5f);_xAxis.set(1.0f, 0.0f, 0.0f);_yAxis.set(0.0f, 1.0f, 0.0f);_zAxis.set(0.0f, 0.0f, 1.0f);_extents = aabb._max - aabb._min;_extents.scale(0.5f);computeExtAxis();
}
协方差矩阵

利用协方差矩阵来确定一个方向包围盒。

通俗点就是将原基下的坐标转换到新基上,然后依照新基算出AABB包围盒,然后再转换到原基,这个时候就是原基的OBB包围盒了。

关于协方差和PCA的知识点可以参考:

PCA

里面讲得非常详细。

大部分引擎都使用到了该算法,cocos2dx中也使用了这个算法。如下:

//生成协方差矩阵static Mat4 _getConvarianceMatrix(const Vec3* vertPos, int vertCount)
{int i;Mat4 Cov;double S1[3];double S2[3][3];S1[0] = S1[1] = S1[2] = 0.0;S2[0][0] = S2[1][0] = S2[2][0] = 0.0;S2[0][1] = S2[1][1] = S2[2][1] = 0.0;S2[0][2] = S2[1][2] = S2[2][2] = 0.0;// get center of massfor(i=0; i<vertCount; i++){S1[0] += vertPos[i].x;S1[1] += vertPos[i].y;S1[2] += vertPos[i].z;S2[0][0] += vertPos[i].x * vertPos[i].x;S2[1][1] += vertPos[i].y * vertPos[i].y;S2[2][2] += vertPos[i].z * vertPos[i].z;S2[0][1] += vertPos[i].x * vertPos[i].y;S2[0][2] += vertPos[i].x * vertPos[i].z;S2[1][2] += vertPos[i].y * vertPos[i].z;}float n = (float)vertCount;// now get covariancesCov.m[0] = (float)(S2[0][0] - S1[0]*S1[0] / n) / n;Cov.m[5] = (float)(S2[1][1] - S1[1]*S1[1] / n) / n;Cov.m[10] = (float)(S2[2][2] - S1[2]*S1[2] / n) / n;Cov.m[4] = (float)(S2[0][1] - S1[0]*S1[1] / n) / n;Cov.m[9] = (float)(S2[1][2] - S1[1]*S1[2] / n) / n;Cov.m[8] = (float)(S2[0][2] - S1[0]*S1[2] / n) / n;Cov.m[1] = Cov.m[4];Cov.m[2] = Cov.m[8];Cov.m[6] = Cov.m[9];return Cov;
}
碰撞检测

关于碰撞检测,在另一篇中有提到,利用分离轴定理(separating axis theorem) 来进行检测。

cocos2dx 3D物理相关知识点汇总

cocos2dx中相关代码:

//将点映射到坐标上
float OBB::projectPoint(const Vec3& point, const Vec3& axis)const
{//点积的方式float dot = axis.dot(point);float ret = dot * point.length();return ret;
}
//计算 最大、最小的投影值
void OBB::getInterval(const OBB& box, const Vec3& axis, float &min, float &max)const
{Vec3 corners[8];box.getCorners(corners);float value;min = max = projectPoint(axis, corners[0]);for(int i = 1; i < 8; i++){value = projectPoint(axis, corners[i]);min = MIN(min, value);max = MAX(max, value);}
}
//取边的矢量
Vec3 OBB::getEdgeDirection(int index)const
{Vec3 corners[8];getCorners(corners);Vec3 tmpLine;switch(index){case 0:// edge with x axistmpLine = corners[5] - corners[6];tmpLine.normalize();break;case 1:// edge with y axistmpLine = corners[7] - corners[6];tmpLine.normalize();break;case 2:// edge with z axistmpLine = corners[1] - corners[6];tmpLine.normalize();break;default:CCASSERT(0, "Invalid index!");break;}return tmpLine;
}
// 取面的方向矢量
Vec3 OBB::getFaceDirection(int index) const
{Vec3 corners[8];getCorners(corners);Vec3 faceDirection, v0, v1;switch(index){case 0:// front and backv0 = corners[2] - corners[1];v1 = corners[0] - corners[1];Vec3::cross(v0, v1, &faceDirection);faceDirection.normalize();break;case 1:// left and rightv0 = corners[5] - corners[2];v1 = corners[3] - corners[2];Vec3::cross(v0, v1, &faceDirection);faceDirection.normalize();break;case 2:// top and bottomv0 = corners[1] - corners[2];v1 = corners[5] - corners[2];Vec3::cross(v0, v1, &faceDirection);faceDirection.normalize();break;default:CCASSERT(0, "Invalid index!");break;}return faceDirection;
}

利用分离轴定理判断两个OBB是否碰撞

第一个包围盒的3个坐标轴、第二个包围盒的3个坐标轴,以及垂直于某一个轴的9个轴。(一共是15个轴)

垂直于某一轴的9个轴 : 取包围盒A的X轴方向的某一边矢量(不是X坐标轴,是x轴方向边的矢量),再取包围盒B的X轴方向的某一边矢量,对两个矢量做叉乘,叉乘结果就是垂直于A和B的矢量的方向矢量,这就是一个分离轴。如此重复,用包围盒A的X轴方向的某一边矢量依次叉乘包围盒B的X,Y,Z,然后再用包围盒A的Y和Z轴方向的某一边矢量再进行这一遍流程,总共得到9个轴。

bool OBB::intersects(const OBB& box) const
{float min1, max1, min2, max2;for (int i = 0; i < 3; i++){getInterval(*this, getFaceDirection(i), min1, max1);getInterval(box, getFaceDirection(i), min2, max2);if (max1 < min2 || max2 < min1) return false;}for (int i = 0; i < 3; i++){getInterval(*this, box.getFaceDirection(i), min1, max1);getInterval(box, box.getFaceDirection(i), min2, max2);if (max1 < min2 || max2 < min1) return false;}for (int i = 0; i < 3; i++){for (int j = 0; j < 3; j++){Vec3 axis;Vec3::cross(getEdgeDirection(i), box.getEdgeDirection(j), &axis);getInterval(*this, axis, min1, max1);getInterval(box, axis, min2, max2);if (max1 < min2 || max2 < min1) return false;}}return true;
}
//检查点是否在OBB中
bool OBB::containPoint(const Vec3& point) const
{Vec3 vd = point - _center;float d = vd.dot(_xAxis);if (d > _extents.x || d < -_extents.x)return false;d = vd.dot(_yAxis);if (d > _extents.y || d < -_extents.y)return false;d = vd.dot(_zAxis);if (d > _extents.z || d < -_extents.z)return false;return true;
}

AABB包围盒算法

轴对称包围盒。

cocos2dx 中,为每一个Spite3D都提供了获取AABB包围盒的接口。

记得转换一次,因为获取的AABB包围盒的坐标系是自己,所以需要转换到世界坐标上。

const AABB& Sprite3D::getAABB() const
{Mat4 nodeToWorldTransform(getNodeToWorldTransform());// If nodeToWorldTransform matrix isn't changed, we don't need to transform aabb.if (memcmp(_nodeToWorldTransform.m, nodeToWorldTransform.m, sizeof(Mat4)) == 0 && !_aabbDirty){return _aabb;}else{_aabb.reset();if (_meshes.size()){Mat4 transform(nodeToWorldTransform);for (const auto& it : _meshes) {if (it->isVisible())_aabb.merge(it->getAABB());}_aabb.transform(transform);_nodeToWorldTransform = nodeToWorldTransform;_aabbDirty = false;}}return _aabb;
}

其他

碰撞算法用得最多的就是AABB和OBB,但也有其他的算法。比如Box2D,Bullet都有自己的一系列算法和检测机制。

Cocos2d-x 3D渲染技术 (三)相关推荐

  1. 下一代3d渲染技术,体素光线投射

    原文地址http://www.tomshardware.com/reviews/voxel-ray-casting,2423.html 强烈推荐看原英文,由于本人英语水平有限,对于图形学领悟有限,又借 ...

  2. 3D渲染技术分享:实时3D水面渲染(反射、折射、水深与水岸柔边)

    一.开篇 自从上次写了**<用实时反射Shader增强画面颜值>** 后,不少开发者开始尝试用它来渲染水面,但效果都差强人意. 这是因为,水面除了反射,还有许多细节需要考虑. 在此之前,也 ...

  3. 3D建模和3D渲染技术专题一: 热身篇,光线追踪(path Tracing),环境光阴影(ambient occlusion),焦距效果(effect focus)介绍

    相比大家都看到过美国迪斯尼或者梦工厂制作的一些动画片,其中很多都是使用3D图像技术来实现的,也就是说根本不用使用摄像机就能拍出一部很好的动画片.现在想开个专题主要介绍一些3D建模和3D渲染. 我之前在 ...

  4. 3D渲染技术分享:基于PBR的车漆Shader

    如今,许多曾经应用在游戏开发中的技术开始愈发频繁地在工业和商业领 域出现. 无论是在建筑.医疗.工业制造等高技术密度的行业,还是在零售.导航.人机互动等与普罗大众人间烟火息息相关的领域,即时渲染技术都 ...

  5. Cocos2d-x 3D渲染技术 (一)

    最近因为工作需要阅读<Cocos2D-X 3.X 3D图形学渲染技术讲解>这本书所做的笔记. GPU 语言 OpenGL : GLSL DirectX : HLSL Nvidia :CG ...

  6. 3D渲染技术分享:用实时反射Shader增强画面颜值

    自制Shader免费分享:实时反射技术实现与3D领域中的应用示例 一个离谱的开始 细心的小伙伴可能已经发现了,最近麒麟子关于 3D 图形渲染方面的文章输出比之前多了许多. 灵感来源于生活,却更有可能是 ...

  7. 3D渲染技术分享:3D游戏开发渲染调试高级技巧

    零.本文主要知识点 友情劝退:全文7400+字 如果知识点里没有你想要的,那可以直接拉到底,与评论区大神一战. 最初的计划是想写一篇关于KylinsGraphicsDebugger实现原理的文章,但感 ...

  8. Cocos2d-x 3D渲染技术 (二)

    3D坐标系统 五个空间 要把游戏模型显示到屏幕需要经历五个空间. 局部空间 (Local Space,模型空间) 世界空间 (Wolrd Space,游戏空间) 观察空间 (View Space,视觉 ...

  9. 增强现实和3D渲染技术是如何应用在SAP产品里的

    要获取更多Jerry的原创文章,请关注公众号"汪子熙":

最新文章

  1. 数据分析索引总结(下)Pandas索引技巧
  2. 函数指针与指针函数的区别
  3. 开始我的Opengl学习之路(rua)
  4. 你真的做好数字化运营了吗?来直播间,给你加点儿“灵感”丨教育专题
  5. Hardware assisted virtualization and data execution protection must be enabled in the BIOS
  6. python定时器库_Python定时器完整示例 python定时器用法举例
  7. activemq网络桥接_ActiveMQ –经纪人网络解释–第2部分
  8. C++学习之路 | PTA乙级—— 1045 快速排序 (25 分)(精简)
  9. 企业实战(Jenkins+GitLab+SonarQube)_10_Jenkins通过Depoly插件热部署Java程序
  10. ntfs安全权限和共享权限的区别
  11. 计算机图形设计论文 真实图形生成技术的发展,绘制技术论文,关于计算机图形图像绘制技术的现状应用相关参考文献资料-免费论文范文...
  12. 消息称苹果、Epic开庭时间从2021年7月提前至5月份
  13. Cron 触发器及相关内容 (第二部分)
  14. jquery扩展方法的两种形式
  15. 二分图最大匹配(最大流)
  16. php计算一年多少周,同时计算出这一周的开始时间和结束时间(可选返回时间戳或日期)
  17. 想考阿里云ACP认证,网上买题库靠谱吗?
  18. HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第3章初识CSS
  19. 家居收纳打造一个美好的家-央央家政家居收纳
  20. oppoa57升级android版本,OPPO A57刷机教程_OPPO A57升级更新官方系统包

热门文章

  1. python-docx保留格式替换其中的文字
  2. 用MATLAB实现灰色预测GM11模型
  3. ros的相关link
  4. photoshop里上色之后,颜色总是灰色的,解决办法
  5. 三国志战略版:许攸阵容初尝试,官渡之战
  6. 安卓qpythonttsspeak_简单手机编程:几行代码让你的安卓手机自动整点报时
  7. 计算机 黑屏 显示桌面,电脑进入系统后黑屏,教您电脑进入系统后黑屏怎么解决...
  8. SAP电子口岸计划使国产软件竞争陷入噩梦?
  9. android studio build中文乱码
  10. 账号注册、登录、注销---网上商城Web