Box2d源码学习<十二>b2Collision之碰撞(上)公共部分的实现

来源:互联网 发布:淘宝哪家情侣装好看 编辑:程序博客网 时间:2024/06/14 17:39

本系列博客是由扭曲45原创,欢迎转载,转载时注明出处,http://blog.csdn.net/cg0206/article/details/8390560

Box2d中将碰撞部分单独放到几个文件中去实现的,它的结构和函数用于计算接触点,距离查询和TOI查询。我们根据这些文件实现功能的不同,我们将该部分分成两个小的部分。它们是:

1、  公共部分的实现

2、  具体形状间的碰撞的实现

 

我们今天就来看第一部分。关于公共部分,主要包括相关结构体的定义和公共函数的实现。

对于b2Collision.h文件,我们也将它分成以下几个部分:

a)、外部类和常量在头文件的声明

b)、结构体的定义

c)、全局函数的声明

d)、内联函数的实现

好了,我们就依次来看看相关源码。

1、外部类和常量在头文件的声明

[cpp] view plain copy
  1. //声明类  
  2. class b2Shape;  
  3. class b2CircleShape;  
  4. class b2EdgeShape;  
  5. class b2PolygonShape;  
  6. //定义特征的无效值  
  7. const uint8 b2_nullFeature = UCHAR_MAX;  

不多说了,看注释。

2、  结构体的定义

[cpp] view plain copy
  1. //特征,交叉形成的接触点  
  2. // 必须是4字节或者更少  
  3. struct b2ContactFeature  
  4. {  
  5.     enum Type  
  6.     {  
  7.         e_vertex = 0,  
  8.         e_face = 1  
  9.     };  
  10.   
  11.     uint8 indexA;       // shapeA的特征索引  
  12.     uint8 indexB;       // shapeB的特征索引  
  13.     uint8 typeA;        // shapeA的特征类型  
  14.     uint8 typeB;        // shapeB的特征类型  
  15. };  
  16.   
  17. //接触id  
  18. union b2ContactID  
  19. {  
  20.     b2ContactFeature cf;        //特征对象变量  
  21.     uint32 key;                 //特征id,用于快速比较  
  22. };  
  23. //流形点属于接触流形的一个接触点。它具有的细节涉及到接触点的几何学和力学  
  24. // 局部点的求解依赖于流形的类型:  
  25. // e_circles:circleB的局部中心  
  26. // e_faceA  :circleB的局部中心 或者polygonB的夹点  
  27. // e_faceB  :polygonA的夹点  
  28. // 这个结构存储在时间步内,所以我们保持它小一些。  
  29. // 注意:这个冲量用来作为内部缓冲,很可能无法提供可靠的接触的力,尤其在高速碰撞的时候  
  30. struct b2ManifoldPoint  
  31. {  
  32.     b2Vec2 localPoint;      //局部点,求解依赖于流形类型  
  33.     float32 normalImpulse;  //法向冲量,用于防止形状的穿透  
  34.     float32 tangentImpulse; //切向冲量,用于模拟摩擦  
  35.     b2ContactID id;         //唯一地标识一个在两个形状之间的接触点  
  36. };  
  37. // 流形(注:也有人译为‘取样’,在物理和数学中均使用‘流形’,参照http://zh.wikipedia.org/wiki/流形 )  
  38. // 流形是两个凸形状的接触部分。  
  39. // Box2D支持多种类型的接触:  
  40. // 夹点与平面半径  
  41. // 点与点半径(圆)  
  42. // 局部的点求解取决于流形的类型:  
  43. // e_circles:circleA的中心  
  44. // e_faceA  : faceA的中心  
  45. // e_faceB  :faceB的重心  
  46. // 同样局部法向量的求解:  
  47. // e_circles:不用  
  48. // e_faceA  : faceA的法向量  
  49. // e_faceB  :faceB的法向量  
  50. // 我们用这种方式存储联系,以便移动时位置被更正。  
  51. //所有接触场景必须表述为这些类型中的一个。  
  52. //这个结构存储在时间步内,所以我们保持它小一些。  
  53. struct b2Manifold  
  54. {  
  55.     //流形的类型  
  56.     enum Type  
  57.     {  
  58.         e_circles,                                  //圆  
  59.         e_faceA,                                    //面A  
  60.         e_faceB                                     //面B  
  61.     };  
  62.   
  63.     b2ManifoldPoint points[b2_maxManifoldPoints];   // 接触点数组  
  64.     b2Vec2 localNormal;                             // 局部法向量,对Type::e_points没用  
  65.     b2Vec2 localPoint;                              // 求解依赖流形类型  
  66.     Type type;                                      // 类型  
  67.     int32 pointCount;                               // 流形的点的总数  
  68. };  
  69. //  这是用于求解当前状态下的接触流形  
  70. struct b2WorldManifold  
  71. {  
  72.     /************************************************************************** 
  73.     * 功能描述:根据流形和提供的变换初始化此结构体。假设适度移动从原始状态开始的。 
  74.                 这不能改变点的数量、冲量等等。半径必须来着与产生流形的形状。 
  75.     * 参数说明: manifold:流形的指针,用于初始化结构体 
  76.                  xfA     :变换A的引用 
  77.                  radiusA :形状A的半径 
  78.                  xfB     :变化B的引用 
  79.                  radiusB :形状B的半径 
  80.     * 返 回 值: (void) 
  81.     ***************************************************************************/  
  82.     void Initialize(const b2Manifold* manifold,  
  83.                     const b2Transform& xfA, float32 radiusA,  
  84.                     const b2Transform& xfB, float32 radiusB);  
  85.   
  86.     b2Vec2 normal;                          //世界向量方向从A到B  
  87.     b2Vec2 points[b2_maxManifoldPoints];    //世界接触点(交点)  
  88. };  
  89. //接触点的状态  
  90. enum b2PointState  
  91. {  
  92.     b2_nullState,       //点不存在  
  93.     b2_addState,        //在update中添加点  
  94.     b2_persistState,    //点在update中持续存在  
  95.     b2_removeState      //点移除update  
  96. };  
  97.   
  98. //裁剪顶点结构体,用于接触流形的求解  
  99. struct b2ClipVertex  
  100. {  
  101.     b2Vec2 v;        //接触点  
  102.     b2ContactID id;  //接触id  
  103. };  
  104.   
  105. //光线输入数据。光线从p1扩展到到p1 + maxFraction * (p2 - p1)  
  106. struct b2RayCastInput  
  107. {  
  108.     b2Vec2 p1, p2;             //光线(或射线)上的两个点,其中p1是起始点  
  109.     float32 maxFraction;       //需要检测的光线范围  
  110. };  
  111.   
  112. //光线输出数据。光线达到p1 + fraction * (p2 - p1),其中p1和 p2来自b2RayCastInput  
  113. struct b2RayCastOutput  
  114. {  
  115.     b2Vec2 normal;            //法向量  
  116.     float32 fraction;         //碰撞点位置的参数值  
  117. };  
  118. ///轴对齐包围盒  
  119. struct b2AABB  
  120. {  
  121.     /************************************************************************** 
  122.     * 功能描述:验证边界排序是否有效 
  123.     * 参数说明: (void) 
  124.     * 返 回 值: (void) 
  125.     ***************************************************************************/  
  126.     bool IsValid() const;  
  127.     /************************************************************************** 
  128.     * 功能描述:获取AABB的中心点 
  129.     * 参数说明: (void) 
  130.     * 返 回 值: 中心点坐标 
  131.     ***************************************************************************/  
  132.     b2Vec2 GetCenter() const  
  133.     {  
  134.         return 0.5f * (lowerBound + upperBound);  
  135.     }  
  136.     /************************************************************************** 
  137.     * 功能描述:获取AABB的区段(宽高的一半) 
  138.     * 参数说明: (void) 
  139.     * 返 回 值: aabb的区段 
  140.     ***************************************************************************/  
  141.     b2Vec2 GetExtents() const  
  142.     {  
  143.         return 0.5f * (upperBound - lowerBound);  
  144.     }  
  145.     /************************************************************************** 
  146.     * 功能描述:获取AABB的周长 
  147.     * 参数说明: (void) 
  148.     * 返 回 值: AABB的周长 
  149.     ***************************************************************************/  
  150.     float32 GetPerimeter() const  
  151.     {  
  152.         float32 wx = upperBound.x - lowerBound.x;  
  153.         float32 wy = upperBound.y - lowerBound.y;  
  154.         return 2.0f * (wx + wy);  
  155.     }  
  156.     /************************************************************************** 
  157.     * 功能描述:合并AABB 
  158.     * 参数说明: aabb:aabb的引用 
  159.     * 返 回 值: (void) 
  160.     ***************************************************************************/  
  161.     void Combine(const b2AABB& aabb)  
  162.     {  
  163.         lowerBound = b2Min(lowerBound, aabb.lowerBound);  
  164.         upperBound = b2Max(upperBound, aabb.upperBound);  
  165.     }  
  166.     /************************************************************************** 
  167.     * 功能描述:合并两个AABB,为对象的aabb赋值 
  168.     * 参数说明: aabb1:一个AABB的引用 
  169.                  aabb2:一个AABB的引用 
  170.     * 返 回 值: (void) 
  171.     ***************************************************************************/  
  172.     void Combine(const b2AABB& aabb1, const b2AABB& aabb2)  
  173.     {  
  174.         lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound);  
  175.         upperBound = b2Max(aabb1.upperBound, aabb2.upperBound);  
  176.     }  
  177.     /************************************************************************** 
  178.     * 功能描述:当前aabb是否包含提供的AABB 
  179.     * 参数说明: aabb1:提供的AABB的引用 
  180.     * 返 回 值: true :包含 
  181.                  false:不包含 
  182.     ***************************************************************************/  
  183.     bool Contains(const b2AABB& aabb) const  
  184.     {  
  185.         bool result = true;  
  186.         result = result && lowerBound.x <= aabb.lowerBound.x;  
  187.         result = result && lowerBound.y <= aabb.lowerBound.y;  
  188.         result = result && aabb.upperBound.x <= upperBound.x;  
  189.         result = result && aabb.upperBound.y <= upperBound.y;  
  190.         return result;  
  191.     }  
  192.     /************************************************************************** 
  193.     * 功能描述:光线投射 
  194.     * 参数说明: output:光线输出数据引用 
  195.                  input :光线输入数据引用 
  196.     * 返 回 值: true :碰撞 
  197.                  false:不碰撞 
  198.     ***************************************************************************/  
  199.     bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;  
  200.   
  201.     b2Vec2 lowerBound;  //lower顶点  
  202.     b2Vec2 upperBound;  //upper顶点  
  203. };  

对于b2ContactFeature和b2ContactID来说主要是和接触相关的结构体,用于保存两形状碰撞时产生的碰撞点的相关信息。对于b2ManifoldPoint、b2Manifold、b2WorldManifold、b2PointState、b2ClipVertex主要用于流形(关于流形 参照 http://zh.wikipedia.org/wiki/流形)相关的结构体,关于具体信息,请看上面的注释。对于b2RayCastInput和b2RayCastOutput结构,这个大家应该很眼熟吧,主要是在光线投射下,保存光线输入和输出数据的。再看看我们更眼熟的b2AABB结构体(小样,原来你的家在这儿,这下你跑不了了吧,嘿嘿),这里有些功能函数的实现,在此也不多说了。


3、全局函数的声明

[cpp] view plain copy
  1. /************************************************************************** 
  2. * 功能描述:通过两个流形计算点的状态。这些状态与从manifold1到maniflod2的过渡有关 
  3.             所以state1要么是持续更新要么就是删除 
  4.             state2要么是添加要么是持续更新 
  5. * 参数说明: state1   :状态1,用于保存mainfold1中接触点的状态 
  6.              state2   :状态2,用于保存mainfold2中接触点的状态 
  7.              manifold1:流形1 
  8.              manifold2:流形2 
  9. * 返 回 值: (void) 
  10. ***************************************************************************/  
  11. void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],  
  12.                       const b2Manifold* manifold1, const b2Manifold* manifold2);  
  13. /************************************************************************** 
  14. * 功能描述:求两个圆形成的碰撞流形 
  15. * 参数说明: manifold :流形对象的指针 
  16.              circleA  :圆形A对象指针 
  17.              xfA      :变换A对象引用 
  18.              circleB  :圆形B对象指针 
  19.              xfB      :变换B对象引用 
  20. * 返 回 值: (void) 
  21. ***************************************************************************/  
  22. void b2CollideCircles(b2Manifold* manifold,  
  23.                       const b2CircleShape* circleA, const b2Transform& xfA,  
  24.                       const b2CircleShape* circleB, const b2Transform& xfB);  
  25.   
  26. /************************************************************************** 
  27. * 功能描述:求一个多边形和一个圆形成的碰撞流形 
  28. * 参数说明: manifold :流形对象的指针 
  29.              polygonA :多边形A对象指针 
  30.              xfA      :变换A对象引用 
  31.              circleB  :圆形B对象指针 
  32.              xfB      :变换B对象引用 
  33. * 返 回 值: (void) 
  34. ***************************************************************************/  
  35. void b2CollidePolygonAndCircle(b2Manifold* manifold,  
  36.                                const b2PolygonShape* polygonA, const b2Transform& xfA,  
  37.                                const b2CircleShape* circleB, const b2Transform& xfB);  
  38.   
  39. /************************************************************************** 
  40. * 功能描述:求解两个多边形碰撞产生的流形 
  41. * 参数说明: manifold:碰撞流形指针,用于保存两个圆产生的流形 
  42.              polygonA:多边形A指针 
  43.              xfA     :变换A 
  44.              polygonB:多边形B指针 
  45.              xfB     :变换B 
  46. * 返 回 值: (void) 
  47. ***************************************************************************/  
  48. void b2CollidePolygons(b2Manifold* manifold,  
  49.                        const b2PolygonShape* polygonA, const b2Transform& xfA,  
  50.                        const b2PolygonShape* polygonB, const b2Transform& xfB);  
  51. /************************************************************************** 
  52. * 功能描述:求解一个边缘形状和一个圆碰撞产生的流形 
  53. * 参数说明: manifold:碰撞流形指针,用于保存两个圆产生的流形 
  54.              polygonA:多边形A指针 
  55.              xfA     :变换A 
  56.              polygonB:多边形B指针 
  57.              xfB     :变换B 
  58. * 返 回 值: (void) 
  59. ***************************************************************************/  
  60. void b2CollideEdgeAndCircle(b2Manifold* manifold,  
  61.                                const b2EdgeShape* polygonA, const b2Transform& xfA,  
  62.                                const b2CircleShape* circleB, const b2Transform& xfB);  
  63. /************************************************************************** 
  64. * 功能描述:求解一个边缘形状和一个多边形碰撞产生的流形 
  65. * 参数说明: manifold:碰撞流形指针,用于保存两个圆产生的流形 
  66.              edgeA   :边缘形状A指针 
  67.              xfA     :变换A 
  68.              polygonB:多边形B指针 
  69.              xfB     :变换B 
  70. * 返 回 值: (void) 
  71. ***************************************************************************/  
  72. void b2CollideEdgeAndPolygon(b2Manifold* manifold,  
  73.                                const b2EdgeShape* edgeA, const b2Transform& xfA,  
  74.                                const b2PolygonShape* circleB, const b2Transform& xfB);  
  75.   
  76.   
  77. /************************************************************************** 
  78. * 功能描述:裁剪碰撞流形 
  79. * 参数说明: vOut        :裁剪顶点输出数组 
  80.              vIn         :裁剪顶点输入数组 
  81.              normal      :法向量 
  82.              offset      :偏移量 
  83.              vertexIndexA:顶点索引 
  84. * 返 回 值: 输出顶点的个数 
  85. ***************************************************************************/  
  86. int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],  
  87.                             const b2Vec2& normal, float32 offset, int32 vertexIndexA);  
  88. /************************************************************************** 
  89. * 功能描述:测试两个通用的形状是否重叠。 
  90.             通过距离【Distance】判断是否重叠 
  91. * 参数说明: shapeA :形状A 
  92.              indexA :索引A 
  93.              shapeB :形状B 
  94.              indexB :索引B 
  95.              xfA    :变换A 
  96.              xfB    : 变换B 
  97. * 返 回 值:true    :重叠 
  98.             false   :不重叠 
  99. ***************************************************************************/  
  100. bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,  
  101.                     const b2Shape* shapeB, int32 indexB,  
  102.                     const b2Transform& xfA, const b2Transform& xfB);  

此部分,注释已经说的很清楚了,在此也不赘述了。

 

4、内联函数的实现

[cpp] view plain copy
  1. //验证边界排序是否有效  
  2. inline bool b2AABB::IsValid() const  
  3. {  
  4.     b2Vec2 d = upperBound - lowerBound;  
  5.     bool valid = d.x >= 0.0f && d.y >= 0.0f;  
  6.     valid = valid && lowerBound.IsValid() && upperBound.IsValid();  
  7.     return valid;  
  8. }  
  9. /************************************************************************** 
  10. * 功能描述:测试两个通用的形状是否重叠。 
  11.             通过aabb判断是否重叠 
  12. * 参数说明: a :AABB对象的引用 
  13.              b :AABB对象的引用 
  14. * 返 回 值: true :重叠 
  15.              false:不重叠 
  16. ***************************************************************************/  
  17. inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b)  
  18. {  
  19.     b2Vec2 d1, d2;  
  20.     d1 = b.lowerBound - a.upperBound;  
  21.     d2 = a.lowerBound - b.upperBound;  
  22.   
  23.     if (d1.x > 0.0f || d1.y > 0.0f)  
  24.         return false;  
  25.   
  26.     if (d2.x > 0.0f || d2.y > 0.0f)  
  27.         return false;  
  28.   
  29.     return true;  
  30. }  

对于b2TestOverlap函数,我们可以看到此处进行了函数的重载,对于上一个TestOverlap函数是通过距离【Distance】判断是否重叠的,而这个函数则是通过通过aabb判断是否重叠。两者用不同的方法,却实现了相同的效果,但是从某些方面来说通过距离判断是否重叠的话更加精确一点,但效率方面却要第一点。为此,我们可以根据用户的不同要求让用户选择不同的函数,如用户要求精确度高,同时效率方面不是太在乎的我们可以选择通过距离判断的那种,相反,我们可以选择通过aabb判断的那种。

 

我们再来看看b2Collision.cpp文件,还是上源码:

[cpp] view plain copy
  1. //根据流形和提供的变换初始化此结构体。  
  2. void b2WorldManifold::Initialize(const b2Manifold* manifold,  
  3.                           const b2Transform& xfA, float32 radiusA,  
  4.                           const b2Transform& xfB, float32 radiusB)  
  5. {  
  6.     //判断流形的点  
  7.     if (manifold->pointCount == 0)  
  8.     {  
  9.         return;  
  10.     }  
  11.     //获取流形的类型  
  12.     switch (manifold->type)  
  13.     {  
  14.     case b2Manifold::e_circles:                                   //圆形  
  15.         {  
  16.             //设置法向量  
  17.             normal.Set(1.0f, 0.0f);  
  18.             b2Vec2 pointA = b2Mul(xfA, manifold->localPoint);  
  19.             b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint);  
  20.             //判断两点是否重合  
  21.             if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)  
  22.             {  
  23.                 //获取法向量,并标准化  
  24.                 normal = pointB - pointA;  
  25.                 normal.Normalize();  
  26.             }  
  27.             //获取世界接触点  
  28.             b2Vec2 cA = pointA + radiusA * normal;  
  29.             b2Vec2 cB = pointB - radiusB * normal;  
  30.             points[0] = 0.5f * (cA + cB);  
  31.         }  
  32.         break;  
  33.   
  34.     case b2Manifold::e_faceA:                                   //面A  
  35.         {  
  36.             //  
  37.             normal = b2Mul(xfA.q, manifold->localNormal);  
  38.             b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint);  
  39.             //获取世界接触点  
  40.             for (int32 i = 0; i < manifold->pointCount; ++i)  
  41.             {  
  42.                 b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint);  
  43.                 b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal;  
  44.                 b2Vec2 cB = clipPoint - radiusB * normal;  
  45.                 points[i] = 0.5f * (cA + cB);  
  46.             }  
  47.         }  
  48.         break;  
  49.   
  50.     case b2Manifold::e_faceB:                                 //面B  
  51.         {  
  52.             normal = b2Mul(xfB.q, manifold->localNormal);  
  53.             b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);  
  54.             //获取世界接触点  
  55.             for (int32 i = 0; i < manifold->pointCount; ++i)  
  56.             {  
  57.                 b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);  
  58.                 b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;  
  59.                 b2Vec2 cA = clipPoint - radiusA * normal;  
  60.                 points[i] = 0.5f * (cA + cB);  
  61.             }  
  62.             // 保证法向量的顶点是A到B的  
  63.             normal = -normal;  
  64.         }  
  65.         break;  
  66.     }  
  67. }  
  68. //通过给定的两个流形计算点的状态。  
  69. void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],  
  70.                       const b2Manifold* manifold1, const b2Manifold* manifold2)  
  71. {  
  72.     //置空初始状态  
  73.     for (int32 i = 0; i < b2_maxManifoldPoints; ++i)  
  74.     {  
  75.         state1[i] = b2_nullState;  
  76.         state2[i] = b2_nullState;  
  77.     }  
  78.     //遍历maifold1检测状态的持续和删除  
  79.     for (int32 i = 0; i < manifold1->pointCount; ++i)  
  80.     {  
  81.         //获取mainfold1的接触id  
  82.         b2ContactID id = manifold1->points[i].id;  
  83.         //将状态置为删除状态  
  84.         state1[i] = b2_removeState;  
  85.         //遍历manifold2检测是否有接触存在  
  86.         //若有则修改当前状态为持续  
  87.         for (int32 j = 0; j < manifold2->pointCount; ++j)  
  88.         {  
  89.             //接触点是否相等  
  90.             if (manifold2->points[j].id.key == id.key)  
  91.             {  
  92.                 //改变接触状态  
  93.                 state1[i] = b2_persistState;  
  94.                 break;  
  95.             }  
  96.         }  
  97.     }  
  98.   
  99.     //遍历maifold1检测状态的持续和添加  
  100.     for (int32 i = 0; i < manifold2->pointCount; ++i)  
  101.     {  
  102.         //获取mainfold2的接触id  
  103.         b2ContactID id = manifold2->points[i].id;  
  104.         //将状态置为添加状态  
  105.         state2[i] = b2_addState;  
  106.         //遍历manifold1检测是否有接触存在  
  107.         //若有则修改当前状态为持续  
  108.         for (int32 j = 0; j < manifold1->pointCount; ++j)  
  109.         {  
  110.             //接触点是否相等  
  111.             if (manifold1->points[j].id.key == id.key)  
  112.             {  
  113.                 //改变接触状态  
  114.                 state2[i] = b2_persistState;  
  115.                 break;  
  116.             }  
  117.         }  
  118.     }  
  119. }  
  120. //光线投射  
  121. bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const  
  122. {  
  123.     //获取float的边值  
  124.     float32 tmin = -b2_maxFloat;  
  125.     float32 tmax = b2_maxFloat;  
  126.     //获取差值并用b2Abs取它的绝对值  
  127.     b2Vec2 p = input.p1;  
  128.     b2Vec2 d = input.p2 - input.p1;  
  129.     b2Vec2 absD = b2Abs(d);  
  130.     //平面的法线  
  131.     b2Vec2 normal;  
  132.   
  133.     for (int32 i = 0; i < 2; ++i)  
  134.     {  
  135.         if (absD(i) < b2_epsilon)  
  136.         {  
  137.             // 平行  
  138.             if (p(i) < lowerBound(i) || upperBound(i) < p(i))  
  139.             {  
  140.                 return false;  
  141.             }  
  142.         }  
  143.         else  
  144.         {  
  145.             float32 inv_d = 1.0f / d(i);  
  146.             float32 t1 = (lowerBound(i) - p(i)) * inv_d;  
  147.             float32 t2 = (upperBound(i) - p(i)) * inv_d;  
  148.   
  149.             //法向量方向  
  150.             float32 s = -1.0f;  
  151.   
  152.             if (t1 > t2)  
  153.             {  
  154.                 b2Swap(t1, t2);  
  155.                 s = 1.0f;  
  156.             }  
  157.             // 提升最小值  
  158.             if (t1 > tmin)  
  159.             {  
  160.                 normal.SetZero();  
  161.                 normal(i) = s;  
  162.                 tmin = t1;  
  163.             }  
  164.             // 下降最大值  
  165.             tmax = b2Min(tmax, t2);  
  166.   
  167.             if (tmin > tmax)  
  168.             {  
  169.                 return false;  
  170.             }  
  171.         }  
  172.     }  
  173.     //验证tmin的有效值  
  174.     //光线的起始点在盒子内部  
  175.     //或者光线的相交不在maxfraction范围之内  
  176.     if (tmin < 0.0f || input.maxFraction < tmin)  
  177.     {  
  178.         return false;  
  179.     }  
  180.     //保存交点信息  
  181.     output->fraction = tmin;  
  182.     output->normal = normal;  
  183.     return true;  
  184. }  
  185.   
  186. // Sutherland-Hodgman裁剪. 参见 http://en.wikipedia.org/wiki/Sutherland-Hodgman  
  187. int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],  
  188.                         const b2Vec2& normal, float32 offset, int32 vertexIndexA)  
  189. {  
  190.     // 开始时没有输出点  
  191.     int32 numOut = 0;  
  192.     //计算线与末尾点的距离  
  193.     float32 distance0 = b2Dot(normal, vIn[0].v) - offset;  
  194.     float32 distance1 = b2Dot(normal, vIn[1].v) - offset;  
  195.     // 点都在平面的一边  
  196.     if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];  
  197.     if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];  
  198.   
  199.     // 点在平面的两边  
  200.     if (distance0 * distance1 < 0.0f)  
  201.     {  
  202.         // 查找边缘与平面的交叉点  
  203.         float32 interp = distance0 / (distance0 - distance1);  
  204.         vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);  
  205.         // VertexA 触碰到edgeB  
  206.         vOut[numOut].id.cf.indexA = vertexIndexA;  
  207.         vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB;  
  208.         vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex;  
  209.         vOut[numOut].id.cf.typeB = b2ContactFeature::e_face;  
  210.         ++numOut;  
  211.     }  
  212.     //输出点个数  
  213.     return numOut;  
  214. }  
  215. //测试两个通用的形状是否重叠。  
  216. bool b2TestOverlap( const b2Shape* shapeA, int32 indexA,  
  217.                     const b2Shape* shapeB, int32 indexB,  
  218.                     const b2Transform& xfA, const b2Transform& xfB)  
  219. {  
  220.     //初始化input变量  
  221.     b2DistanceInput input;  
  222.     input.proxyA.Set(shapeA, indexA);  
  223.     input.proxyB.Set(shapeB, indexB);  
  224.     input.transformA = xfA;  
  225.     input.transformB = xfB;  
  226.     input.useRadii = true;  
  227.     //声明cache对象  
  228.     b2SimplexCache cache;  
  229.     cache.count = 0;  
  230.     //声明output变量,并获取output  
  231.     b2DistanceOutput output;  
  232.   
  233.     b2Distance(&output, &cache, &input);  
  234.     //判断是否重叠,并返回  
  235.     return output.distance < 10.0f * b2_epsilon;  
  236. }  

本部分主要4个函数,Initialize函数初始化世界流形(当前状态下的流形)。


b2GetPointStates函数则是重新更新接触点的状态,这个函数是到程序员要用的时候自己手动调用的。


RayCast函数则用于光线投射,在这里,我们注意下那个for循环,有个问题,大家先思考一下,为什么i的终止值小于2呢?那个2究竟是干什么的?


b2ClipSegmentToLine函数是裁剪碰撞流形,这里用到了Sutherland-Hodgman裁剪,(参见 http://en.wikipedia.org/wiki/Sutherland-Hodgman),关于Sutherland-Hodgman裁剪算法,我们简单的说一下,这种方法也叫逐边裁减法,主要思想是:将多边形的各边先相对于窗口的某一条边界进行裁剪,然后将裁剪结果再与另一条边界进行裁剪,如此重复多次,便可得到最终结果。再来说说我们是怎么做的:

  1. 由函数传入相对与法线的偏移量offset,将法线加偏移量作为边界,将平面分成两部分:可见部分和不可见部分。
  2. 在获取两个输入点向量在法线方向上的长度,并和边界做比较相减,获取结果。
  3. 然后判断结果和是否有交点,并保存到数组中。

因为此处我们只有两个点,故不需要多次重复裁剪。

 

b2TestOverlap函数主要是通过判断距离来实现是否重叠的,在此就不多说了。


大家知道上面那个问题的答案了吗?

知道了?!太好了,那我就不说了。嘿嘿。。。


ps:

 

以上文章仅是一家之言,若有不妥、错误之处,请大家多多指出。同时也希望能与大家多多交流,共同进步。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 在公司交的五险一金辞职了怎么办 铝合金的渣子整到眼睛里怎么办 铁锅手柄上的铆钉拧不动怎么办 喂完鱼鱼缸上边飘着一层油膜怎么办 铸铁管道横着排的结口漏水怎么办 缤智行李架免打孔螺丝款怎么办 前保险杠和叶子板缝隙大怎么办 新奥拓的大灯调节螺丝滑丝了怎么办 小米手环2计步不准怎么办 小米手环3计步不准怎么办 眼镜用洗发水洗了后模糊怎么办 雷朋近视镜眼镜腿折了怎么办 近视镜眼镜腿断了该怎么办 老师把学生的眼镜打坏了怎么办 生死狙击忘了密保改不了密码怎么办 我叫mt狂猎之弓怎么办 你能利用你的弱点打击你怎么办 研控两相混合伺服电机反转怎么办? 战地一要我升级显卡驱动怎么办 刺客信条兄弟会存档损坏了怎么办 电脑上所有软件和文件被删了怎么办 电脑显示文件已打开无法删除怎么办 金立手机桌面停止运行黑屏怎么办 苹果平板电脑玩游戏黑屏闪退怎么办 电脑开机时显示无法找到入口怎么办 我的世界显示网络玩不了的怎么办啊 网页被设置成不可以到下一页怎么办 小天鹅热水器排污螺丝拧不动怎么办 葡萄霜霉严重叶片开始发焦了怎么办 上海高架gps定位信号差怎么办 老公开车技术不行还非要开怎么办 我偷了同学手机被发现应该怎么办 没满月孩孑4天没大便了怎么办 电机轴总是从皮带轮处断裂怎么办 天花板吊顶里的热水管经常坏怎么办 摩托车油箱下面的废油管漏油怎么办 大修机械压力机轴取不下来怎么办 萌侠传说账号密码没了怎么办 车子前保护杠塑料刮花了怎么办 糖猫电话手表关机了找不到了怎么办 小天才电话手表被洗衣机洗了怎么办