一、理論基礎(chǔ)
1、三維場(chǎng)景中創(chuàng)建圖像
第一步:透視投影。這是一個(gè)將三維物體的形狀投影到圖像表面上的幾何過(guò)程,這一步只需要連接從對(duì)象特征到眼睛之間的線,然后在畫(huà)布上繪制這些投影線與圖像平面相交的輪廓。
第二步:添加顏色。圖像輪廓繪制好之后,給它的骨架添加顏色,這樣就完成了三維場(chǎng)景中的圖像創(chuàng)建過(guò)程。
2、物體的顏色和亮度
? 主要是光線與物體材質(zhì)相互作用的結(jié)果。
? 光由光子(電磁粒子)組成,光子由各種光源發(fā)射。當(dāng)一組光子撞擊一個(gè)物體時(shí),可能發(fā)生三種情況:被吸收,反射或透射。發(fā)生這三種情況的光子百分比因材料而異,通常決定了物體在場(chǎng)景中的顯現(xiàn)方式。然而,所有材料都有一個(gè)共性:入射光子總數(shù)總是與反射光子、吸收光子、透射光子的總和相同。
? 白光由“紅”、“藍(lán)”、“綠”三種顏色光子組成。當(dāng)白光照亮紅色物體時(shí),光子吸收過(guò)程會(huì)過(guò)濾掉“綠色”和“藍(lán)色”光子。因?yàn)槲矬w不吸收“紅色”光子,所以它們將被反射,這就是物體呈現(xiàn)紅色的原因。
? 我們之所以能夠看到物體,是因?yàn)槲矬w反射的一些光子向我們傳播并擊中了我們的眼睛。我們的眼睛由光感受器組成,可以將光信號(hào)轉(zhuǎn)換為神經(jīng)信號(hào),然后我們的大腦能夠使用這些信號(hào)來(lái)辨別不同的陰影和色調(diào)。
3、光與物體的關(guān)系
? 沒(méi)有光線,我們都看不到周?chē)奈矬w。
? 周?chē)h(huán)境中沒(méi)有物體,我們看不到光。
1、Forward Tracing
在用計(jì)算機(jī)生成的圖像中模擬光與物體相互作用過(guò)程之前,我們需要了解一個(gè)物理現(xiàn)象。一束光線照射在物體上時(shí),反射的光子中只有少數(shù)會(huì)到達(dá)我們眼睛的表面。想象一下,假設(shè)有一個(gè)每次只發(fā)射一個(gè)光子的光源,光子從光源發(fā)出并沿著直線路徑行進(jìn),直至撞擊到物體表面,忽略光子的吸收,該光子會(huì)以隨機(jī)的方向反射。如果光子撞擊到我們的眼睛表面,則我們會(huì)看到光子被反射的點(diǎn)。具體過(guò)程如下圖所示。
現(xiàn)在從計(jì)算機(jī)圖形的角度來(lái)看待這種情況。首先,我們用像素組成的平面代替我們的眼睛。在這種情況下,發(fā)射的光子將撞擊圖形平面上許多像素的一個(gè),并將該點(diǎn)的亮度增加到大于零的值。重復(fù)多次直到所有的像素被調(diào)整,創(chuàng)建一個(gè)計(jì)算機(jī)生成的圖像。這種技術(shù)稱為前向光線追蹤(Forward Tracing),因?yàn)槲覀兪茄刂庾訌墓庠聪蛴^察者的前進(jìn)的路徑。
但是,這種技術(shù)在計(jì)算機(jī)中模擬光子與物體相互作用是不太現(xiàn)實(shí)的,因?yàn)樵趯?shí)際中反射的光子擊中眼睛表面的可能性是非常非常低的,我們必須投射大量的光子才能找到一個(gè)能夠引起眼睛注意的。此外,我們也不能保證物體的表面被光子完全覆蓋,這是這項(xiàng)技術(shù)的主要缺點(diǎn)。
換句話說(shuō),我們可能不得不讓程序一直運(yùn)行,直到足夠的光子噴射到物體的表面上獲得精確的顯示。這意味著我們要監(jiān)視正在呈現(xiàn)的圖像以決定何時(shí)停止應(yīng)用程序。這在實(shí)際生產(chǎn)環(huán)境中是不可能的。另外,正如我們將看到的,射線追蹤器中最昂貴的任務(wù)是找到射線幾何交點(diǎn)。從光源產(chǎn)生大量光子不是問(wèn)題,但是在場(chǎng)景內(nèi)找到所有的交點(diǎn)將會(huì)是非常昂貴的。
2、Backward Tracing
這項(xiàng)技術(shù)為前向光線追蹤技術(shù)的缺陷提供了一個(gè)方便的解決方案。由于我們的模擬不能像自然一樣快速完美,所以我們必須妥協(xié),并追蹤從眼睛進(jìn)入到場(chǎng)景中的光線。
光線照到一個(gè)物體時(shí),我們可以通過(guò)將另一條光線(稱為光線或陰影光線)從擊中點(diǎn)投射到場(chǎng)景的光線,得到它所接受到的光子數(shù)量。這個(gè)“光線”有的時(shí)候會(huì)被另一個(gè)物體阻擋,這意味著我們?cè)瓉?lái)的撞擊點(diǎn)在陰影中,沒(méi)有獲得任何照明。
三、算法實(shí)現(xiàn)
1、基本原理
? 光線追蹤算法采用由像素組成的圖像。對(duì)于圖像中的每個(gè)像素,它將主光線投射到場(chǎng)景中。該主光線的方向是通過(guò)追蹤從眼睛到像素中心線獲得的。一旦我們確定了主射線的方向,我們就開(kāi)始檢查場(chǎng)景中的每個(gè)對(duì)象,看它是否與其中的任何一個(gè)相交。當(dāng)發(fā)生主射線與多個(gè)對(duì)象相交的情況時(shí),我們選擇交點(diǎn)離眼睛最近的物體。
? 然后,我們從交叉點(diǎn)向光線投射陰影射線。如果這條特定的光線在通往光源的路上不與某個(gè)物體相交,那么這個(gè)點(diǎn)就被照亮了。
? 如果它與另一個(gè)物體相交,則該物體在其上投下陰影。
? 最后,如果我們對(duì)每個(gè)像素重復(fù)這一操作,就可以獲得三維場(chǎng)景的二維表示。
2、偽代碼
光線追蹤算法實(shí)現(xiàn)的偽代碼如下所示:
for (int j = 0; j < imageHeight; ++j) { ? ?for (int i = 0; i < imageWidth; ++i) { ? ? ? ?// compute primary ray direction ? ? ? ?Ray primRay; ? ? ? ?computePrimRay(i, j, &primRay); ? ? ? ?// shoot prim ray in the scene and search for intersection ? ? ? ?Normal nHit; ? ? ? ?float minDist = INFINITY; ? ? ? ?Object object = NULL; ? ? ? ?for (int k = 0; k < objects.size(); ++k) { ? ? ? ? ? ?if (Intersect(objects[k], primRay, &pHit, &nHit)) { ? ? ? ? ? ? ? ?float distance = Distance(eyePosition, pHit); ? ? ? ? ? ? ? ?if (distance < minDistance) { ? ? ? ? ? ? ? ? ? ?object = objects[k]; ? ? ? ? ? ? ? ? ? ?minDistance = distance; // update min distance ? ? ? ? ? ? ? ?} ? ? ? ? ? ?} ? ? ? ?} ? ? ? ?if (object != NULL) { ? ? ? ? ? ?// compute illumination ? ? ? ? ? ?Ray shadowRay; ? ? ? ? ? ?shadowRay.direction = lightPosition - pHit; ? ? ? ? ? ?bool isShadow = false; ? ? ? ? ? ?for (int k = 0; k < objects.size(); ++k) { ? ? ? ? ? ? ? ?if (Intersect(objects[k], shadowRay)) { ? ? ? ? ? ? ? ? ? ?isInShadow = true; ? ? ? ? ? ? ? ? ? ?break; ? ? ? ? ? ? ? ?} ? ? ? ? ? ?} ? ? ? ?} ? ? ? ?if (!isInShadow) ? ? ? ? ? ?pixels[i][j] = object->color * light.brightness; else pixels[i][j] = 0; } }
四、加入反射和折射
1、基本原理
在光學(xué)中,反射和折射是總所周知的現(xiàn)象。反射和折射分向都是基于相交點(diǎn)處的法線和入射光線(主光線)的方向。為了計(jì)算折射方向,我們還需指定材料的折射率。
同樣,我們也必須意識(shí)到像玻璃球這樣的物體同時(shí)具有反射性和折射性的事實(shí)。我們需要為表面上的給定點(diǎn)計(jì)算兩者的混合值。反射和折射具體值的混合取決于主光線(或觀察方向)和物體的法線和折射率之間的夾角。有一個(gè)方程式精確地計(jì)算了每個(gè)應(yīng)該如何混合,這個(gè)方程被稱為菲涅耳方程。
加入反射折射后,進(jìn)行以下三個(gè)步驟:
? 計(jì)算反射
為此,我們需要兩個(gè)項(xiàng):交點(diǎn)處的法線和主光線的方向。一旦我們獲得了反射方向,我們就朝這個(gè)方向發(fā)射新的光線。我們假設(shè)反射光線撞擊了紅色球體,通過(guò)向光線投射陰影射線來(lái)找出到達(dá)紅色球體上的那個(gè)點(diǎn)的光線多少。這會(huì)得到一種顏色(如果是陰影,則為黑色),然后乘以光強(qiáng)并返回到玻璃球的表面。
? 計(jì)算折射
注意,因?yàn)楣饩€穿過(guò)玻璃球,所以它被認(rèn)為是透射光線(光線從球體的一側(cè)傳播到另一側(cè))。為了計(jì)算透射方向,我們需要在知道擊中點(diǎn)的法線,主射線方向和材料的折射率。
當(dāng)光線進(jìn)入并離開(kāi)玻璃物體時(shí),光線的方向會(huì)改變。每當(dāng)介質(zhì)發(fā)生變化時(shí)都會(huì)發(fā)生折射,而且兩種介質(zhì)具有不同的折射率。折射對(duì)光線有輕微彎曲的作用。這個(gè)過(guò)程就是讓物體在透視時(shí)或在不同折射率的物體上出現(xiàn)偏移的原因。
現(xiàn)在讓我們想象一下,當(dāng)折射的光線離開(kāi)玻璃球時(shí),它會(huì)碰到一個(gè)綠色的球體。在那里,我們?cè)俅斡?jì)算綠色球體和折射射線之間交點(diǎn)處的局部照明(通過(guò)拍攝陰影射線)。然后,將顏色(如果被遮擋,則為黑色)乘以光強(qiáng)并返回到玻璃球的表面。
? 應(yīng)用菲涅爾方程
我們需要玻璃球的折射率,主光線的角度,以及擊中點(diǎn)的法線。使用點(diǎn)積,菲涅耳方程返回兩個(gè)混合值。
這種算法的美妙之處在于它是遞歸的。迄今為止,在我們研究過(guò)的情況下,反射光線照射到一個(gè)紅色的、不透明的球體上,而折射光線照射到一個(gè)綠色的、不透明的和漫射的球體上。但是,我們會(huì)想象紅色和綠色的球體也是玻璃球。為了找到由反射和折射光線返回的顏色,我們必須按照與原始玻璃球一起使用的紅色和綠色球體的相同過(guò)程。
這是光線追蹤算法的一個(gè)嚴(yán)重缺陷。想象一下,我們的相機(jī)是在一個(gè)只有反射面的盒子里。從理論上講,光線被困住了,并且會(huì)持續(xù)不斷地從箱子的墻壁反彈(或者直到你停止模擬)。出于這個(gè)原因,我們必須設(shè)置一個(gè)任意的限制值,從而防止光線相互作用導(dǎo)致的無(wú)限遞歸。每當(dāng)光線反射或折射時(shí),其深度都會(huì)增加。當(dāng)光線深度大于最大遞歸深度時(shí),我們就停止遞歸過(guò)程。
2、偽代碼
偽代碼如下所示:
// compute reflection color color reflectionCol = computeReflectionColor(); // compute refraction color color refractionCol = computeRefractionColor(); float Kr; // reflection mix value float Kt; // refraction mix value fresnel(refractiveIndex, normalHit, primaryRayDirection, &Kr, &Kt); // mix the two color glassBallColorAtHit = Kr * reflectionColor + (1-Kr) * refractionColor;
-
算法
+關(guān)注
關(guān)注
23文章
4625瀏覽量
93123 -
圖像
+關(guān)注
關(guān)注
2文章
1088瀏覽量
40515 -
光線追蹤
+關(guān)注
關(guān)注
0文章
183瀏覽量
21509
原文標(biāo)題:計(jì)算機(jī)圖形學(xué)——光線追蹤(RayTracing)算法
文章出處:【微信號(hào):Imgtec,微信公眾號(hào):Imagination Tech】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論