【光线追踪系列四】抗锯齿

本次光线追踪系列从基础重新开始,主要参照 Ray Tracing in One Weekend ,具体实现代码框架见 https://github.com/RayTracing/raytracing.github.io/。本文只是主要精炼光追相关理论,具体实现可参照原文。
在这里插入图片描述

当真实的相机拍摄照片时,通常沿边缘没有锯齿,因为边缘像素是某些前景和某些背景的混合。通过平均每个像素中的一堆样本,我们可以获得相同的效果。我们不会为分层而烦恼。这是有争议的,但是在我的程序中很常见。对于某些光线跟踪器来说,它很关键,但是我们正在编写的那种通用的射线跟踪器并不能从中受益很多,这会使代码更丑陋。我们对相机类进行了一些抽象,以便以后可以制作更酷的相机。

一、相机类

跟原来入口函数里面的逻辑完全一样,新增了个get_ray(float u, float v)函数,用于获得从相机位置发射到屏幕对应位置的射线。

class camera
{
public:
    vec3 origin;
    vec3 lower_left_corner;
    vec3 horizontal;
    vec3 vertical;

    camera()
    {
        lower_left_corner = vec3(-2.0, -1.0, -1.0);
        horizontal = vec3(4.0, 0.0, 0.0);
        vertical = vec3(0.0, 2.0, 0.0);
        origin = vec3(0.0, 0.0, 0.0);
    }

    ray get_ray(float u, float v)
    {
        return ray(origin, lower_left_corner + u * horizontal + v * vertical - origin);
    }
};

二、随机采样

中的随机数函数rand()会返回0到RANDMAX之间的一个随机数,要生成[0,1)的随机数,我们可以将代码写成这样:

#include <cstdlib>

inline double random_double() {
    return rand() / (RAND_MAX + 1.0);
}

三、随机采样并求平均

在一个像素里面随机使用多条光线进行采样,最后求平均,可以实现抗锯齿。
在这里插入图片描述
添加像素随机采样代码:

void RayTracing()
{
	...
    int ns = 100;   //new
    camera cam;     //new

    for (int j = ny - 1; j >= 0; j --)
    {
        for (int i = 0; i < nx; i++)
        {
            
            vec3 col(0, 0, 0);	//new
            for(int s = 0; s < ns; s++)	//随机采样100次
            {
                float u = float(i + random_double()) / float(nx);
                float v = float(j + random_double()) / float(ny);
                ray r = cam.get_ray(u, v);
                col += color(r, world);
            }
            col /= float(ns);	//new

            int ir = int(255.99 * col[0]);
            int ig = int(255.99 * col[1]);
            int ib = int(255.99 * col[2]);
            DrawPixel(i, j, ir, ig, ib);
        }
    }
}

对每个像素随机发射100条光线后,求平均,得到如下的抗锯齿效果:
在这里插入图片描述
此时你可以对比下随机采样1次的效果:
在这里插入图片描述

再夸张点,下边贴上一张每个像素采样1000次的图片:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值