光线追踪球体反射bug

时间:2017-12-17 19:16:26

标签: c++ opengl raytracing

我正在尝试实现光线追踪算法,我在计算球形物体的反射光线时遇到了一些麻烦。似乎 对于某些特定光线,反射光线刚好穿过并与跟踪光线共线。 贝娄是我记录射线 - 球体交叉的方式:

bool Sphere::intersectLocal(const ray & r, isect & i) const {
    Vec3d P = r.getPosition();
    Vec3d D = r.getDirection();
    //D.normalize();
    double a = dot(D, D);
    double b = 2 * dot(P, D);
    double c = dot(P, P) - 1;
    double delta = b * b - 4 * a * c;
    if (delta < 0)
        return false;
    if (delta == 0) {
        double t = -b / 2 * a;
        Vec3d Q = P + t * D;
        Vec3d N = Q;
        N.normalize();
        i.setT(t);
        i.setN(N);
        i.setObject(this);
        return true;
    }
    if (delta > 0) {
        double t1 = (-b - sqrt(delta)) / 2 * a;
        double t2 = (-b + sqrt(delta)) / 2 * a;
        double t;
        if (t1 > 0) t = t1;
        else if (t2 > 0) t = t2;
        else return false;
        Vec3d N = P + t * D;
        N.normalize();
        i.setT(t);
        i.setN(N);
        i.setObject(this);
        return true;
    }
    return false;
}

这就是我计算每个交叉点的反射光线的方法:

isect i;
if (scene - > intersect(r, i)) {
    // An intersection occured!  
    const Material & m = i.getMaterial();
    double t = i.t;
    Vec3d N = i.N;
    Vec3d I = m.shade(scene, r, i); //local illumination
    if (!m.kr(i).iszero() && depth >= 0) {
        // compute reflection direction
        Vec3d raydir = r.getDirection();
        Vec3d refldir = 2 * dot(-raydir, i.N) * i.N + raydir;
        refldir.normalize();
        ray reflectionRay = ray(r.at(i.t), refldir, ray::RayType::REFLECTION);
        Vec3d reflection = traceRay(reflectionRay, thresh, depth - 1);
        Vec3d R = reflection;
        I += R;
    }
    return I;
} else {
    // No intersection.  This ray travels to infinity, so we color
    // it according to the background color, which in this (simple) case
    // is just black.
    return Vec3d(0.0, 0.0, 0.0);
}

上面的代码似乎对于光线相交的球体上的大多数点都可以正常工作,但对于其他点,它并不像我期望的那样反映

enter image description here

enter image description here

enter image description here

2 个答案:

答案 0 :(得分:0)

如果我看到正确的话,这会使正常的脸朝向与射线相同的方向。所以ray==normal==reflected_ray没有任何反映。

Vec3d Q = P + t * D;
Vec3d N = Q;

答案 1 :(得分:0)

关于浮点算术中的错误及其处理方法:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

在这里您可以找到如何比较浮点数。搜索relative absolute compare floating可能会发现更多信息。

https://floating-point-gui.de/errors/comparison/

这是我在C#中的代码的摘录。几乎从不使用绝对比较。

public static bool IsAlmostRelativeEquals(this double d1, double d2, double epsilon)
{
    double absDiff = Math.Abs(d1 - d2);

    if (double.IsPositiveInfinity(absDiff))
        return false;

    if (absDiff < epsilon)
        return true;

    double absMax = Math.Max(Math.Abs(d1), Math.Abs(d2));

    return Math.Abs(d1 - d2) <= epsilon * absMax;
}

public static bool IsAlmostZero(this double d, double epsilon)
{
    double abs = Math.Abs(d);

    if (double.IsPositiveInfinity(abs))
        return false;

    return abs < epsilon;
}