C ++-处理几何插值中的浮点错误

时间:2019-06-05 17:05:35

标签: c++ floating-point

问题

我正在编写光线追踪器,作为计算机图形学中特定机器学习方法的用例。

我的问题是,当我尝试找到射线与表面之间的交点时,结果不准确。

基本上,如果我将光线从 O点散射到位于(x,y,z)的表面,其中z = 81,则我希望解决方案是类似 S =(x,y,81)
问题是:我得到了类似(x,y,81.000000005)的解决方案。
这当然是一个问题,因为后续操作取决于该解决方案,并且它必须是准确的解决方案。

问题

我的问题是:计算机图形学的人如何处理这个问题?我试图将变量从float更改为double,但这不能解决问题。

替代解决方案

我尝试使用功能std::round()。这仅在特定情况下有帮助,但在确切的解决方案包含一个或多个有效数字时则无济于事。
std::ceil()std::floor()相同。

编辑

这是我计算与平行于 xz 轴的表面(矩形)的交点的方式。
首先,我计算射线的原点与曲面之间的距离t。如果我的射线在那个特定方向上没有撞击到表面,则t返回为0。

class Rectangle_xy: public Hitable {
public:
    float x1, x2, y1, y2, z;
    ... 

    float intersect(const Ray &r) const { // returns distance, 0 if no hit
        float t = (y - r.o.y) / r.d.y;      // ray.y = t* dir.y
        const float& x = r.o.x + r.d.x * t;
        const float& z = r.o.z + r.d.z * t;
        if (x < x1 || x > x2 || z < z1 || z > z2 || t < 0) {
            t = 0;
            return 0;
        } else {
            return t;
        }
    ....
    }

具体来说,给定一个Ray和列表中一个对象的id(我要命中):

inline Vec hittingPoint(const Ray &r, int &id) {
    float t;                             // distance to intersection
    if (!intersect(r, t, id))
        return Vec();
    const Vec& x = r.o + r.d * t;// ray intersection point (t calculated in intersect())
    return x ;
}

如果我与某个对象相交,则上一段代码中的函数intersect()将检查列表rect中的每个Rectangle:

inline bool intersect(const Ray &r, float &t, int &id) {
    const float& n = NUMBER_OBJ; //Divide allocation of byte of the whole scene, by allocation in byte of one single element
    float d;
    float inf = t = 1e20;
    for (int i = 0; i < n; i++) {
        if ((d = rect[i]->intersect(r)) && d < t) { // Distance of hit point
            t = d;
            id = i;
        }
    }

    // Return the closest intersection, as a bool
    return t < inf;
}

然后使用3D空间中的线和曲面之间的几何插值获得坐标:

Vec& x = r.o + r.d * t;

其中:
r.o:代表射线原点。它被定义为r.o:Vec(float a, float b, float c
r.d:这是射线的方向。如前所述:r.d:Vec(float d, float e, float f)。 tfloat代表物体与原点之间的距离。

1 个答案:

答案 0 :(得分:0)

您可以考虑使用std::numeric_limits<T>::epsilon进行浮动/双重比较。并查看结果是否在+-ε区域。

一种替代方法是不向点发出光线跟踪。也许只是在其中放置相对较小的盒子或球体即可。