Preface
終於到了激動人心的紋理章節了
然鵝,看了下,並不激動
因為我們之前就接觸過
當初有一個 attenuation 嗎?
對了,這就是我們的rgb分量過濾器,我們畫出的紅色、藍色、綠色等等,都是通過它來控制的
專業點的詞語叫做rgb衰減比例,比如rtvec(1.,0.,0.),最后呈現出來的是紅色,因為r保留了100%
它是怎么控制的呢,我們來回顧一下這個過程
首先,我們創建一個材質球
后面那個rtvec(0.4,0.2,0.1)就是衰減比例(衰減到原來的百分之。。)
之后
進入數據成員中,之后主函數調用lerp的時候
info.materialp->scatter(sight, info, attenuation, scattered))
球體的材質調用scatter函數
即:
沒有絲毫改動地有數據成員傳遞到了attenuation 中
然后用attenuation 做乘法進行rgb衰減,遞歸就不用說了吧,最后遞歸到深處為黑色,不然為背景色
為什么要在前言將這個東東,因為
attenuation 所控制形成的物體表面顏色就是最簡單的紋理
說白了這章比較簡單,因為下一章是這本書的另外一個高難度章節(分別分布於第二章和第四章)
所以,中間第三章來點簡單好玩的,過渡一下
先看效果
Chapter 3:Solid Textures
廢話不多說,先寫一個紋理類
/// texture.hpp // ----------------------------------------------------- // [author] lv // [begin ] 2019.1 // [brief ] the texture-class for the ray-tracing project // from the 《ray tracing the next week》 #pragma once namespace rt { class texture { public: virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const = 0; }; }
u 和 v后面用到再講,p就是衰減向量
然后寫一個常量紋理(基礎紋理)
/// constant_tex.hpp // ----------------------------------------------------- // [author] lv // [begin ] 2019.1 // [brief ] the constant_texture-class for the ray-tracing project // from the 《ray tracing the next week》 // ----------------------------------------------------- #pragma once namespace rt { class constant_texture :public texture { public: constant_texture() { } constant_texture(const rtvec& color); virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const override; public: inline const rtvec& color()const { return _color; } private: rtvec _color; }; inline constant_texture::constant_texture(const rtvec& color) :_color(color) { } rtvec constant_texture::value(rtvar u, rtvar v, const rtvec& p)const { return _color; } }
之后,我們把材質中的rtvec向量改為紋理指針
/// diffuse.hpp // https://www.cnblogs.com/lv-anchoret/p/10198423.html // ----------------------------------------------------- // [author] lv // [begin ] 2018.12 // [brief ] one of the materials // ----------------------------------------------------- #pragma once
namespace rt { class texture; //diffuse material class lambertian : public material { public: lambertian(texture* _tex); virtual bool scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const override; protected: texture* _albedo; }; inline lambertian::lambertian(texture* _tex) :_albedo(_tex) { } bool lambertian::scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const { rtvec target = info._p + info._n + lvgm::random_unit_sphere(); scattered = ray{ info._p, target - info._p }; attenuation = _albedo->value(0.,0.,info._p); return true; } }
之前我們創建的材質球代碼就要改一種風格了
把其他的材質類也做相應的改動
我們今天最重要的是弄棋盤(checkerboard)紋理
棋盤紋理就是交錯的雙色格子,呈現一定的規律性
所以我們想象一下利用某些映射函數來實現這種類似二值性,且呈現周期性
我們比較容易想到利用正余弦函數,呈現周期性,且值域為【-1,1】是個有界函數
如何體現二值呢,正負嘛,正余弦函數一定關於x軸對稱
如何將物體表面和正余弦函數聯系在一起形成雙色交錯的格子呢
我們采用每個點在3D空間中的位置來將兩者聯系在一起
綜上,如果我們在所有三個維度中相乘某個正余弦函數,那么該公式的符號形成一個棋盤形式
即:rtvar sines = sin(10 * p.x()) * sin(10 * p.y()) * sin(10 * p.z());
當然,你也可以試一下sgnx函數,設置一個相關的判別式
/// checker_tex.hpp // ----------------------------------------------------- // [author] lv // [begin ] 2019.1 // [brief ] the checker_texture-class for the ray-tracing project // from the 《ray tracing the next week》 // ----------------------------------------------------- #pragma once namespace rt { class checker_texture :public texture { public: checker_texture() { } checker_texture(texture* t1, texture* t2); virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const override; private: texture* _even; texture* _odd; }; inline checker_texture::checker_texture(texture * t1, texture * t2) :_even(t1) , _odd(t2) { } rtvec checker_texture::value(rtvar u, rtvar v, const rtvec& p)const { rtvar sines = sin(30 * p.x()) * sin(30 * p.y()) * sin(30 * p.z()); if (sines < 0) return _odd->value(u, v, p); else return _even->value(u, v, p); } }
我們把大球設置為棋盤紋理
就是開篇圖
然后,我把判別式中的10改成了30依舊是原圖
10(左)30(右)
y = sin(wx + φ)
你可以嘗試改動一下φ參數試一下
補充:
使用
使得紋理向屏幕左部偏移了一段距離
下面是另外一個圖:
隨機球體生成函數改成
相機參數依舊是之前的
會得到這樣一個圖
感謝您的閱讀,生活愉快~