返回

探索碰撞检测的奥秘:GJK 算法详解

见解分享

碰撞检测:GJK 算法——2D

引言

碰撞检测是计算机图形学和游戏开发中的基石,它使虚拟世界中的物体能够逼真地相互作用。在本文中,我们将深入探讨 GJK(Gilbert-Johnson-Keerthi)算法,这是一种广泛用于狭义相交检测的强大算法。我们将重点关注 GJK 算法的二维版本,并通过 Python 实现和实际示例来加深理解。

GJK 算法简介

GJK 算法是一种几何算法,用于确定两个凸几何体的相交情况。它通过迭代方式逐步逼近相交点,最终收敛到最接近点对。该算法利用闵可夫斯基和点差的概念,在凸几何体之间构建闵可夫斯基和集,并寻找该和集中的支持点。

GJK 算法步骤

GJK 算法的基本步骤如下:

  1. 初始化两个凸几何体的支持点集合。
  2. 计算闵可夫斯基和集的支持点。
  3. 如果支持点在原点内,则说明两个几何体相交。
  4. 否则,将新的支持点添加到支持点集合中,并返回步骤 2。
  5. 重复步骤 2-4,直到达到最大迭代次数或收敛到最近点对。

Python 实现

以下是用 Python 实现的二维 GJK 算法:

import math

def gjk_2d(geometry1, geometry2, max_iterations=100):
    """
    GJK 算法的二维实现。

    参数:
    geometry1: 凸几何体 1
    geometry2: 凸几何体 2
    max_iterations: 最大迭代次数

    返回值:
    True 如果几何体相交,否则为 False
    """

    # 初始化支持点集合
    support_points1 = [geometry1.support_point(direction) for direction in [0, math.pi/2]]
    support_points2 = [geometry2.support_point(direction) for direction in [0, math.pi/2]]

    for _ in range(max_iterations):
        # 计算闵可夫斯基和集的支持点
        support_point = support_points1[0] - support_points2[0]

        # 检查支持点是否在原点内
        if support_point.dot(support_point) <= 1e-6:
            return True

        # 否则,更新支持点集合
        direction = support_point.normalized()
        support_points1.append(geometry1.support_point(direction))
        support_points2.append(geometry2.support_point(-direction))

    return False

示例

为了展示 GJK 算法的实际应用,让我们考虑以下两个示例:

示例 1:两个相交的圆

from geometry import Circle

circle1 = Circle(radius=1, center=(0, 0))
circle2 = Circle(radius=1, center=(1, 0))

if gjk_2d(circle1, circle2):
    print("圆 1 和圆 2 相交")
else:
    print("圆 1 和圆 2 不相交")

输出:

 1 和圆 2 相交

示例 2:不相交的矩形和圆

from geometry import Rectangle, Circle

rectangle = Rectangle(width=2, height=1, center=(0, 0))
circle = Circle(radius=1, center=(2, 0))

if gjk_2d(rectangle, circle):
    print("矩形和圆相交")
else:
    print("矩形和圆不相交")

输出:

矩形和圆不相交