【RAY TRACING THE REST OF YOUR LIFE 超詳解】 光線追蹤 3-1 蒙特卡羅 (一)


今天起,咱們就開始學習第三本書了ios

  

 

 

這本書主要講的是蒙特卡羅渲染,以及相關的數學、術語概念等ide

這本書相較於前面兩本有着什麼不一樣,承擔着什麼樣的任務,尚涉書未深,姑妄言之:學習

第一本書,帶領咱們初探光線追蹤技術,感覺一下測試

第二本書,篇幅頁目最多,帶着咱們一步一步,構建了一個「真正」的光線追蹤器,這裏真正指的是,第二本書的內容較廣,涉及紋理、光照、煙霧,隨機初步等,所謂麻雀雖小,五臟俱全,此所謂「真正」優化

第三本書,讓咱們更加走進了實際的光線追蹤器,偏向工業級的,因此,做者前言即講到,若是你想要從事光線追蹤相關的行業,這本書爲你準備。學過第二本書,咱們知道,越日後面,渲染效果越不盡人意,這裏指的是若是採樣點過少(例如幾百),根本沒法渲染出真實的效果,好比光照相關的Cornell box例子就有不少噪聲干擾,這些,玩玩還能夠,可是,離專業還有距離,也就是它只是一個五臟俱全的劣質品,並不能稱得上是真正的光線追蹤器。spa

而這本書承擔的任務只有一個,就是利用Monte Carlo(MC)方法優化咱們第二本書中的渲染效果,也就是爲第二本書中的光線追蹤機器裝一個高端的引擎驅動內核零件,讓它更好。code

 

咱們先來一個簡單的開胃菜blog

 

chapter 1:A Simple Monte Carlo Program圖片

蒙特卡羅方法(MC)是一種統計模擬方法,是一類很重要的數值計算方法,它是一種使用隨機數解決好不少實際問題的方法。ci

先來看一個很簡單的例子:估計π

有不少經典的方法,其中之一是

假設你扔了不少隨機的點到方框中,那麼有一部分在圓內,其中圓內點和方框點的比例應該就是圓的面積和方框面積的比例,由此:

比例 = (π * R * R)/((2R)*(2R)) = π/4

因此上式和R無關,咱們任意取R = 1,圓心位於原點,則

#include <iostream>
#include <lvgm\randfunc.hpp>
#define stds std::
using namespace lvgm;

void estimate_π(const size_t points)
{
    int inside = 0;
    for (int i = 0; i < points; ++i)
    {
        double x = 2 * rand01() - 1;
        double y = 2 * rand01() - 1;
        if (x*x + y*y < 1)
            inside++;
    }
    stds cout << "Estimate of π by" << points << "test points is " << 4 * double(inside) / points << stds endl;
}

int main()
{
  estimate_π(1000);
  estimate_π(10000);
  estimate_π(100000);
  estimate_π(1000000);
  estimate_π(10000000);
  estimate_π(10000000 / 2);
}

 

模擬結果爲

 

 

 固然咱們能夠利用下面的程序使結果迅速逼近π

void lawDiminishingReturns()
{
    int inside = 0;
    int runs = 0;
    while (true)
    {
        runs++;
        double x = 2 * rand01() - 1;
        double y = 2 * rand01() - 1;
        if (x*x + y*y < 1)
            inside++;
        if(runs % 10000 == 0)
            stds cout << "Estimate of π by" << runs << "test points is " << 4 * double(inside) / runs << stds endl;
    }
}

結果:

.

 

一開始很是快速的逼近π,以後變化就比較緩慢了,這是一個收益遞減法(Law of Diminishing Returns)的例子

即每個樣本對結果的收益少於後面一個,這個是MC的一個缺點,咱們能夠經過對樣本進行分層來減輕這種遞減收益,此法一般稱爲抖動

咱們進行網格劃分,並在每一個網格中選取一個樣本:

 

咱們採用邊長爲1e4的方框進行測試

void stratify()
{
    size_t inside{ 0 };
    size_t circle_stratified{ 0 };
    size_t sqrtAll = 1e4;
    for (int i = 0; i < sqrtAll; ++i)
        for (int j = 0; j < sqrtAll; ++j)
        {
            double x = 2 * rand01() - 1;
            double y = 2 * rand01() - 1;
            if (x*x + y*y < 1)
                inside++;
            x = 2 * ((i + rand01()) / sqrtAll) - 1;
            y = 2 * ((j + rand01()) / sqrtAll) - 1;
            if (x*x + y*y < 1)
                circle_stratified++;
        }
    stds cout << "Regular Estimate of π by 1e8 test points is " << 4 * double(inside) / 1e8 << stds endl;
    stds cout << "Stratified Estimate of π by 1e8 test points is " << 4 * double(circle_stratified) / 1e8 << stds endl;
}

 

圖片渲染運算讀寫文件的時候慢。。現在控制檯運算輸出也整不動了。。。。

有意思~

 

分層方法能更好地收斂於漸近率。不足之處是,這個優點隨着問題的維度而下降(例如,對於3D球體積版本,差距會更小)。 這被稱爲維度詛咒(=.=)。 咱們的工程將是很是高的維度(每一個反射增長兩個維度),因此我不會在本書中進行分層。

可是,若是你作的是單反射或陰影或某些嚴格的2D問題,分層是個很好的選擇

 

感謝您的閱讀,生活愉快~

相關文章
相關標籤/搜索