表达方法

AABB内的点满足不等式:\(\begin{align}x_{min}\leq x\leq x_{max}\\y_{min}\leq y\leq y_{max}\\z_{min}\leq z\leq z_{max}\end{align}\)

顶点:\(\begin{align} p_{min} = \begin{bmatrix} x_{min} & y_{min} & z_{min} \end{bmatrix}\\ p_{max} = \begin{bmatrix} x_{max} & y_{max} & z_{max} \end{bmatrix} \end{align}\)

中心点:\(c=(p_{min}+p_{max})/2\)

尺寸向量:\(s=p_{max}-p_{min}\),尺寸向量为\(p_{min}\)指向\(p_{max}\)的向量,包含矩形边界框的长、宽、高

半径向量:\(r=p_{max}-c=s/2\),半径向量为中心指向\(p_{max}\)的向量

明确定义一个AABB只需要\(p_{min}\)\(p_{max}\)\(c\)\(s\)\(r\)这5个向量中的两个(\(s\)\(r\)不能配对,其它任意两个都可以配对)

算法实现

计算AABB

struct Vec3 {
    float x, y, z;
};

struct AABB {
    Vec3 min;
    Vec3 max;
};

AABB ComputeAABB(const std::vector<Vec3>& vertices) {
    Vec3 min = vertices[0];
    Vec3 max = vertices[0];

    for (const auto& v : vertices) {
        if (v.x < min.x) min.x = v.x;
        if (v.y < min.y) min.y = v.y;
        if (v.z < min.z) min.z = v.z;

        if (v.x > max.x) max.x = v.x;
        if (v.y > max.y) max.y = v.y;
        if (v.z > max.z) max.z = v.z;
    }

    return { min, max };
}

判断点与AABB是否相交

bool PointInsideAABB(const Vec3& point, const AABB& box) {
    return (point.x >= box.min.x && point.x <= box.max.x) &&
           (point.y >= box.min.y && point.y <= box.max.y) &&
           (point.z >= box.min.z && point.z <= box.max.z);
}

判断两个AABB是否相交

bool AABBOverlap(const AABB& a, const AABB& b) {
    return (a.min.x <= b.max.x && a.max.x >= b.min.x) &&
           (a.min.y <= b.max.y && a.max.y >= b.min.y) &&
           (a.min.z <= b.max.z && a.max.z >= b.min.z);
}

判断射线与AABB是否相交

射线:\(Ray(t)=origin+t\times dir(t\geq0)\)

由射线表达式可以得到\(t=\frac{origin-Ray(t)}{dir}\),其中\(Ray(t)\)可由\(p_{min}\)\(p_{max}\)获得,使用\(Slab Method\)算法求出每个轴所对应的相交区间\([t_{min},t_{max}]\), 射线与AABB相交的条件是:所有三个轴的相交区间有公共部分。

struct Vec3 {
    float x, y, z;
    float& operator[](int i) { return *((&x) + i); }
    const float& operator[](int i) const { return *((&x) + i); }

    Vec3 operator+(const Vec3& rhs) const {
        return { x + rhs.x, y + rhs.y, z + rhs.z };
    }
    Vec3 operator*(float s) const {
        return { x * s, y * s, z * s };
    }
};

bool RayIntersectsAABB(
    const Vec3& origin,
    const Vec3& dir,
    const Vec3& boxMin,
    const Vec3& boxMax,
    Vec3& enterPoint,
    Vec3& exitPoint)
{
    float tmin = -std::numeric_limits<float>::infinity();
    float tmax =  std::numeric_limits<float>::infinity();

    for (int i = 0; i < 3; ++i) {
        if (dir[i] == 0.0f) {
            if (origin[i] < boxMin[i] || origin[i] > boxMax[i])
                return false; // 平行且在外面
        } else {
            float t1 = (boxMin[i] - origin[i]) / dir[i];
            float t2 = (boxMax[i] - origin[i]) / dir[i];
            if (t1 > t2) std::swap(t1, t2);
            tmin = std::max(tmin, t1);
            tmax = std::min(tmax, t2);
            if (tmin > tmax) return false;
            if (tmax < 0) return false;
        }
    }

    enterPoint = origin + dir * tmin;
    exitPoint  = origin + dir * tmax;
    return true;
}
posted on 2025-08-02 09:07  WoBok  阅读(64)  评论(0)    收藏  举报