You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GJK算法生成相反单形点致叉乘为零的物理引擎碰撞检测问题

GJK碰撞检测零向量方向问题修复方案

问题根因

  • 初始方向选取逻辑存在边界缺陷:当前初始方向基于质心差生成垂直向量,当两个立方体仅沿x轴偏移时,初始方向落到y轴方向,刚好取到闵可夫斯基差的两个反向顶点。
  • 线段单形的方向计算未做零向量校验:当ab与ao共线时,ab.cross(ao).cross(ab)会返回零向量,后续点积校验逻辑直接失效。

修复方案

1. 新增线段单形零向量兜底逻辑

修改lineSimplex函数,检测到生成的新方向为零向量时,自动替换为垂直于ab的非零向量:

def lineSimplex(args):
    a, b = args[0]
    ab = b - a
    ao = -a
    if ab.dot(ao) > 0:
        new_dir = ab.cross(ao).cross(ab)
        if new_dir == Vector3.zero():
            # 共线时取任意垂直于ab的非零向量
            if abs(ab.x) < abs(ab.y) and abs(ab.x) < abs(ab.z):
                new_dir = Vector3(1, 0, 0).cross(ab)
            elif abs(ab.y) < abs(ab.z):
                new_dir = Vector3(0, 1, 0).cross(ab)
            else:
                new_dir = Vector3(0, 0, 1).cross(ab)
        args[1] = new_dir
    else:
        args[0] = [a]
        args[1] = ao

2. 优化初始方向选取逻辑

优先使用两个形状的质心差作为初始方向,大幅降低边界场景出现概率:

def gjk(a, b):
    ab = a.pos - b.pos
    # 优先用质心差作为初始方向,仅质心重合时再生成垂直方向
    if ab == Vector3.zero():
        c = Vector3(ab.z, ab.z, -ab.x - ab.y)
        if c == Vector3.zero():
            c = Vector3(-ab.y - ab.z, ab.x, ab.x)
        initial_dir = ab.cross(c)
    else:
        initial_dir = ab
    support = supportPoint(a, b, initial_dir)
    points = [support]
    direction = -support
    # 后续循环逻辑保持不变
    while True:
        support = supportPoint(a, b, direction)
        if support.dot(direction) <= 0:
            return None
        points.insert(0, support)
        args = [points, direction]
        if nextSimplex(args):
            return args[0]
        points, direction = args

3. 可选全局校验兜底

可以在每次更新direction之后、查询新支持点之前,统一判断方向是否为零向量,若为零则替换为随机非零单位向量,彻底覆盖所有边界场景。

修改完成后测试x轴偏移为-1、0、1的场景,不会再出现零向量导致的校验失效问题,碰撞检测可以正常返回结果。

内容的提问来源于stack exchange,提问作者Ray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 21:12:02