轉載自: 羊羊2035
原文:幾何向量:計算光線折射refract向量
光線折射的產生,其實是因爲光線通過不同介質所產生的“偏折”現象。
ps:一般情況下,我們認爲真空中(或者說空氣中)折射率n = 1,畢竟我們起碼要選取一個標準閥值,來推導其他介質的折射率,這裏直接規定真空(空氣)爲標準1,那麼其他介質的折射率都比真空要大,也就是>1。
我們通過建立單位圓輔助計算,通過標量推導出向量的模長,然後通過向量平行和同異方向推導出向量,推出OB = OD + DB = -|cosβ|OE + |sinβ/sinθ|(AO + |cosθ|* OE),推導到這裏,我們就把OB的公式用cos sin以及入射光向量AO和介質法向量N來計算了,這時候我們就思考如何計算cosβ cosθ,讓這兩個值使用已知的n1,n2,AO,OE來替換,如下圖:
我們通過斯涅爾定律:n1 * sinθ = n2 * sinβ得到sinβ = n1/n2 * sinθ
點積的概念推出cosθ
cosβ的推導可以先試用sinβ替換,然後替換斯涅爾定律中計算的sinβ得到cosθ的表示,
這個時候我們所有的未知量就全部通過已知值(n1,n2,AO,OE)來表示了,如下圖
代碼實現:
// Snell's law
// https://blog.csdn.net/yinhun2012/article/details/79472364
Vec3f refract(const Vec3f& I, const Vec3f& N,float &refractive_index) {
float cosi = -std::max(-1.0f, std::min(1.f, I*N));
float etai = 1, etat = refractive_index;
Vec3f n = N;
if (cosi < 0) {
// if the ray is inside the object,
// swap the indices and invert the normal to get the correct result
cosi = -cosi;
std::swap(etai, etat); n = -N;
}
float eta = etai / etat;
float k = 1 - eta*eta*(1 - cosi*cosi);
return k < 0 ? Vec3f(0, 0, 0) : I*eta + n*(eta * cosi - sqrtf(k));
}