光线追踪 - 折射错误

6

我正在编写一个光线追踪器。到目前为止,我已经实现了漫反射、Blinn光照和反射。但是我的折射出了问题,我不知道怎么回事。希望有人能帮助我。

enter image description here

我有一个大的红色漫反射+Blinn球和一个小的折射率为n=1.5的球。

小球的效果非常糟糕。

相关代码:

ReflectiveSurface::ReflectiveSurface(const Color& _n, const Color& _k) : 
F0(Color(((_n - 1)*(_n - 1) + _k * _k) / ((_n + 1)*(_n + 1) + _k * _k))) {}

Color ReflectiveSurface::F(const Point& N, const Point& V) const {
    float cosa = fabs(N * V);
    return F0 + (F0 * (-1) + 1) * pow(1 - cosa, 5);
}

Color ReflectiveSurface::getColor(const Incidence& incidence, const Scene& scene, int traceDepth) const {
    Point reflectedDir = reflect(incidence.normal, incidence.direction);
    Ray ray = Ray(incidence.point + reflectedDir * epsilon, reflectedDir);
    return F(incidence.normal, incidence.direction) * scene.rayTrace(ray, traceDepth + 1);
}

Point ReflectiveSurface::reflect(const Point& N, const Point& V) const {
    return V - N * (2 * (N * V));
}

bool RefractiveSurface::refractionDir(Point& T, Point& N, const Point& V) const {
    float cosa = -(N * V), cn = n;
    if (cosa < 0) { cosa = -cosa; N = N * (-1); cn = 1 / n; }
    float disc = 1 - (1 - cosa * cosa) / cn / cn;
    if (disc < 0) return false;
    T = V / cn + N * (cosa / cn - sqrt(disc));
    return true;
}

RefractiveSurface::RefractiveSurface(float _n, const Color& _k) : ReflectiveSurface(Color(1, 1, 1) * _n, _k) {}

Surface* RefractiveSurface::copy() { return new RefractiveSurface(*this); }

Color RefractiveSurface::getColor(const Incidence& incidence, const Scene& scene, int traceDepth) const {
    Incidence I = Incidence(incidence);
    Color reflectedColor, refractedColor;
    Point direction = reflect(I.normal, I.direction);
    Ray reflectedRay = Ray(I.point + direction * epsilon, direction);
    if (refractionDir(direction, I.normal, I.direction)) {
        Ray refractedRay = Ray(I.point + direction * epsilon, direction);
        Color colorF = F(I.normal, I.direction);
        reflectedColor = colorF * scene.rayTrace(reflectedRay, traceDepth + 1);
        refractedColor = (Color(1, 1, 1) - colorF) * scene.rayTrace(refractedRay, traceDepth + 1);
    }
    else {
        reflectedColor = scene.rayTrace(reflectedRay, traceDepth + 1);
    }
    return reflectedColor + refractedColor;
}

代码分散在各处,因为这是一份作业,不允许包含额外的头文件,并且必须在一个 cpp 文件中发送。所以我不得不将每个类分开成前向声明、声明和实现放在一个文件中。这让我感到非常恶心,但我尽可能保持了代码的整洁。由于代码很多,所以我只包含了我认为最相关的部分。ReflectiveSurface 是 RefractiveSurface 的父类。N 是曲面法线,V 是该法线上的光线方向向量,n 是折射率。入射结构包含一个点、一个法线和一个方向向量。
Fersnel 近似公式和折射向量的公式分别如下: enter image description here 您可以看到代码中我使用 epsilon * 射线方向值来避免由于浮点精度不准确而导致的阴影痤疮。虽然类似的情况也发生在小球上。 另一个截图: enter image description here 如您所见,球体并不透明,但它继承了漫反射球体的颜色。通常还会有一些白色像素。
无折射时的效果: enter image description here

涉及哪种类型的数字?你的值可能变得太小,无法被“float”准确表示,并趋近于零。你可以/已经尝试使用“double”代替吗? - nobody
在调试模式下,在getColor函数的结尾处,两个颜色值似乎在前几次迭代中都在20-100范围内,然后将被距离^2除以相机并饱和。 - PEC
1
我们都在想。死星。 - Neil Kirk
2个回答

1
答案实际上非常简单,但我花了三天时间盯着代码才找到错误。我有一个Surface类,我从它派生出两个类:RoughSurface(漫反射+布林)和ReflectiveSurface。然后,RefractiveSurace从RefleciveSurface派生而来。 ReflectiveSurface的构造函数将折射率(n)和消光系数(k)作为参数,但不存储它们。在构造过程中,从它们计算出(F0),然后就丢失了。另一方面,RefractiveSurface在折射角计算中使用(n)。
旧的构造函数:
RefractiveSurface::RefractiveSurface(float _n, const Color& _k) :
    ReflectiveSurface(Color(1, 1, 1) * _n, _k) {}

新构造函数:
RefractiveSurface::RefractiveSurface(float _n, const Color& _k) :
    ReflectiveSurface(Color(1, 1, 1) * _n, _k), n(_n) {}

作为您的助手,我可以翻译以下内容:

如您所见,我在构造函数中忘记保存RefractiveSurface的(n)值。

相机两侧照亮的大玻璃球后面的小红球:

enter image description here

它在运动中看起来很棒!D

谢谢你们的时间。我得完成这份作业,然后重新编写整个东西并尽可能地进行优化。


1

RefractiveSurface::refractionDir函数通过(非常量)引用获取法线N,并且它可能会翻转它。这似乎很危险。不清楚调用者是否希望I.normal被翻转,因为它在下面的颜色计算中使用。

此外,refracted_color并非总是初始化(除非Color构造函数使其变为黑色)。

尝试(暂时)简化代码,只需查看折射光线是否击中了您期望的位置。删除Fresnel计算和反射组件,并将refracted_color设置为折射光线的跟踪结果。这将有助于确定错误是在Fresnel计算中还是在弯曲光线的几何形状中。

调试提示:将未击中任何内容的像素着色为与黑色不同的颜色。这样可以轻松区分未命中的像素和阴影(表面粉刺)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接