1. 程式人生 > >光線追蹤<1-1> 超詳解《Ray Tracing in One Weekend》

光線追蹤<1-1> 超詳解《Ray Tracing in One Weekend》

 

Preface

從這一篇起,我們開始學光線追蹤這門牛逼的技術。讀了幾天,一個字:強!

這一篇我們主要講述技術入門和一些簡單的案例。

我們先學這本:

        

 

 

Ready

這本書需要ppmview這個軟體幫忙看效果圖,不過下載也非常快。

其次,需要你會C/C++讀寫檔案

最後需要你具備三維空間想象能力以及我對書中公式的講述

 

Chapter1: Output an image

先看一張圖,秒懂一下它如何設定畫素

話說,有這麼一個檔案,叫做.ppm檔案。它以水平向右為x正方向,以垂直向下為y正方向。

它的檔案儲存內容解讀如上,關於第一行的P3是指檔案的type

 

P3下面那兩個數指的是列數和行數,或者你可以理解為x軸的長度和y軸的長度,或者理解為影象的寬和高。

再下面一行有一個數為畫素的最大值

之後有x*y個(r,g,b)三元組,它會按照順序讀取,並且在影象的左上角開始一行一行掃描設定畫素值

 

所以我們現在開始寫程式碼實現上面那個影象,但是我按照上面的輸入到檔案中,由於只有6個畫素點,我幾乎看不到任何影象,我不知道你們的情況,所以我自己設定一個例子:

我設定上面那個影象的每一個顏色方格為20*20尺寸的。然後每個方格對應自己的畫素值。

 

程式碼如下:

#define stds std::
void build_1_1()
{
    const stds string s1[3] = { "255 0 0","0 255 0","0 0 255" };
    const stds string s2[3] = { "255 255 0","255 255 255","0 0 0" };

    stds ofstream file("graph1-1.ppm");
    if (file.is_open())
    {
        file << "P3\n" << 60 << "
" << 40 << "\n255\n"; for (int i = 0; i < 20; ++i) for (int j = 0; j < 60; ++j) file << s1[j / 20] << stds endl; for (int i = 0; i < 20; ++i) for (int j = 0; j < 60; ++j) file << s2[j / 20] << stds endl; file.close(); stds cout << "complished" << stds endl; } else stds cerr << "error" << stds endl; }

 

然後我們用ppmview開啟就是這樣的:

    

 

好了,大家估計明白了我們這個檔案的使用

 

那我們來整一個好玩的。

 

這是書上的程式碼,如果你能夠看懂,那固然很好,不過看不懂也沒關係

它說了個啥意思呢?

它先設定三個量r,g,b,它們的值在[0,1),然後通過乘255.99將值對映到[0,255]

好了我們可以看第一個畫素:(0,255,0.2),應該是綠色的,如果覺得blue的0.2有點干擾,你可以設為0(建議這麼做),第一行掃完之後,也就是內部for第一次跳出的時候,那個畫素是(255,255,0.2),差不多是r和g組合,接近黃色,那麼第一行就是r從0到255,綠色到黃色漸變。用同樣的方法,我們可以知道,左下角這個點應該是近黑色,右下角應該是近紅色。中間的內容是線性插值得到的畫素值。

 

 Chapter 2:The vec3 class

 

 此章節,以及後面的部分,數學部分直接引用現寫的3D數學庫

轉到:https://www.cnblogs.com/lv-anchoret/p/10163085.html

 

這一章就是將上述rgb用三維向量表示:

 

#define LOWPRECISION

#include <fstream>
#include <lvgm\lvgm.h>
using namespace lvgm;

#define stds std::

void build_1_2()
{
    int X = 400, Y = 200;
    stds ofstream file("graph2-1.ppm");
    if (file.is_open())
    {
        file << "P3\n" << X << " " << Y << "\n255\n";
        for (int j = Y - 1; j >= 0; --j)
            for (int i = 0; i < X; ++i)
            {
                dvec3 col(double(i) / X, double(j) / Y, 0.0);
                int ir = int(255.99*col.r());
                int ig = int(255.99*col.g());
                int ib = int(255.99*col.b());
                file << ir << " " << ig << " " << ib << stds endl;
            }
        file.close();
        stds cout << "complished" << stds endl;
    }
    else
        stds cerr << "load file failed!" << stds endl;
}


int main()
{
    build_1_2();

}

 

 

 

 

把blue改為0,影象就清晰多了

 

 

由於今日天色已晚,咱們明天繼續

 

感謝您的閱讀,晚安~