《一个周末的光线追踪:第 1 部分》一书中的 ray_color(...)(光线追踪函数)是否正确?

问题描述 投票:0回答:1

《周末光线追踪》书中的光线追踪(书中名为 ray_color)函数看起来像这样 color ray_color(const ray& r, int depth, const hittable& world) const { // If we've exceeded the ray bounce limit, no more light is gathered. if (depth <= 0) return color(0,0,0); hit_record rec; if (world.hit(r, interval(0.001, infinity), rec)) { ray scattered; color attenuation; if (rec.mat->scatter(r, rec, attenuation, scattered)) return attenuation * ray_color(scattered, depth-1, world); return color(0,0,0); } vec3 unit_direction = unit_vector(r.direction()); auto a = 0.5*(unit_direction.y() + 1.0); return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0); }

我怀疑由于某个特定原因这没有意义。

depth=1

当我们开始通过像素发射初始光线时。假设我们击中了一个物体,因此我们到达了

if(rec.mat->scatter(...))
。假设
scatter(...)
返回 true,因此我们返回
attenuation * ray_color(scattered, depth - 1, world)
。现在请注意,由于守卫
if(depth <= 0)
的 retval 为
color(0,0,0)
,递归调用将立即返回。这将使乘法
attenuation * ray_color(...)
变为
0
这不是不正确吗,因为我们

确实

击中过某物并遮蔽了该点,但我们将返回黑色。我对此进行了测试,所有物体都变黑了。如果我设置 sure enoughdepth = 2 我会得到

。请注意,我们似乎获得了一次反射(从我们可以看到镜面反射的事实来看)......但反射的反射全部为黑色。this weird result
我真的无法理解这是如何正确的。我在谷歌上搜索了很多人对这本书的实现,他们似乎都做了完全相同的事情。这有什么意义?

编辑:

如果我添加一个守卫if (depth == 1) return attenuation; else return attenuation * ray_color(...);,我确实会得到你想要的东西,如果你有

,而且反射似乎用depth=1depth=2着色更正确。尽管如此,结果对我来说仍然看起来很奇怪。请注意,我仍然得到完全黑色的反射,这可能是由于最初提到的与零相乘的问题。也许还有其他问题,可能是我自己的代码。我可能需要就此发表一篇新文章,因为这可能是一个与这个问题所涉及的问题不同的问题。depth=25
Color RayTracer::TraceRay(const Ray& ray, int depth, float weight)
{

    if (depth <= 0)
        return Utils::Colors::BLACK;

    HitPayload hp = FindClosestHit(ray);
    
    if (hp.t < 0.0f) {
        // We didn't hit anything, just return a sky color of some kind.
        const float alpha = 0.5f * (ray.Dir().y + 1.0f);
        const Color skyColor = (1.0f - alpha) * Utils::Colors::WHITE + alpha * Utils::Colors::SKY_COLOR;
        return skyColor * weight;
    }
    
    const Material* mat = m_Scene->GetMaterial(hp.Shape->GetMaterialIdx());

    Color colorOut{};
    Ray rayOut{};
    rayOut.SetOrigin(hp.Position + Utils::Constants::EPSILON * hp.Normal);

    // TODO: Cast shadow ray(s)
    if (mat->Shade(ray, rayOut, colorOut, hp))
        if (depth == 1)
            return colorOut;
        else
            return (weight * colorOut) * TraceRay(rayOut, depth - 1, 0.75f * weight);
    
    // Material is a black body
    return Utils::Colors::BLACK;

}


raytracing
1个回答
0
投票
这有什么意义?

您可能已经知道这一点,但关于光线追踪,首先要记住的是它是向后完成的。我们从眼睛(或相机)发射光线,但实际上光线源自背景,从物体反射并最终进入眼睛。

示例中的球体不发光,它们只是反射/散射因反照率而减弱的背景光。

如果光线反射太多次,就会变成“黑色”。我们通过将

max_depth

设置为某个值来“加速”这个过程(以及我们的计算)。

如果深度太低,那么最终会出现黑点。但是,当深度足够高时,光线最终会“找到路径”到达背景。实际上,这意味着背景光通过多次反射(乘以反射物体的反照率)会到达眼睛/相机。

所以,你不会有黑点。这是一个非常非技术性(和隐喻性)的解释,但希望它有意义。

...尽管如此,结果对我来说仍然看起来很奇怪。

那是因为你的物理宇宙模型不准确。事实上,灯没有
max_depth

功能。它会反射多次,每次都会失去一些强度。

    

© www.soinside.com 2019 - 2024. All rights reserved.