Prefacehtml
注:鑑於不少網站隨意爬取數據,可能致使內容殘缺以及引用失效等問題,影響閱讀,請認準原創網址:app
https://www.cnblogs.com/lv-anchoret/category/1368696.html框架
咱們這節主要講把以前的機率密度作混合,以獲得更好的效果dom
咱們上一篇之前常常用關於cos函數的pdf,上一節用的是與光源採樣相關的pdf,那麼,咱們把二者結合到一塊兒,協調它們之間的比例,咱們就能夠獲得一個有着兩種機率密度模型的pdf,這每每是更貼近生活的,那麼咱們今天就來學習測試一下。函數
Ready學習
這一節就是把前幾篇的機率密度作混合,因此,須要的就是熟悉以前的內容。測試
固然,以前的框架代碼也比較醜,基本都是在lerp函數裏面作調整,因此,咱們順便把框架搭得更好一點網站
正文ui
咱們都知道,設計pdf的一個很重要的原則就是使得累積機率密度達到且只達到1,因此,咱們先採用一種很是簡單的比例協調方式混合兩個pdf。this
例如咱們有以下的混合密度方程
pdf_mixture(direction) = 1/2 * pdf_reflection(direction) + 1/2 * pdf_light(direction)
即,二者各佔一半
要實現二者,代碼描述也很簡單:
if ( rand01() < 0.5 ) pdf_reflection(); ... else pdf_light(); ...
///pdf.hpp // ----------------------------------------------------- // [author] lv // [ time ] 2019.3 // [brief ] In the Monte Carlo system, pdf acts as the // most important element of Important-Sample // ----------------------------------------------------- #pragma once namespace rt { // the basic class of pdf system class pdf { public: /* @brief: we get the value of pdf function by this interface @param: the direction of location @retur: the value of the pdf function */ virtual rtvar value(const rtvec & direction)const = 0; /* @brief: generate a random number with a Probability model @param: none @retur: the Three-dimensional random vector */ virtual rtvec generate()const = 0; }; }//rt namespace
咱們來實現關於它的一些子類
首先咱們來實現關於cosine 機率密度的模型
///cosine_pdf.hpp // ----------------------------------------------------- // [author] lv // [ time ] 2019.3 // [brief ] one of the pdf' forms // ----------------------------------------------------- #pragma once namespace rt { class cosine_pdf :public pdf { public: //constructor cosine_pdf(const rtvec& w); /* @brief: we get the value of pdf function by this interface @param: the direction of location @retur: the value of the pdf function */ virtual rtvar value(const rtvec& direction)const; /* @brief: generate a random number with a Probability model @param: none @retur: the Three-dimensional random vector */ virtual rtvec generate()const; private: onb _uvw; }; inline cosine_pdf::cosine_pdf(const rtvec& w) { _uvw.build_from_w(w); } rtvar cosine_pdf::value(const rtvec& direction)const { rtvar cosine = dot(direction.ret_unitization(), _uvw.w()); if (cosine > 0.) return cosine / π; else return 0.; } rtvec cosine_pdf::generate()const { return _uvw.local(random_cosine_direction()); } }
這個模型以前細說過,cosine大於0的時候返回cosine/π,反之,則返回0。由於光線反射以後若是和表面法線的夾角爲鈍角的時候,違反反射規律,不以反射。生成隨機數的那個以前也講過,在上上一篇
其實這些都不是新東西,就是把以前講的的那一套整合了一下
獲得結果也就是以前的效果
咱們把主函數裏面的lerp()也改一下
每一個像素點採樣100次,取均值,即sample 爲 100時
這是代碼敲錯了,意外獲得的一張圖
如今咱們嘗試,光源採樣,即
///hit_pdf.hpp // ----------------------------------------------------- // [author] lv // [ time ] 2019.3 // [brief ] toward to the hitable // ----------------------------------------------------- #pragma once namespace rt { class hit_pdf :public pdf { public: /* @param: info -> Geometry information origion -> the point of intersection */ hit_pdf(intersect* info, const rtvec& origion) :_intersectp(info) ,_o(origion) { } /* @brief: we get the value of pdf function by this interface @param: the direction of location @retur: the value of the pdf function */ virtual rtvar value(const rtvec& direction)const { return _intersectp->pdf_value(_o, direction); } /* @brief: generate a random number with a Probability model @param: none @retur: the Three-dimensional random vector */ virtual rtvec generate()const { return _intersectp->random(_o); } private: rtvec _o; intersect * _intersectp; }; }// rt namespace
對應的intersect類也要改一下
/// intersect.hpp //https://www.cnblogs.com/lv-anchoret/p/10190092.html // ----------------------------------------------------- // [author] lv // [begin ] 2018.12 // [refre ] 2019.3 // [brief ] the intersect-class for the ray-tracing project // from the 《ray tracing in one week》 // ----------------------------------------------------- #pragma once #include "E:\OpenGL\光線追蹤\code\ray tracing 1-3\ray tracing 1-3\ray.hpp" namespace rt { class material; class aabb; // the infomation of intersection point struct hitInfo { lvgm::precision _t; //ray 中的係數t rtvec _p; //相交點、撞擊點 rtvec _n; //_p點的表面法線 material* _materialp; //材質 rtvar _u; //texture-u rtvar _v; //texture-v }; // the statement of intersect class class intersect { public: /* @brief: 撞擊函數,求取撞擊點相關記錄信息 @param: sight->視線 係數t的上下界->篩選撞擊點 info->返回撞擊點信息 @retur: 是否存在合法撞擊點 */ virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const = 0; /* @brief: get the box of Geometry */ virtual aabb getbox()const = 0; /* Get the value of pdf function */ virtual rtvar pdf_value(const rtvec& o, const rtvec& v)const { return 0.; } /* generate the random number */ virtual rtvec random(const rtvec& o)const { return rtvec(1, 0, 0); } }; }// rt namespace
由於咱們如今只是拿區域光源作實驗,並非全部的幾何體派生類都要繼承pdf相關的方法,因此,它們兩個以虛函數的形式存在便可。
那麼就剩下xz長方形了
rtvar xz_rect::pdf_value(const rtvec& o, const rtvec& v)const { hitInfo rec; if (this->hit(ray(o, v), 1e-3, rt::rtInf(), rec)) { rtvar area = (_x2 - _x1)*(_z2 - _z1); rtvar distance_squared = rec._t * rec._t * v.squar(); rtvar cosine = fabs(dot(v, rec._n) / v.normal()); return distance_squared / (cosine*area); } else return 0.; } rtvec xz_rect::random(const rtvec& o)const { rtvec random_point = rtvec(_x1 + lvgm::rand01() * (_x2 - _x1), _other, _z1 + lvgm::rand01()*(_z2 - _z1)); return random_point - o; }
把上一篇寫在lerp函數裏面的一大堆東西整合到類裏面
那麼咱們的lerp就統一化了:
咱們取sample爲10,便可獲得很好的效果:
如今咱們將寫一個關於混合機率密度的類:
///mixture_pdf.hpp // ----------------------------------------------------- // [author] lv // [ time ] 2019.3 // [brief ] mixture pdfs // ----------------------------------------------------- #pragma once namespace rt { class mixture_pdf :public pdf { public: mixture_pdf(pdf * p1, pdf* p2) { _p[0] = p1; _p[1] = p2; } /* @brief: we get the value of pdf function by this interface @param: the direction of location @retur: the value of the pdf function */ virtual rtvar value(const rtvec& direction)const { return 0.5*_p[0]->value(direction) + 0.5*_p[1]->value(direction); } /* @brief: generate a random number with a Probability model @param: none @retur: the Three-dimensional random vector */ virtual rtvec generate()const { if (lvgm::rand01() < 0.5) return _p[0]->generate(); else return _p[1]->generate(); } private: pdf* _p[2]; }; }// rt namespace
咱們的lerp函數以下:
咱們採樣10次獲得:
可是以爲效果不是很理想,咱們來作一些測試
1. pdf 方程修改成 mixture_pdf = 1/3 * hit_pdf + 2/3 * cosine_pdf
2. pdf 方程修改成 mixture_pdf = 2/3 * hit_pdf + 1/3 * cosine_pdf
3. random修改 2/3 取 hit_pdf產生的隨機值, 1/3 取 cosine_pdf 產生的隨機值
4. random修改 1/3 取 hit_pdf產生的隨機值, 2/3 取 cosine_pdf 產生的隨機值
咱們去上述方案的三、1,即:
獲得圖:
這張圖顯然比均分的效果要好
這裏咱們看不出究竟是random起做用仍是value,咱們不妨取二、3組合
3把2的彩色噪聲消除了些,可是這張圖和原始的均分圖差很少同樣
因此結論,random和value的比例交叉比較好
咱們採樣1000次獲得:
渲染中。。。。(就是清晰了點)
/***********************************************************************************/
跑了一夜爬起來發現除零錯誤了,又抽空跑完了
/************************************************************************************/
本書第九章(下一章)介紹了一些關於當前渲染器的見解
做者在描述陰影光線和混合密度設計時,做者我的更偏向於混合密度設計,因此並無在渲染器中採用陰影光線
做者描述了關於lerp函數中內存問題以及編碼的不足
做者描述了關於玻璃材質和鏡面的一些處理方法
做者還描述了關於HDR的0~1浮點表示以及RGB分組的0~255表示,還說明了這個渲染器是RGB的且基於物理的,還有一種是基於光譜的,以及二者結合的,但作起來很難,因此咱們堅持RGB且基於物理的渲染器。
感謝您的閱讀,生活愉快~