/** * @file ray_intersect.h * @brief 射线求交工具集 * * 射线与基本几何图元(三角形、AABB、球体、平面、网格)的求交函数。 * 包含 Möller-Trumbore 算法、slab 方法、解析求交等。 * * @ingroup collision */ #pragma once #include "vde/core/point.h" #include "vde/core/line.h" #include "vde/core/triangle.h" #include "vde/core/aabb.h" #include #include namespace vde::collision { using core::Point3D; using core::Vector3D; using core::Triangle3D; using core::Ray3Dd; using core::AABB3D; /** * @brief 射线-三角形求交结果 */ struct RayTriResult { double t; /**< 沿射线的参数:hit_point = origin + t * dir */ double u, v; /**< 三角形重心坐标:hit_point = (1−u−v)*v0 + u*v1 + v*v2 */ Point3D point; /**< 命中点的世界坐标 */ }; /** * @brief 射线-三角形求交(Möller-Trumbore 算法) * * 标准 MT 算法,直接计算重心坐标 u, v 和参数 t。 * 不预先计算平面方程,一步到位检测。 * * 算法: * 1. 计算两个边向量 e1 = v1−v0, e2 = v2−v0 * 2. 计算 pvec = dir × e2, det = dot(e1, pvec) * 3. 若 |det| < ε → 射线平行于三角形(无命中) * 4. 计算 tvec = origin−v0, u, v, t * 5. 验证 u≥0, v≥0, u+v≤1, t>0 → 命中 * * 复杂度 O(1)。 * * @param origin 射线起点 * @param dir 射线方向(需归一化以获得正确 t 值) * @param tri 三角形 * @return 命中返回 RayTriResult;未命中返回空 * * @code{.cpp} * if (auto hit = ray_triangle_intersect(origin, dir, tri)) { * std::cout << "Hit at t=" << hit->t * << " barycentric=(" << hit->u << "," << hit->v << ")\n"; * } * @endcode * * @see ray_mesh_intersect */ std::optional ray_triangle_intersect( const Point3D& origin, const Vector3D& dir, const Triangle3D& tri); /** * @brief 射线-三角形求交(Ray3Dd 重载) * * @param ray 射线 * @param tri 三角形 * @return 命中返回 RayTriResult;未命中返回空 * * @see ray_triangle_intersect(origin, dir, tri) */ inline std::optional ray_triangle_intersect( const Ray3Dd& ray, const Triangle3D& tri) { return ray_triangle_intersect(ray.origin(), ray.direction(), tri); } /** * @brief 射线-AABB 求交(slab 方法) * * 分别检测射线与三个坐标轴方向 slab(平板块)的交点, * 取最大 t_min 和最小 t_max。若 t_min ≤ t_max 且 t_max ≥ 0,则命中。 * * 复杂度 O(1)。 * * @param ray 射线 * @param box 轴对齐包围盒 * @param tmin_out [输出] 进入包围盒的参数 t * @param tmax_out [输出] 离开包围盒的参数 t * @return 命中返回 true * * @note 常用于 BVH 遍历节点的快速 rejection test * * @see ray_triangle_intersect */ bool ray_aabb_intersect(const Ray3Dd& ray, const AABB3D& box, double& tmin_out, double& tmax_out); /** * @brief 射线-球体求交结果 */ struct RaySphereResult { double t; /**< 命中参数(通常取较小的 t) */ Point3D point; /**< 命中点世界坐标 */ }; /** * @brief 射线-球体求交(解析法) * * 解二次方程 |origin + t*dir − center|² = r²。 * 通过判别式 Δ = b² − 4ac 判断: * - Δ < 0 → 无交点 * - Δ = 0 → 切点(一个交点) * - Δ > 0 → 两个交点(返回较近的) * * 复杂度 O(1)。 * * @param origin 射线起点 * @param dir 射线方向 * @param center 球心 * @param radius 球半径 * @return 命中返回 RaySphereResult(最近交点);未命中返回空 * * @see ray_sphere_intersect(ray, center, radius) */ std::optional ray_sphere_intersect( const Point3D& origin, const Vector3D& dir, const Point3D& center, double radius); /** * @brief 射线-球体求交(Ray3Dd 重载) * * @param ray 射线 * @param center 球心 * @param radius 球半径 * @return 命中返回 RaySphereResult;未命中返回空 */ inline std::optional ray_sphere_intersect( const Ray3Dd& ray, const Point3D& center, double radius) { return ray_sphere_intersect(ray.origin(), ray.direction(), center, radius); } /** * @brief 射线-平面求交 * * 解 t = dot(plane_point − origin, plane_normal) / dot(dir, plane_normal)。 * 若分母 ≈ 0(射线平行于平面)→ 无交点。 * * @param origin 射线起点 * @param dir 射线方向 * @param plane_point 平面上一点 * @param plane_normal 平面法线(需归一化以获得正确 t) * @return 命中返回参数 t;未命中(平行或反向)返回空 */ std::optional ray_plane_intersect( const Point3D& origin, const Vector3D& dir, const Point3D& plane_point, const Vector3D& plane_normal); /** * @brief 射线-平面求交(Ray3Dd 重载) * * @param ray 射线 * @param plane_point 平面上一点 * @param plane_normal 平面法线 * @return 命中返回参数 t;未命中返回空 */ inline std::optional ray_plane_intersect( const Ray3Dd& ray, const Point3D& plane_point, const Vector3D& plane_normal) { return ray_plane_intersect(ray.origin(), ray.direction(), plane_point, plane_normal); } /** * @brief 射线-网格求交(暴力遍历) * * 遍历所有三角形,对每个三角形调用 ray_triangle_intersect, * 跟踪最小 t 值返回最近命中。 * * 复杂度 O(n),n 为三角形数量。 * * @param origin 射线起点 * @param dir 射线方向 * @param triangles 三角形列表 * @return 最近命中结果;无命中返回空 * * @note 对于大型网格建议配合 BVH 使用: * @code{.cpp} * BVH bvh; * bvh.build(triangles); * auto hit = bvh.query_ray_nearest(ray); // O(log n) * @endcode * * @see ray_tri_intersect.h, query_ray_nearest (BVH) */ std::optional ray_mesh_intersect( const Point3D& origin, const Vector3D& dir, const std::vector& triangles); /** * @brief 射线-网格求交(Ray3Dd 重载) * * @param ray 射线 * @param triangles 三角形列表 * @return 最近命中结果;无命中返回空 */ inline std::optional ray_mesh_intersect( const Ray3Dd& ray, const std::vector& triangles) { return ray_mesh_intersect(ray.origin(), ray.direction(), triangles); } } // namespace vde::collision