碰撞检测——GJK算法

这篇具有很好参考价值的文章主要介绍了碰撞检测——GJK算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

碰撞检测——GJK算法

1.GJK算法的原理及思想

1.1 Minkowski Sum(明可夫斯基和)

1.2 Simplex

1.3 support函数

1.4 构建Simplex

2. GJK算法步骤

3. GJK算法的优缺点分析

4. GJK算法与其他相关算法的比较分析

4.1 GJK算法和SAT算法的比较

4.2 GJK算法和EPA算法的比较

参考资料


碰撞检测——GJK算法

1.GJK算法的原理及思想

GJK算法是由 Gilbert,johnson和 Keerthi 3人在1988年共同开发的一类迭代算法。GJK算法的输入为两物体的顶点集,通过有限次数的迭代后,最后输出结果为两物体之间的欧氏距离。根据两物体之间 的欧氏距离,可进行碰撞检测。当两物体之间的距离等于或者小于零时,可判定两物体发生碰撞。基于距离跟踪的Gilbert-Johnson-Keerth(简称GJK)碰撞算法是通过支持映射来计算空间中两个凸体间距的渐进算法。

1.1 Minkowski Sum明可夫斯基和)

GJK算法中使用了明可夫斯基和的概念。假设有两个物体,它们的明可夫斯基和就是物体1上的所有点和物体2上的所有点的和集。用公式表示就是:

A + B = {a + b|a∈A, b∈B}

如果两个物体都是凸体,它们的明可夫斯基和也是凸体。

对于减法,明可夫斯基和的概念也成立,这时也可称作明可夫斯基差。

A – B = A + (-B) = {a + (– b)|a∈A, b∈B} = {a – b)|a∈A, b∈B}

如果两个形状重叠,进行Minkowski Sum后的形状包含原点。Minkowski Sum的运算是shape A的每个顶点和shape B的所有顶点求和(或求差)。所得到点的外包络即是运算所得形状。

碰撞检测——GJK算法

碰撞检测——GJK算法

1.2 Simplex

单纯形是代数拓扑中的基本概念,单纯形是三角形和四面体的一种泛化,一个k 维单纯形是指包含(k+1)个节点的凸多面体。不需要计算Minkowski Sum,只需要计算Minkowski Sum是否包含原点,如果包含原点则两个形状重叠,否则不重叠。在Minkowski Sum得到的形状中迭代的构建Simplex,判断Simplex是否包含原点,包含则重叠,否则不重叠。

1.3 support函数

support函数返回两个形状Minkowski Sum的一个点用以构建Simplex,shape1的点减去shape2的点可以得到一个Minkowski Sum的一个点,但我们不希望得到重复的点。使用support函数得到shape在一个direction(方向)上的最远点,然后在不同的方向上得到另一个不同的点。在direction上选择最远点可以使生成的Simplex的面积最大化以增加包含原点的几率增加算法收敛速度。使用这种方法得到的点在Minkowski Sum的边上,因此如果得到的点不包含原点则Minkowski Sum不包含原点。

Public Point support(Shape shape1, Shape shape2, Vector d) {
    // d is a vector direction(doesn't have to normalized)
    // get points on the edge of the shapes in opposite direction
    Point p1 = shape1.getFarthestPointInDirection(d);
    Point p2 = shape2.getFarthestPointInDirection(d.negative());
    // perform the Minkowski Sum
    Point p3 = p1.subtract(p2);
    // p3 is now a point in Minkowski space on the edge of the Minkowski Difference
    return p3;
}

1.4 构建Simplex

首先选择三个点构造Simplex,如果包含原点,则两个多边形重叠,否则重新选择点构建新的Simplex。由support函数可知,需要一个direction来选择Minkowski Sum点,任意的direction都是可以的,但是选择两个多边形的中心点的向量方向是较优的选择。

Vector d = // choose a search direction
// get the first Minkowski Difference point
Simplex.add(support(A, B, d));
// negate d for the next point
d.negate();
// start looping
while (true) {
    // add a new point to the simplex because we haven't terminated yet
    Simplex.add(support(A, B, d));
    // make sure that the last point we added actually passed the origin
    if (Simplex.geLast().dot(d) <= 0) {
        // if the point added last was not past the origin in the direction of d 
        // then the Minkowski Sum cannot possibly contain the origin since
        // the last point added is on the edge of Minkowski Difference
        return false;
    } else {
        // otherwise we need to determine if the origin is in the current simplex
        if (Simplex.contains(ORIGIN)) {
            // if it does then we know there is a collision
            return true;
        } else {
            // otherwise we cannot be certain so find the edge who is closest to the
            // origin and use its normal (in the direction of the origin) as the new
            // d and continue the loop
            d = getDirection(Simplex);
        }
    }
}

     

Simplex.geLast().dot(d) <= 0的解释:

Simplex最新得到的点是Minkowski Sum在给定方向上的最远点,如果这个点没有enclose原点,则Minkowski Sum不会包含原点。如下图,direction是(  1 , 0 ) (-1, 0)(-1,0),点p ( 1, - 4 ) p(1, 4)p(1, -4)是在direction上的最远点。点p在d上的投影是-1,原点在d dd上的投影是0,由于p是Minkowski Sum是最远点,所以其不会包含原点

碰撞检测——GJK算法

当得到两个Minkowski Sum点时,如图-4,B是第一个点,A 是第二个点,A 和B是Minkowski Sum包络上的点,如果origin在R1或者R4区域,则Minkowski Sum不包含原点,Simplex.geLast().dot(d) <= 0返回true。由图可知,origin在R3区域内,因此需要计算AB的petualar vector应该指向R3。

AB=B−A

AO=O−A

perp=(AB×AO)×AB

如图-5,此时support函数得到新的Minkowski Sum点A,点B是第二点(图-4中的A ),点C 是第一个点(图-4中的B),origin可能存在于R3、R4和R5中,计算( A C × A B ) × A B生成ABperp,计算ABprep⋅(AO)判断origin是否在R4,计算(AB×AC)×AC生成ACperp,计算ACperp⋅(AO)判断origin是否在R3。

碰撞检测——GJK算法

碰撞检测——GJK算法

 文章来源地址https://www.toymoban.com/news/detail-511969.html

  

Vector d = // choose a search direction
// get the first Minkowski Sum point
Simple.add(support(A, B, d));
// nagate d for the next point
d.negate();
// start loop
while (true) {
    // add a new point to the simplex because we haven't terminated yet
    Simple.add(support(A, B d));
    // make sure that the last point added actually passed the origin
    if (Simple.getLast().dot(d) <= 0) {
        // if the point added last was not past the origin in the direction of d 
        // then the Minkowski Sum cannot possibly contain the origin since
        // the last point added is on the edge of Minkowski Difference
        return false;
    } else {
        // otherwise determine if the origin is in the current simplex
        if (containsOrigin(Simple, d)) {
            // if it does, there is a collision
            return true;
        }
    }
}

public boolean containOrign(Simples s, Vector d) {
    // get the last point added to the simplex
    a = Simplex.getLast(); // the last point
    // compute AO (same thing as -A)
    ao = a.negate();
    if (Simplex.points.size == 3) {
        // in triangle case
        // get point B and C
        b = Simplex.getB(); // the second point
        c = Simplex.getC(); // the first point
        // compute the edges
        ab = b - a;
        ac = c - a;
        // compute the normals
        abPerp = tripleProduct(ac, ab, ab);
        acPerp = tripltProdect(ab, ac, ac);
        // is the origin in R4
        if (adPerp.dot(ao) > 0) {
            // remove point C
            Simplex.remove(c);
            // set the new direction to ABPerp
            d.set(abPerp);
        } else {
            // is the origin in R3
            if (acPerp.dot(ao) > 0) {
                // remove point B
                Simples.remove(b);
                // set the new direction to ACPerp
                d.set(acPerp);
            } else {
                // otherwise origin in R5, there is a collision
                return true;
            }
        }
    } else {
        // in line segment case
        b = Simplex.getB();
        // compute AB
        ab = b -a;
        // get the perp to AB in the direction of the origin
        abPerp = tripleProduct(ab, ao, ab);
        // set the direction to ABPerp
        d.set(abPerp);
    }
    return false;
}

 

2. GJK算法步骤

1.选取初始方向,初始方向可以是两个多边形的中心点构成的矢量,也可以是两个多边形各自选取一个顶点构成的

矢量,还可以是给定的任意矢量;

2.根据初始方向,用Support函数得到第一个support点,并放到单纯形(simplex)中;

3.将初始方向取反,作为下一-次迭代方向;

4.循环开始:

a)根据迭代方向和Support函数计算出一个新的support点;

b)若新的support点与迭代方向的点乘结果小于0 ,说明在这个迭代方向上,已经无法找到一个能够跨越原

点的support点了。也就是说,无法组成一个能够包含原点的单纯形。 即两个多边形不相交,函数退出;

c)若新的support点能够跨越原点,则将其加到simplex中;

d)更新单纯形和迭代方向,并判断simplex是否包含原点。这时simplex有两个点或三个点:

若为两个点,则这两个点构成一条直线,以该直线的垂线朝向原点的方向,作为下一次迭代方向;

若为三个点,则需要判断这三个点组成的三角形是否包含原点。若不包含,则保留离原点最近的边上的两个点,同样以这两个点的直线的垂线朝向原点的方向,作为下一次迭代方向。

回到循环的开始步骤a。

3. GJK算法的优缺点分析

优点:

基于GJK模型的算法有快速,易实施,且适用于多种凸体的优点。

它是一种迭代方法,但是收敛速度非常快,如果使用最终的穿透/分离向量进行约束,则可以在几乎恒定的时间内运行。

它可以支持实现“support ”函数的任何形状。因此不需要增加特殊的代码或算法来处理弯曲的形状。

缺点:

仅能在凸包上运行,数学模型复杂(需要有一定的线性空间,线性代数的知识),且难以理解。

线段是一种十分简单的单形体,用GJK算法进行距离计算太繁琐。

4. GJK算法与其他相关算法的比较分析

4.1 GJK算法和SAT算法的比较

分离轴定理(Separating Axis Theorem,SAT)是一种可用于精确判断两个物体是否相交的算法,不仅适用于 Box(矩形),还适用于凸多边形。SAT用来检测两个凸多边形是否相交,也可以用于检测点是否在凸多边形内。凸多边形内的点的连线上的点都在凸多边形内,或者连线只和图多边形相交两次(边界处)。

GJK与SAT一样,仅在凸包上运行。GJK更具吸引力的功能之一是,它可以支持实现“support ”函数的任何形状。因此,与SAT不同,您不需要增加特殊的代码或算法来处理弯曲的形状。

GJK是一个迭代算法,但是如果事先给出穿透/分离向量,则它的收敛会很快,可以在常量时间内完成。在3D环境中,GJK可以取代SAT算法。GJK算法的最初目的是计算两个凸体之间的距离,在两个物体穿透深度比较小的情况下,可用它判定物体之间的碰撞。它也可以和别的算法相结合,用来检测两个物体之间深度穿透时候的碰撞情况。

4.2 GJK算法和EPA算法的比较

EPA,扩展多边形算法(Epanding Polytop Algorithm) ,用来计算两个多边形碰撞的穿透深度和方向,可用于将两个发生碰撞的多边形分离。当碰撞发生时,原点到最近的闵可夫斯基差集多边形的边(下文称作“差集最近边”)的距离,就是穿透深度,原点到该边的垂直向量就是穿透向量的方向。因此,核心问题就转换成了,如何求得距离原点最近的差集边。当碰撞检测完毕后,我们会得到一个单形体(Simplex),该单形体可能包含两个或三个support点,将这些support点首尾相连构成封闭的多边形。EPA算法每次迭代的时候,从这个多边形中选择一条最近的边,沿着该边的法线方向(原点到边的垂线方向),向外扩展。直到某条边无法向外扩展时,则该边就是差集最近边。

EPA算法和GJK求最近距离算法很相似,都是在找一个差集最近边。不过EPA用于发生碰撞的情况下,GJK求最近距离用于没有发生碰撞的情况下。理论上EPA也可以用于求两个多边形的最近边,只不过EPA收敛的速度没有GJK算法快。

参考资料

参考资料:http://www.dyn4j.org/2010/04/gjk-gilbert-johnson-keerthi/
版权声明:本文为CSDN博主「小作坊钳工」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:http://t.csdn.cn/6Vmyo

游蓝海的这篇文章:http://t.csdn.cn/dxWdx

由上述文章参考并修改

 

 

到了这里,关于碰撞检测——GJK算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 常见的2D与3D碰撞检测算法

    分离轴定理(Separating Axis Theorem)是用于解决2D或3D物体碰撞检测问题的一种方法。其基本思想是,如果两个物体未发生碰撞,那么可以找到一条分离轴(即一条直线或平面),两个物体在该轴上的投影不会重叠。 具体实现时,我们需要确定所有可能作为分离轴的候选轴,并将

    2023年04月11日
    浏览(44)
  • 碰撞检测算法——分离轴算法在Unity中实现(二)

    一、介绍        分离轴算法(简称SAT)通常用于检查两个简单多边形(凸边形)之间或多边形与圆之间的碰撞。本质上,如果您能够绘制一条线来分隔两个多边形,则它们不会发生碰撞,如果找不到一条线来分割两个多边形,则它们发生碰撞。 如图:           具体做法

    2024年02月04日
    浏览(71)
  • 机器人C++库(10)Robotics Library 之碰撞检测算法

    RL库中集成了以下开源含碰撞检测功能的库: 1.bullet3:https://pybullet.org/wordpress/ 2.FCL:https://github.com/flexible-collision-library/fcl 3.ODE:http://www.ode.org/ 4.PQP:http://gamma.cs.unc.edu/SSV/

    2023年04月08日
    浏览(43)
  • 智能交通系统-yolov5+deepsort车辆跟踪、计数、测速、碰撞检测、违规驶入检测(算法-毕业设计)

    本项目效果展示视频:https://www.bilibili.com/video/BV1E3411G7cP/ 1、本项目通过yolov8/yolov7/yolov5 5.0和deepsort实现了一个多功能智能交通监控系统,可为一些同学的课设、大作业等提供参考。分别实现了不同车辆的跟踪,统计不同车型“上行”和“下行”的数量,实时检测车辆速度,检

    2023年04月09日
    浏览(51)
  • yolov8/yolov5-车辆测距+前车碰撞预警(追尾预警)+车辆检测识别+车辆跟踪测速(算法-毕业设计)

    本项目效果展示视频: https://www.bilibili.com/video/BV14d4y177vE/?spm_id_from=333.999.0.0vd_source=8c532ded7c7c9041f04e35940d11fdae 1、本项目通过yolov8/yolov7/yolov5和deepsort实现了一个自动驾驶领域的追尾前车碰撞预警系统,可为一些同学的课设、大作业等提供参考。分别实现了自行车、汽车、摩托车

    2024年02月06日
    浏览(59)
  • 空间划分算法优化碰撞检测研究(网格划分、四叉树\八叉树、层次包围盒树BVH)Unity C#实现

    目录 前言 一、Demo说明 二、暴力法  三、网格划分 实测 分析 四、四叉树 四叉树的构建细节  实测 五、松散四叉树 实测 八叉树 六、层次包围盒树(BVH) 包围盒 AABB树 AABB树构建细节 实测 总结   碰撞检测是一个非常经典的问题。虽然现在我们都有物理引擎提供的便捷接口

    2023年04月11日
    浏览(84)
  • yolov8/yolov7/yolov5-车辆测距+前车碰撞预警(追尾预警)+车辆检测识别+车辆跟踪测速(算法-毕业设计)

    本项目效果展示视频: https://www.bilibili.com/video/BV14d4y177vE/?spm_id_from=333.999.0.0vd_source=8c532ded7c7c9041f04e35940d11fdae 1、本项目通过yolov8/yolov7/yolov5和deepsort实现了一个自动驾驶领域的追尾前车碰撞预警系统,可为一些同学的课设、大作业等提供参考。分别实现了自行车、汽车、摩托车

    2024年02月04日
    浏览(65)
  • 【计算几何】凸多面体重叠判断算法:GJK 算法详解 & C++代码实现二维情形的凸多边形重叠判断

    GJK 算法是由 Gilbert,Johnson,Keerthi 三位前辈发明的, 用来计算两个凸多面体之间的碰撞检测 ,以及最近距离。 GJK 算法可以在 O ( M + N ) O(M+N) O ( M + N ) 的时间复杂度内,检测出碰撞,算法在每次迭代的过程中,都会优先选择靠近原点的方向,因此收敛速度会很快。算法的证明

    2024年02月08日
    浏览(67)
  • yolov5车道线检测+测距(碰撞检测)

    相关链接 1. 基于yolov5的车道线检测及安卓部署 2. YOLOv5#

    2024年02月08日
    浏览(42)
  • 3D 碰撞检测

    推荐:使用 NSDT场景编辑器快速搭建3D应用场景 与 2D 碰撞检测一样, 轴对齐边界框  (AABB) 是确定两个游戏实体是否重叠的最快算法。这包括将游戏实体包装在一个非旋转(因此轴对齐)的框中,并检查这些框在 3D 坐标空间中的位置以查看它们是否重叠。 由于性能原因,

    2024年02月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包