【Ray Tracing in One Weekend】(ch6)Ray Tracer 裏的反走樣

Chapter 6: Antialiasing

先回顧一下在上一章我們得到的圖

這裏寫圖片描述

把局部放大一下

這裏寫圖片描述

可以看到球體邊緣呈現比較明顯的鋸齒狀。解決這個問題的過程就叫做反走樣。其實就是讓前景和背景交叉的邊緣變得更平滑而已。具體應該怎麼做呢?

從代碼中我們知道,我們共發射出了200*100條射線,對應了200*100個像素格子(從上圖中可以隱隱看出像素格子),這樣在前景與背景交叉的像素格子上必定只有一種顏色,這樣就會出現明顯的鋸齒狀(鋸齒其實就是一個個像素格子)。在不改變圖像分辨率的情況下,如何改善這種狀況呢?

其實,每個像素格子的顏色並不代表着那一塊區域真正的顏色,只是我們採用了發射一條射線碰撞到的一點返回的顏色代替了那一小塊區域的顏色,那麼,解決這個問題就變得簡單了,我們多發射一些射線到這個格子裏,然後取這些射線返回顏色的均值就好啦!

首先爲了方便,我們先把擱置了很久的 Camera 類封裝起來:

#pragma once

#include "Ray.h"

class Camera 
{
public:
    Camera()
    {
        lower_left_corner = Vec3(-2.0f, -1.0f, -1.0f);
        horizontal = Vec3(4.0f, 0.0f, 0.0f);
        vertical = Vec3(0.0f, 2.0f, 0.0f);
        origin = Vec3(0.0f, 0.0f, 0.0f);
    }

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

    Vec3 lower_left_corner;
    Vec3 origin;
    Vec3 horizontal;
    Vec3 vertical;
};

接着修改Main方法爲:

int main()
{

    ofstream outfile;
    outfile.open("ch6Image.ppm");

    int nx = 200;
    int ny = 100;
    //採樣次數
    int ns = 100;
    outfile << "P3\n" << nx << " " << ny << "\n255\n";

    Hitable *list[2];
    list[0] = new Sphere(Vec3(0.0f, 0.0f, -1.0f), 0.5f);
    list[1] = new Sphere(Vec3(0.0f, -100.5f, -1.0f), 100.0f);
    Hitable *world = new HitableList(list, 2);

    Camera cam;

    //隨機數引擎
    default_random_engine reng;
    uniform_real_distribution<float> uni_dist(0.0f, 1.0f);

    for (int j = ny - 1; j >= 0; j--)
    {
        for (int i = 0; i < nx; i++)
        {
            Vec3 col(0.0f, 0.0f, 0.0f);
            //每個區域採樣ns次
            for (int s = 0; s < ns; s++)
            {
                float u = float(i + uni_dist(reng)) / float(nx);
                float v = float(j + uni_dist(reng)) / float(ny);
                Ray r = cam.getRay(u,v);
                //Vec3 p = r.point_at_parameter(2.0);
                //將本區域((u,v)到(u+1,v+1))的顏色值累加
                col += Color(r, world);
            }
            //獲得區域的顏色均值
            col /= float(ns);

            int ir = int(255.99*col[0]);
            int ig = int(255.99*col[1]);
            int ib = int(255.99*col[2]);
            outfile << ir << " " << ig << " " << ib << "\n";
        }
    }
    outfile.close();
    return 0;
}

最後所得圖片爲:

這裏寫圖片描述

將局部放大一下做一下對比:

這裏寫圖片描述

可以看到,下面的圓的邊緣明顯出現了“過渡色”的像素塊,比較好的解決了走樣問題。

同時我們也要注意到,開啓反走樣之後,渲染速率變慢了非常多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章