查看: 5882|回复: 11

再谈BoundingBox

[复制链接]

该用户从未签到

发表于 2011-7-13 16:46:36 | 显示全部楼层 |阅读模式
本帖最后由 湖面之舟 于 2011-7-13 20:32 编辑

最近打算学学碰撞检测,不过觉得太难了,还是先研究下包围盒吧,论坛上关于包围盒的帖子基本上都看了,也部分实现了预计效果。感觉还是有些地方不是太清楚。
首先我赞同大家说的,
osg::ComputeBoundsVisitor()计算得到是包围盒的世界坐标系。问题是当被计算对象发生空间变换时,计算出的包围盒仍然不变,是否可以理解模型没变,视图变了,因此包围盒没变?如果是,通过节点从局部坐标系到世界坐标系的变换矩阵可以计算出包围盒的位置,那么要这个类干嘛呢,因为模型的包围盒在建模时就知道了,仅仅是回调访问吗?感觉跑题了,还是直接说问题吧。


场景图结构如下图


s.jpg


代码如下:
  1. //创建包围盒
  2. osg::ref_ptr<osg::MatrixTransform> CQC::CreateBoundingBox()
  3. {
  4. //吊具包围盒
  5. spreaderCBV=new osg::ComputeBoundsVisitor();//osg::NodeVisitor::TraversalMode::TRAVERSE_PARENTS

  6. //绘制包围盒
  7. osg::ref_ptr<osg::Geode> geode=new osg::Geode();
  8. osg::ref_ptr<osg::ShapeDrawable> sd=new osg::ShapeDrawable(new osg::Box(osg::Vec3(0,0,0),1.0));
  9. sd->setColor(osg::Vec4(1.0,1.0,1.0,1.0));
  10. osg::ref_ptr<osg::StateSet> state=sd->getOrCreateStateSet();
  11. osg::ref_ptr<osg::PolygonMode> pm=new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE);
  12. state->setAttributeAndModes(pm.get());
  13. geode->addDrawable(sd.get());

  14. bbMT=new osg::MatrixTransform();
  15. bbMT->addChild(geode.get());
  16. return bbMT;
  17. }
  18. //绘制包围盒
  19. void CQC::DrawBoundingBox()
  20. {
  21. //spreaderPat->accept(*spreaderCBV);
  22. osg::Node* node=spreaderPat->getChild(0);
  23. node->accept(*spreaderCBV);
  24. spreaderBB=spreaderCBV->getBoundingBox();
  25. osg::Matrix localToWorld=osg::computeLocalToWorld(node->getParentalNodePaths()[0]);
  26. osg::Vec3 max=spreaderBB._max*localToWorld;
  27. osg::Vec3 min=spreaderBB._min*localToWorld;
  28. osg::BoundingBox bbTemp;
  29. bbTemp.set(min,max);
  30. //for (unsigned i=0;i<8;i++)
  31. //{
  32. // bbTemp.expandBy(spreaderBB.corner(i)*localToWorld);
  33. //}
  34. float lengthX=bbTemp.xMax()-bbTemp.xMin();
  35. float lengthY=bbTemp.yMax()-bbTemp.yMin();
  36. float lengthZ=bbTemp.zMax()-bbTemp.zMin();
  37. //变换矩阵
  38. bbMT->setMatrix(osg::Matrix::scale(lengthX,lengthY,lengthZ)*osg::Matrix::translate(bbTemp.center()));
  39. }
  40. //将bbMT加入主场景mRoot
  41. mRoot->addChild(CreateBoundingBox().get());
  42. //在节点回调中调用绘制包围盒
  43. void DriveCallBack::operator()(osg::Node *n, osg::NodeVisitor *nv)
  44. {
  45. //改变各Pat对象位置
  46. TrolleyMove();
  47. //绘制包围盒
  48. DrawBoundingBox();
  49. traverse(n, nv);
  50. }
复制代码



问题:

以上代码在对各osg:ositionAttitudeTransform对象进行平移操作,可以产生预计的效果(即包围盒跟随Node节点移动),但是当对Node节点的Dof子节点进行变换时,只能增大包围盒,当模型尺寸缩小时,包围盒没有相应缩小。关键在spreaderBB=spreaderCBV->getBoundingBox()这句代码得出的包围盒是模型尺寸最大时的包围盒,我怀疑getBoundingBox()函数的实现过程。

1.jpg

原始状态

2.jpg

伸长状态

3.jpg

缩小状态

该用户从未签到

 楼主| 发表于 2011-7-13 18:40:09 | 显示全部楼层
用dirtyBound也不能够让包围盒缩小

该用户从未签到

 楼主| 发表于 2011-7-13 20:04:06 | 显示全部楼层
对于Z方向的移动我做了个试验,试验对象包围盒在世界坐标系中值为(zMin,zMax)=(34.36,36.319),在回调中改变spreaderPat节点的Z坐标(-3.27个单位),分四种情况讨论:
1 变换节点应用访问器,代码如下:
spreaderPat->accept(*spreaderCBV);
//注意从父节点计算
osg::Matrix localToWorld=osg::computeLocalToWorld(spreaderPat->getParent(0)->getParentalNodePaths()[0]);
localToWorld矩阵的值如下
1     0     0     0
0     1     0     0
0     0     1     0
0     0     0     1
通过spreaderBB=spreaderCBV->getBoundingBox();计算得到经过平移转换后的
(zMin,zMax)=(31.087,36.319),由于localToWorld的32元素为0,因此包围盒的高度变为5.232,明显不对。
2 变换节点应用访问器,代码如下:
spreaderPat->accept(*spreaderCBV);
//注意从当前PAT节点计算
osg::Matrix localToWorld=osg::computeLocalToWorld(spreaderPat->getParentalNodePaths()[0]);
localToWorld矩阵的值如下
1     0     0     0
0     1     0     0
0     0     1     0
0     0     -3.27     1
通过spreaderBB=spreaderCBV->getBoundingBox();计算得到经过平移转换后的
(zMin,zMax)=(31.087,36.319),由于localToWorld的32元素为-3.27,
与矩阵相乘后为(27.81,33.05),因此包围盒的高度依然是5.232,还是不对。
3 PAT中的node节点应用访问器,代码如下:
osg::Node* node=spreaderPat->getChild(0);
node->accept(*spreaderCBV);
//注意从父节点PAT计算
osg::Matrix localToWorld=osg::computeLocalToWorld(node->getParent(0)->getParentalNodePaths()[0]);
localToWorld矩阵的值如下
1     0     0     0
0     1     0     0
0     0     1     0
0     0     -3.27     1
通过spreaderBB=spreaderCBV->getBoundingBox();计算得到经过平移转换后的
(zMin,zMax)=(34.36,36.319),由于localToWorld的32元素为-3.27,
与矩阵相乘后为(31.087,33.046),因此包围盒的高度是1.959,完全正确,即包围盒性状不变,高度下降。
4 PAT中的node节点应用访问器,代码如下:
osg::Node* node=spreaderPat->getChild(0);
node->accept(*spreaderCBV);
//注意从当前节点node计算
osg::Matrix localToWorld=osg::computeLocalToWorld(node->getParentalNodePaths()[0]);
localToWorld矩阵的值如下
1     0     0     0
0     1     0     0
0     0     1     0
0     0     -3.27     1
通过spreaderBB=spreaderCBV->getBoundingBox();计算得到经过平移转换后的
(zMin,zMax)=(34.36,36.319),由于localToWorld的32元素为-3.27,
与矩阵相乘后为(31.087,33.046),因此包围盒的高度依然是1.959,完全正确。

该用户从未签到

 楼主| 发表于 2011-7-13 20:12:11 | 显示全部楼层
通过上面的研究,我们基本上可以得出这个结论:
osg:ositionAttitudeTransform和osgSim:OFTransform类型节点保留了变换操作的过程,因此对其计算包围盒必然与直接计算二者子结点包围盒结果不同,现象就是包围盒不断扩大。
根据这个结论,不难解释帖子开头所述问题。

,不过没有想到特别完美的解决办法,望大家讨论。

该用户从未签到

发表于 2011-7-13 21:02:43 | 显示全部楼层
碰撞检测不难,包围盒或者包围球体可加速碰撞检测的过程,最终还是要和mesh的所有三角形逐一检测的。

该用户从未签到

发表于 2011-7-14 08:16:20 | 显示全部楼层
首先我赞同大家说的,osg::ComputeBoundsVisitor()计算得到是包围盒的世界坐标系。
这已经被证实是错误的了,论坛上有一个非常好的帖子,lanxun发起的,我后来给出了比较详细的分析和实验结果,应该能说明包围盒的性质和计算世界包围体的方法了

该用户从未签到

 楼主| 发表于 2011-7-14 21:11:30 | 显示全部楼层
http://bbs.osgchina.org/viewthread.php?tid=4728&highlight=lanxun
这个帖子看了几遍,基本明白什么意思。
我这个帖子估计写的太长,大家没明白我什么意思

该用户从未签到

发表于 2011-7-26 14:02:28 | 显示全部楼层
spreaderBB=spreaderCBV->getBoundingBox() 访问器获取到的包围盒应该没有问题,我试验的是MatrixTransform节点下的操作,平移不影响包围盒的大小,缩放里放大和缩小也没有问题,我建议你把pat改成MatrixTransform试试

该用户从未签到

发表于 2011-7-27 19:47:31 | 显示全部楼层
都一样,要分清楚求的包围盒是在哪个坐标系下,可以看他的源代码.

该用户从未签到

发表于 2011-7-27 19:49:08 | 显示全部楼层
求出来的应该是在node的父物体的坐标系下的包围盒

该用户从未签到

发表于 2012-9-8 13:06:14 | 显示全部楼层
顶下贴,想问下,如果模型在旋转了一个角度后,如何获取到原先大小的包围盒,即没有被放大或缩小的包围盒。

该用户从未签到

发表于 2012-9-11 15:48:24 | 显示全部楼层
初始状况的保卫和做个备份不就行了吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表