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

OpenGL 3D物体选择:3D国际象棋游戏棋子点击检测实现方案

射线与轴对齐包围盒(AABB)相交检测实现方案

国际象棋棋子仅存在平移操作无旋转,使用AABB作为碰撞盒完全满足需求,精度匹配棋子外形,性能也高于球体碰撞检测。

步骤1:为棋子类添加包围盒属性

在Figure类中预定义两个属性存储本地坐标系下的包围盒边界:

  • localMinBounds:棋子本地空间的最小x/y/z坐标点
  • localMaxBounds:棋子本地空间的最大x/y/z坐标点
    可根据你的模型实际尺寸调整数值,例如标准棋子可设置为(-0.2, 0, -0.2)和(0.2, 1, 0.2)。

步骤2:实现射线-AABB相交检测函数

采用经典的Slabs算法实现相交判断,逻辑为分别计算射线在三个坐标轴方向进入、离开包围盒的阈值,若三个轴的有效区间存在重叠则判定相交:

private boolean intersect(Vector3f rayStart, Vector3f rayDir, Vector3f boxMin, Vector3f boxMax) {
    // 计算X轴方向的进出阈值
    float tMinX = (boxMin.x - rayStart.x) / rayDir.x;
    float tMaxX = (boxMax.x - rayStart.x) / rayDir.x;
    if (tMinX > tMaxX) {
        float temp = tMinX;
        tMinX = tMaxX;
        tMaxX = temp;
    }

    // 计算Y轴方向的进出阈值
    float tMinY = (boxMin.y - rayStart.y) / rayDir.y;
    float tMaxY = (boxMax.y - rayStart.y) / rayDir.y;
    if (tMinY > tMaxY) {
        float temp = tMinY;
        tMinY = tMaxY;
        tMaxY = temp;
    }

    // X/Y轴区间无重叠直接返回不相交
    if ((tMinX > tMaxY) || (tMinY > tMaxX))
        return false;

    // 合并前两个轴的有效区间
    if (tMinY > tMinX)
        tMinX = tMinY;
    if (tMaxY < tMaxX)
        tMaxX = tMaxY;

    // 计算Z轴方向的进出阈值
    float tMinZ = (boxMin.z - rayStart.z) / rayDir.z;
    float tMaxZ = (boxMax.z - rayStart.z) / rayDir.z;
    if (tMinZ > tMaxZ) {
        float temp = tMinZ;
        tMinZ = tMaxZ;
        tMaxZ = temp;
    }

    // 三个轴区间无重叠直接返回不相交
    if ((tMinX > tMaxZ) || (tMinZ > tMaxX))
        return false;

    // 确认相交点在射线正方向上
    return tMaxZ > 0;
}

步骤3:整合到现有业务逻辑

修改你的update方法,注意鼠标射线需要先归一化避免计算误差:

public void update(Vector3f mouseRay, Camera camera, Figure figure){
    Vector3f start = camera.getPosition();
    // 归一化射线方向
    Vector3f rayDir = new Vector3f(mouseRay);
    rayDir.normalise();
    Vector3f figurePos = figure.getPosition();
    // 转换为世界坐标系下的包围盒
    Vector3f worldMin = new Vector3f(figure.getLocalMinBounds()).add(figurePos);
    Vector3f worldMax = new Vector3f(figure.getLocalMaxBounds()).add(figurePos);
    if(intersect(start, rayDir, worldMin, worldMax)){
       selectFigure();
    }
}

可选优化方案

  • 国际象棋所有棋子都落在棋盘平面上,可先计算射线和棋盘平面的交点,直接定位到对应坐标的格子,仅检测该格子上存在的棋子即可,无需遍历所有32个棋子,性能提升非常明显。
  • 如果后续有旋转棋子的需求,可将AABB替换为有向包围盒(OBB),只需额外把射线转换到棋子的本地坐标系,再复用上述AABB算法检测即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 20:15:02