光線追蹤<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,影象就清晰多了
由於今日天色已晚,咱們明天繼續
感謝您的閱讀,晚安~