《一周學完光線追蹤》學習 九 電介質材料

2021-10-06 15:48:25 字數 3265 閱讀 4839

蒙特卡洛光線追蹤技術系列 見 蒙特卡洛光線追蹤技術

透明材料如水、玻璃和鑽石都是電介質。當光線擊中它們時,它**成反射光線和折射(透射)光線。我們將通過在反射或折射之間隨機選擇並在每次互動中僅生成乙個散射光線來處理該問題。

最難除錯的部分是折射光線。如果有折射光線的話,我通常先讓所有的光線折射。為了這個專案,我試著在我們的場景中放兩個玻璃球,我得到了這個:

對嗎?玻璃球在現實生活中看起來很奇怪。但不,這是不對的。世界應該顛倒過來,不要有奇怪的黑色東西。我剛剛把光線直接從影象中間列印出來,顯然是錯誤的。這經常起作用。

折射率用snell定律描述:n sin(θ)=n'sin(θ')

其中n和n'是折射率(通常為空氣=1,玻璃=1.3-1.7,金剛石=2.4),幾何結構為:

乙個棘手的實際問題是,當光線位於折射率較高的材料中時,snell定律沒有真正的解,因此就不可能有折射。這裡所有的光都被反射,因為在實際中通常是在固體物體內部,所以稱為「全內反射」。這就是為什麼有時當你被淹沒時,水-空氣邊界就像一面完美的鏡子。因此,折射**比反射**要複雜一些:

inline bool refract(const vec3&v, const vec3 &n, float ni_over_nt, vec3& refracted) 

else

return false;

}

在可能的情況下總是折射的介電材料是:

class dielectric :public material 

virtual bool scatter(const ray&r_in, const hit_record&rec, vec3& attenuation, ray& scattered)const

else

if (refract(r_in.direction(), outward_normal, ni_over_nt, refracted))

else

return true;

} float ref_idx;

};

衰減總是1-玻璃表面不吸收任何東西。

如果我們用這些引數來嘗試:

list[0] = new sphere(vec3(0, 0, -1.0), 0.5, new lambertian(vec3(0.8,0.3,0.3)));

list[1] = new sphere(vec3(0.0, -100.5, -1.0), 100, new lambertian(vec3(0.8, 0.8, 0.0)));

list[2] = new sphere(vec3(1.0, 0.0, -1.0), 0.5, new metal(vec3(0.8, 0.6, 0.2),0.1));

list[3] = new sphere(vec3(-1.0, 0.0, -1.0), 0.5, new dielectric(1.5));

就能得到如圖所示的結果:

注意,和書上給的結果不一樣(待會我們再來查明):

(讀者貝克指出,當存在反射光線時,函式返回false,因此沒有反射。)。他是對的,這就是為什麼上面的裡沒有(就是說直接在程式的判斷中為錯就截止了)。我把這個留在這裡,而不是糾正這個,因為這是乙個非常有趣的例子,乙個主要的錯誤仍然留下乙個合理的效果。這些潛藏的bug是最難找到的bug,因為我們人類的設計並不是為了找出我們所看到的東西的毛病。)

現在,真正的玻璃具有隨角度變化的反射率——以乙個比較陡峭的角度看乙個視窗,它就會變成一面鏡子。有乙個很難看的方程來描述這個反射率,但是現在幾乎每個人都使用乙個簡單的多項式近似,這是克里斯托夫·施利克(christophe schlick)提出的:

float schlick(float cosine, float ref_idx)
這就產生了我們的全玻璃材料:

class dielectric :public material 

virtual bool scatter(const ray&r_in, const hit_record&rec, vec3& attenuation, ray& scattered)const

else

if (refract(r_in.direction(), outward_normal, ni_over_nt, refracted))

else

if (rand() / (rand_max + 1.0) < reflect_prob)

else

return true;

} float ref_idx;

};

使用電介質球的乙個有趣且簡單的技巧是,如果使用負半徑,則幾何體不受影響,但曲面法線指向內部,因此可以將其用作氣泡來製作空心玻璃球:

list[0] = new sphere(vec3(0, 0, -1.0), 0.5, new lambertian(vec3(0.8,0.3,0.3)));

list[1] = new sphere(vec3(0.0, -100.5, -1.0), 100, new lambertian(vec3(0.8, 0.8, 0.0)));

list[2] = new sphere(vec3(1.0, 0.0, -1.0), 0.5, new metal(vec3(0.8, 0.6, 0.2),0.1));

list[3] = new sphere(vec3(-1.0, 0.0, -1.0), 0.5, new dielectric(1.5));

list[4] = new sphere(vec3(-1.0, 0.0, -1.0), -0.45, new dielectric(1.5));

可以得到:

注意和書上還是不一樣:

下一節我們把這段程式好好研究研究,看看到底**有差錯。

《一周學完光線追蹤》學習 六 抗鋸齒

蒙特卡洛光線追蹤技術系列 見 蒙特卡洛光線追蹤技術 當乙個真正的相機拍攝一張 通常沒有沿邊緣的鋸齒,因為邊緣畫素是一些前景和一些背景的混合。我們可以通過平均每個畫素內的一組樣本來獲得相同的效果。我們不必為分層而煩惱,這是有爭議的,但對我的節目來說卻是司空見慣的。對於某些光線 來說,這是非常關鍵的,但...

《一周學完光線追蹤》學習 三 光線相機和背景

蒙特卡洛光線追蹤技術系列 見 蒙特卡洛光線追蹤技術 所有光線 都有乙個光線類,以及計算沿光線看到的顏色。讓我們把射線看作乙個函式,p t a t b,這裡p是3d中沿直線的3d位置,a是射線的原點,b是射線的方向。射線引數t是實數 中的浮點數 插入不同的t和p t 沿射線移動點。加上負t,你就可以得...

《一周學完光線追蹤》學習 十一 離焦模糊

蒙特卡洛光線追蹤技術系列 見 蒙特卡洛光線追蹤技術 現在我們的最後乙個特點 離焦模糊。注意,所有的攝影師都會稱之為 景深 所以請注意,只有在朋友之間使用 離焦模糊 在真正的相機中,我們使焦距模糊的原因是因為它們需要乙個大洞 而不僅僅是乙個針孔 來收集光線。這會使所有的東西都散焦,但是如果我們把乙個鏡...