《Ray Tracing in a Weekend》学习笔记05

想看原书可以看本系列的第一篇《Ray Tracing in a Weekend》学习笔记01

8.3 Using Gamma Correction for Accurate Color Intensity

在这里插入图片描述

这张照片很暗,这个球体在现实生活中应该是浅灰色。我们的球体在每次反弹仅吸收一半的能量,因此是50%反射器。看上去暗的原因是几乎所有的图像查看器都是假定图像经过“伽马校正”的,这意味着0到1的值存储为字节之前会有一些变换。我们可以使用“伽马2”,也就是将颜色提升为1/gamma的幂,或者通常就是平方根。

//[color.h] write_color(), with gamma correction
void write_color(std::ostream &out, color pixel_color, int samples_per_pixel) {
    auto r = pixel_color.x();
    auto g = pixel_color.y();
    auto b = pixel_color.z();

    // Divide the color by the number of samples and gamma-correct for gamma=2.0.
    auto scale = 1.0 / samples_per_pixel;
    r = sqrt(scale * r);
    g = sqrt(scale * g);
    b = sqrt(scale * b);

    // Write the translated [0,255] value of each color component.
    out << static_cast<int>(256 * clamp(r, 0.0, 0.999)) << ' '
        << static_cast<int>(256 * clamp(g, 0.0, 0.999)) << ' '
        << static_cast<int>(256 * clamp(b, 0.0, 0.999)) << '\n';
}

在这里插入图片描述

8.4 Fixing Shadow Acne

还有一个细微的错误。 一些反射的射线不是恰好在t = 0时撞击到它们所反射的对象,而是在t = -0.0000001或t = 0.00000001或球体相交给我们的任何浮点近似值处射出。 因此,我们需要忽略非常接近零的点击:

//[main.cc] Calculating reflected ray origins with tolerance
if (world.hit(r, 0.001, infinity, rec)) {
8.5 True Lambertian Reflection

这里介绍的方法是在单位球沿曲面法线偏移的位置产生随机点。这意味着接近法线的位置概率更高,偏离法线的位置概率较低。此分布是按cos^3(ϕ)缩放,ϕ是偏离方向与法线的夹角。这是合理的,因为以浅角度到达的光,会散布到更大的区域上,因此他们对最终颜色贡献较小。

我们对具有cos(ϕ)分布的Lambertian分布感兴趣。 True Lambertian射线接近法线的可能性更高,但是分布更均匀。 这是通过在单位球面上拾取沿曲面法线偏移的点来实现的。 可以通过在单位球中拾取点,然后对其进行归一化来获得球体上的拾取点。

//[vec3.h] The random_unit_vector() function
//单位球体表面上一点满足x^2+y^2+z^2=1;
vec3 random_unit_vector() {
    auto a = random_double(0, 2*pi);
    auto z = random_double(-1, 1);
    auto r = sqrt(1 - z*z);
    return vec3(r*cos(a), r*sin(a), z);
}

在这里插入图片描述

该random_unit_vector()替代了现有random_in_unit_sphere()函数。

//[main.c] ray_color() with replacement diffuse
color ray_color(const ray& r, const hittable& world, int depth) {
    hit_record rec;

    // If we've exceeded the ray bounce limit, no more light is gathered.
    if (depth <= 0)
        return color(0,0,0);

    if (world.hit(r, 0.001, infinity, rec)) {
        point3 target = rec.p + rec.normal + random_unit_vector();
        return 0.5 * ray_color(ray(rec.p, target - rec.p), world, depth-1);
    }

    vec3 unit_direction = unit_vector(r.direction());
    auto t = 0.5*(unit_direction.y() + 1.0);
    return (1.0-t)*color(1.0, 1.0, 1.0) + t*color(0.5, 0.7, 1.0);
}

在这里插入图片描述

这两个变化都是由于光线的散射更加均匀,朝法线散射的光线更少。 这意味着对于散射的物体,它们会显得更亮,因为更多的光会朝着相机反弹。 对于阴影,较少的光直接向上反射,因此较大球体的正下方较小球体的部分更亮。

8.6 An Alternative Diffuse Formulation

一种更直观的方法是,对于远离击点的所有角度都具有统一的散射方向,而不依赖于与法线的角度。 许多第一批射线追踪论文都使用这种扩散方法(在采用Lambertian散射之前)。

//[vec3.h] The random_in_hemisphere(normal) function
vec3 random_in_hemisphere(const vec3& normal) {
    vec3 in_unit_sphere = random_in_unit_sphere();
    if (dot(in_unit_sphere, normal) > 0.0) // In the same hemisphere as the normal
        return in_unit_sphere;
    else
        return -in_unit_sphere;
}

将新公式插入ray_color()函数:

//[main.c] ray_color() with hemispherical scattering
color ray_color(const ray& r, const hittable& world, int depth) {
    hit_record rec;

    // If we've exceeded the ray bounce limit, no more light is gathered.
    if (depth <= 0)
        return color(0,0,0);

    if (world.hit(r, 0.001, infinity, rec)) {
        point3 target = rec.p + random_in_hemisphere(rec.normal);
        return 0.5 * ray_color(ray(rec.p, target - rec.p), world, depth-1);
    }

    vec3 unit_direction = unit_vector(r.direction());
    auto t = 0.5*(unit_direction.y() + 1.0);
    return (1.0-t)*color(1.0, 1.0, 1.0) + t*color(0.5, 0.7, 1.0);
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值