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

3D引擎开发:求射线到指定点的最近点的高效代码实现方法

3D射线与给定点最近点的高效计算方法

核心数学原理

射线的参数方程为 R(t) = p + t*d(其中 p 是射线原点,d 是射线方向向量,t ≥ 0)。要找到射线上距离点 c 最近的点,本质是计算向量 pc = c - p 在方向 d 上的投影,再根据投影结果确定合法的 t 值:

  1. 计算向量 pc 与 d 的点积:dot_pc_d = (c - p) · d
  2. 计算方向向量 d 的自点积:dot_d_d = d · d
  3. 投影参数 t = dot_pc_d / dot_d_d
  4. 由于射线仅包含 t ≥ 0 的部分,若 t ≤ 0,最近点即为射线原点 p;否则为 p + t*d

高效代码实现

以下是通用的3D向量运算实现,针对光照模块的高频调用做了精度和效率优化:

#include <algorithm> // 用于std::max

struct Vec3 {
    float x, y, z;

    Vec3 operator-(const Vec3& other) const {
        return {x - other.x, y - other.y, z - other.z};
    }

    Vec3 operator+(const Vec3& other) const {
        return {x + other.x, y + other.y, z + other.z};
    }

    Vec3 operator*(float scalar) const {
        return {x * scalar, y * scalar, z * scalar};
    }

    float dot(const Vec3& other) const {
        return x * other.x + y * other.y + z * other.z;
    }
};

Vec3 closestPointOnRay(Vec3 rayOrigin, Vec3 rayDir, Vec3 targetPoint) {
    Vec3 pc = targetPoint - rayOrigin;
    float dotPCDir = pc.dot(rayDir);
    float dotDirDir = rayDir.dot(rayDir);

    // 处理方向向量为零的极端情况(射线退化为点)
    if (dotDirDir < 1e-8f) {
        return rayOrigin;
    }

    float t = dotPCDir / dotDirDir;
    // 限制t为非负值,符合射线的定义
    t = std::max(0.0f, t);

    return rayOrigin + rayDir * t;
}

性能优化建议

  • 归一化方向向量:如果射线会被多次使用,提前将 rayDir 归一化为单位向量(模长为1)。此时 dotDirDir = 1,可以直接省略除法操作,仅需计算 t = dotPCDir,大幅提升计算速度。
  • 精度控制:使用极小的epsilon值(如 1e-8f)判断方向向量是否为零,避免浮点数除法的异常。
  • 批量处理:若光照模块需要同时计算大量射线的最近点,可考虑将向量运算向量化(利用SIMD指令),进一步优化性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:15:13