查看: 6616|回复: 9

OSG 碰撞检测之多面体求交器代码解读(PloytopeIntersector) (下)

[复制链接]

该用户从未签到

发表于 2009-8-2 15:43:42 | 显示全部楼层 |阅读模式
续上:
其后最主要的还是在于对于drawable里的每个primitiveset 进行接受fuctor访问操作 (*itr)->accept(functor);
我们知道.primitiveset里头拥有的数据是顶点最后绘制的规则. 相当于我们在OPENGL当中使用glBegin() glEnd()一样指定最后基础图元生成的规则.而我们所要求交集的目的在于获得跟这些基础图元的交集.因此.我们有必要继续往下深究.我们还没有嗅到最终结果,还不能够放弃. 好了 继续..PrimitiveSet又是一个虚类.因此,我们有必要挑个实体类来深究.就选DrawArray吧. DrawArray指定一个MODE,顶点的起始位置,以及参与绘制的顶点的总数目..
MODE 就相当于 GL_LINES GL_TRIANGLES 等等.我们再次回到代码来说吧.
       这次我们将定位在: osg/PrimitiveSet.cpp 第43行:
       很简单... DrawArrays::accept
  1. void DrawArrays::accept(PrimitiveFunctor& functor) const
  2. {
  3.     functor.drawArrays(_mode,_first,_count);
  4. }
复制代码
所以最终的结果 都将回到fuctor里头进行交集运算的处理..._mode _first _count 将拥有的规则送往fuctor..

       在追究了这么多之后,我们又需要回到functor里头.这个functor 是什么呢? 还记得我之前说的使用PolytopePrimitiveIntersector 构造了一个func对不? 所有的关键将在那里揭开....最后的结果总还是深藏于原来的最初的起点位置..不过我想还真不枉绕了一圈...
      在我们回到func 之前我们还需要深究下functor.drawArrays() 这个函数到底做了什么? 因为在PolytopePrimitiveIntersector当初我们并未发现有这个函数.PolytopePrimitiveIntersector这个类是在PolytopeIntersector.cpp文件当中定义的.它只有一大堆的operator()操作...因此我们需要回到构造它的那个functor()里头..
现在我将定位到 include/osg/TemplatePrimitiveFunctor.h  第90行..
  1. virtual void drawArrays(GLenum mode,GLint first,GLsizei count)
  2.         {
  3.             if (_vertexArrayPtr==0 || count==0) return;

  4.             switch(mode)
  5.                 {
  6.                 case(GL_TRIANGLES): {
  7.                     const Vec3* vlast = &_vertexArrayPtr[first+count];
  8.                     for(const Vec3* vptr=&_vertexArrayPtr[first];vptr<vlast;vptr+=3)
  9.                         this->operator()(*(vptr),*(vptr+1),*(vptr+2),_treatVertexDataAsTemporary);
  10.                     break;
  11.                 }
  12.        /** *//** 后面的其他省略…… */
  13. }
复制代码
对于此,我们暂时只观看最简单的GL_TRIANGLES ,对于三角形的每三个点将会绘制一个三角形.因此每次只取三个顶点,将它传递给当前构造的func0>operator()处理.这就是为什么 func里头全部是都是operator()操作了..
       我们弄明白这些之后,马上回到PolytopePrimitiveIntersector 最后的结果.令人期待啊...
       PolytopePrimitiveIntersector中的operator()支持很多种类型,.参数的不同,一个点(points)(两个点)lines,三个点(Triangles),四个点(quads)

       最后定位在三角形的处理上: osgUtil/PolytopeIntersector.cpp 第208行.

       这段代码相当的长,但是看起来非常的好理解.这里我也将解释为什么对于多面体在定义的时候法线很重要了?  我想我有必要将这部分代码全部解读清楚..这部分是关键.
  1. void operator()(const Vec3_type v1, const Vec3_type v2, const Vec3_type v3, bool treatVertexDataAsTemporary)
  2. {
  3.      /** 代码很长 省略 请自行观看源码*/
  4. }
复制代码
现在将做最后的代码解读工作 selector_mask 当前操作平面编号的标记 inside_mask 标记三角形在哪些平面的正面?即所说在区域内..对于所有平面,将进行如下操作:
1.  d1 d2 d3 分别求得 ax+by+cz+d < = > 0
     [ax+by+cz >0 表示点在正面这边,=0 表示点平面上,<0则表示在背面这边]
     若三个点都在某个平面的背面..那说明这个三角形肯定在这个多面体的区域外.则结束..
     若三个点都在某个平面的正面,则做标记并继续其他平面.
2.  若不是以上两种情况,那分别判断v1v2 v1v3 v2v3这三条线段的与平面的交点.并加入至候选顶点列表当中.

在对所有平面都进行操作之后,需要判断几种情况我们可以考虑?
第一.三角形刚好在多面体内部.
第二.可能这些交点落在其他平面的背面了.
第三 可能三条边与平面是存在交点.但是多面体的组成的闭合区域却刚好穿过三角形内部.这个时候必须对平面的交线与三角形求交点..

所以这三个部分完全概括了上面的代码?是的.我想这个部分并不需要我讲的有多么详细了.很容易理解的.

其后,我还想深究下最后这个交集会存放到哪里去了?我们最终该如何使用获得交集才能够更好被我们所利用?
  1. addIntersection(_index, _candidates);
复制代码
对于每处理一个三角形 _index 都会在开头部分自增..因此 对于Intersections中的每一个交集的点都针对于同一个三角形..(对于别的同理可得?) 也就是说_index表示在primitiveSet当中.这个三角形是第几个三角形.(三角形序号)
    最后,我们再次回到我们最开始进入这么大段篇幅讨论的起始位置吧?还记得否?我们第二个intersect()函数..就是PolytopeIntersector类中的..因为我们最后的结果总会回归到我们需要的地方.所以我们现在得回到那里去取得我们最终获得的数据/.
    结果如何?
  1. for(PolytopeIntersectorUtils::Intersections::const_iterator it=func.intersections.begin();
  2.         it!=func.intersections.end();
  3.         ++it)
  4.     {
  5.         const PolytopeIntersectorUtils::PolytopeIntersection& intersection = *it;

  6.         Intersection hit;
  7.         hit.distance = intersection._distance;
  8.         hit.maxDistance = intersection._maxDistance;
  9.         hit.primitiveIndex = intersection._index;
  10.         hit.nodePath = iv.getNodePath();
  11.         hit.drawable = drawable;
  12.         hit.matrix = iv.getModelMatrix();

  13.         osg::Vec3 center;
  14.         for (unsigned int i=0; i<intersection._numPoints; ++i)
  15.         {
  16.             center += intersection._points[i];
  17.         }
  18.         center /= float(intersection._numPoints);
  19.         hit.localIntersectionPoint = center;

  20.         hit.numIntersectionPoints = intersection._numPoints;
  21.         std::copy(&intersection._points[0], &intersection._points[intersection._numPoints],
  22.               &hit.intersectionPoints[0]);

  23.         insertIntersection(hit);
  24.     }
复制代码
对于从func中获得的交集.我们将需要将它变成我们所需要的数据.我将一一解释最终我们得到的每个数据的含义:
  1.      
  2.      hit.distance // 表示从当前这个交集的所有顶点的中心点到参考平面的距离.
  3.      hit.primitiveIndex //表示之前我们说的这个图元在PrimitiveSet中的序号.
  4.      hit.nodepath  //表示这个从根结点到当前这个geode的路径..因为我们知道在vistor中我们有pushNodepath() popNodePath()来保存这个路径操作..所以这个路径是从vistor中获得的.
  5.      hit.drawable //当然是我们保存着当前这个交集是对于哪个drawable.
  6.      hit.matrix   //表示当前这个drawable应当在世界坐标系的变换矩阵.我们可以使用point*matrix 来得到获得点在世界坐标系下的位置..
  7.      hit.localIntersecotPoint  //表示所有交点的中心点.
  8.      hit.intersectorPoint //所有交点的一个数组..目前最多的顶点个数应该是6..  enum { MaxNumIntesectionPoints=6 };
  9.      hit.numintersectorPoint // 所有顶点的个数..
复制代码
我想这个解读过程到此应当结束了...继续学习ING.....

该用户从未签到

发表于 2011-2-20 14:03:02 | 显示全部楼层
学习了

该用户从未签到

发表于 2011-2-23 17:12:42 | 显示全部楼层
支持分享啊

该用户从未签到

发表于 2011-3-17 09:34:06 | 显示全部楼层
这个解读过程很详细,赞美lz

该用户从未签到

发表于 2011-12-5 09:27:04 | 显示全部楼层
赞一个,超强啊

该用户从未签到

发表于 2011-12-27 09:39:01 | 显示全部楼层
好贴!希望有更多好贴。

该用户从未签到

发表于 2012-12-23 23:59:15 | 显示全部楼层
这个写的好,受益非浅,谢谢!

该用户从未签到

发表于 2013-3-25 20:46:59 | 显示全部楼层
谢谢分享

该用户从未签到

发表于 2014-4-16 15:17:56 | 显示全部楼层
非常受益!感谢分享!

该用户从未签到

发表于 2015-8-30 21:21:59 | 显示全部楼层
学习了,好帖子
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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