《周末光线追踪》书中的光线追踪(书中名为 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
。这不是不正确吗,因为我们确实击中过某物并遮蔽了该点,但我们将返回黑色。我对此进行了测试,所有物体都变黑了。如果我设置 depth = 2
我会得到
如果我添加一个守卫if (depth == 1) return attenuation; else return attenuation * ray_color(...);
,我确实会得到你想要的东西,如果你有
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;
}
您可能已经知道这一点,但关于光线追踪,首先要记住的是它是向后完成的。我们从眼睛(或相机)发射光线,但实际上光线源自背景,从物体反射并最终进入眼睛。
示例中的球体不发光,它们只是反射/散射因反照率而减弱的背景光。
如果光线反射太多次,就会变成“黑色”。我们通过将
max_depth
设置为某个值来“加速”这个过程(以及我们的计算)。
如果深度太低,那么最终会出现黑点。但是,当深度足够高时,光线最终会“找到路径”到达背景。实际上,这意味着背景光通过多次反射(乘以反射物体的反照率)会到达眼睛/相机。所以,你不会有黑点。这是一个非常非技术性(和隐喻性)的解释,但希望它有意义。
...尽管如此,结果对我来说仍然看起来很奇怪。
那是因为你的物理宇宙模型不准确。事实上,灯没有
max_depth
功能。它会反射多次,每次都会失去一些强度。