光线求交计算中如何选择合适的Epsilon值?
光线追踪中Epsilon值的选择与三角形漏检问题解决
Epsilon值的核心选择原则
- 绝对不要用固定死的极小值一刀切,优先根据场景尺度和物体尺寸动态调整:
- 单精度浮点场景下,基础Epsilon可以从
1e-6f开始测试;针对极小尺寸的三角形,可缩小到1e-8f,但注意不要过小引发新的精度问题。 - 优先使用相对Epsilon:比如结合光线交点的
t值(距离)计算,epsilon = t * 1e-6f——距离越远,浮点误差越大,需要的容差也越大。
- 单精度浮点场景下,基础Epsilon可以从
- 所有浮点数比较必须用绝对值小于Epsilon替代直接的
==、<、>硬判断,这是解决漏检的核心。
你的代码中的关键问题
- 硬浮点数比较:
pointInTriangle和intersectRayWithPlane中直接用==判断平面方程结果,浮点运算的微小误差会直接导致漏检,尤其是小三角形。 - 面积法的稳定性问题:面积法依赖多次除法和长度计算,会放大浮点误差,对小三角形极不友好。
- 冗余的平面检查:
intersectRayWithPlane中计算出t后再次检查点是否在平面上完全多余——t本身就是通过平面方程推导的,这一步反而会引入额外误差。
修改后的代码实现
首先定义可调整的Epsilon常量:
const float EPSILON = 1e-6f; // 针对常规场景,小物体可改为1e-8f
改进的三角形内点判断(重心坐标法,更稳定)
bool pointInTriangle(const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& n, const glm::vec3& p) { Plane plane = trianglePlane(v0,v1,v2); // 用Epsilon判断点是否在平面容差范围内 if (std::abs(glm::dot(plane.normal, p) - plane.D) > EPSILON) return false; // 重心坐标法计算,避免面积法的除法误差 glm::vec3 v0v1 = v1 - v0; glm::vec3 v0v2 = v2 - v0; glm::vec3 v0p = p - v0; float dot00 = glm::dot(v0v1, v0v1); float dot01 = glm::dot(v0v1, v0v2); float dot02 = glm::dot(v0v1, v0p); float dot11 = glm::dot(v0v2, v0v2); float dot12 = glm::dot(v0v2, v0p); float denom = dot00 * dot11 - dot01 * dot01; // 处理退化三角形(面积接近0) if (std::abs(denom) < EPSILON) return false; float invDenom = 1.0f / denom; float u = (dot11 * dot02 - dot01 * dot12) * invDenom; float v = (dot00 * dot12 - dot01 * dot02) * invDenom; // 用Epsilon容差判断重心坐标是否在三角形范围内 return (u >= -EPSILON) && (v >= -EPSILON) && (u + v <= 1.0f + EPSILON); }
改进的光线-平面相交检测
bool intersectRayWithPlane(const Plane& plane, Ray& ray) { float denom = glm::dot(plane.normal, ray.direction); // 避免除以0(光线与平面平行或重合) if (std::abs(denom) < EPSILON) return false; float t = (plane.D - glm::dot(ray.origin, plane.normal)) / denom; // 用Epsilon过滤t的极小值(避免光线原点在平面上的误判),同时保留最近交点 if (t > EPSILON && t < ray.t) { ray.t = t; return true; } return false; }
额外优化建议
- 对于极小三角形,可在计算时临时切换为
double精度,减少浮点误差。 - 动态调整Epsilon:比如在光线相交后,根据
t值(交点到原点的距离)计算当前需要的容差,dynamic_epsilon = t * 1e-6f,适配不同距离的误差。
内容的提问来源于stack exchange,提问作者Cristian Cutitei
相关产品推荐
相关产品推荐

