計(jì)算機(jī)圖形學(xué)基礎(chǔ)(二):光線追蹤(Ray Tracing)

所有專欄系列的內(nèi)容均為本人(b站id:寧牁兒)精心總結(jié)和排版,僅用于免費(fèi)學(xué)習(xí)交流,任何人不得擅自用于商業(yè)活動(dòng)

計(jì)算機(jī)圖形計(jì)算的最基本任務(wù)之一就是渲染三維物體。模型是用特定語(yǔ)言或者數(shù)據(jù)結(jié)構(gòu)對(duì)于三維物體的描述,包括幾何形狀、視點(diǎn)、紋理以及照明信息等。渲染就是將三維場(chǎng)景中的模型,按照設(shè)定好的環(huán)境、燈光、材質(zhì)及渲染參數(shù),二維投影成數(shù)字圖像的過(guò)程。
從數(shù)學(xué)角度上來(lái)說(shuō),渲染就是接收一堆物體的數(shù)字集合作為輸入,產(chǎn)生出一些像素點(diǎn)的矩陣作為輸出。我們需要考慮每個(gè)物體對(duì)最后輸出的每個(gè)像素點(diǎn)有什么影響,通常有兩種渲染方式:
1. 按物體順序渲染(object-order rendering)。輪詢每個(gè)物體對(duì)象,考察每個(gè)對(duì)象影響了哪些像素的值并依次更新這些像素值
2. 按圖像順序渲染(image-order rendering)。輪詢每個(gè)像素,考察每個(gè)像素會(huì)被哪些物體影響并計(jì)算最終的像素值
上述兩種渲染方式能產(chǎn)生相同的結(jié)果,對(duì)3D渲染來(lái)說(shuō),光線追蹤就是一種image-order rendering的渲染算法。
本章涉及到的數(shù)學(xué)知識(shí)點(diǎn)回顧:
笛卡爾坐標(biāo)系中,給定兩點(diǎn)
和
,
可以表示從點(diǎn)
出發(fā)指向點(diǎn)
的向量

基礎(chǔ)光線追蹤算法
光線追蹤器(ray tracer)的基礎(chǔ)工作就是每次計(jì)算一個(gè)像素,考察圖像中該像素位置能觀測(cè)到的物體。以特定的像素位為觀測(cè)點(diǎn)(下圖中眼睛的位置),視線(ray)可能會(huì)和多個(gè)物體相交(T2,T1),我們只關(guān)心那個(gè)離觀測(cè)點(diǎn)最近的物體(T2),因?yàn)樗竺娴奈矬w(T1)會(huì)被其遮擋住。一旦找到了這個(gè)物體(T2),就使用交點(diǎn)、表面法線和其它信息來(lái)進(jìn)行著色計(jì)算(shading computation)來(lái)決定最終該像素點(diǎn)的值:

因此,一個(gè)基礎(chǔ)光線追蹤器包括三個(gè)部分:
光線生成(計(jì)算觀測(cè)光線)
光線相交計(jì)算
著色
用偽代碼來(lái)描述這一算法過(guò)程:
透視
計(jì)算機(jī)產(chǎn)生以前,使用2D的圖像來(lái)表示3D的物體場(chǎng)景的方法已經(jīng)被各路藝術(shù)家研究過(guò),如立體繪畫、魚眼鏡頭、外圍攝像機(jī),其中大部分方法都是線性透視:3D的物體投影到一個(gè)平面上,保證場(chǎng)景內(nèi)的直線在圖像中呈現(xiàn)的仍然是直線。
最簡(jiǎn)單的投影方法是平行投影:3D的點(diǎn)沿著投影方向移動(dòng)到與圖像平面相交,從而映射到2D的平面上。最終產(chǎn)生的視圖由投影方向和圖像平面位置決定:如果圖像平面和觀測(cè)方向垂直,那么這個(gè)投影就被稱作正交的(orthographic),否則就被稱作斜交的(oblique)。但在日常生活經(jīng)驗(yàn)中,更遠(yuǎn)處的物體看起來(lái)更小,因?yàn)槲覀兊难劬Σ皇菑膯我环较蚴占饩€的,而是從一個(gè)特定的點(diǎn),這就是透視投影:讓投影沿著的線都是經(jīng)過(guò)某一個(gè)點(diǎn)(視點(diǎn)),透視投影的視圖是通過(guò)視點(diǎn)位置和圖像平面位置決定的。
計(jì)算觀測(cè)光線
基于正交基的計(jì)算方法需要建立一個(gè)光線的數(shù)學(xué)表示,一條光線其實(shí)就是一個(gè)起點(diǎn)和一個(gè)傳播方向。一條三維直線,從觀測(cè)點(diǎn)出發(fā)并經(jīng)過(guò)圖像平面上一點(diǎn)
可以表示為:
其中向量的方向從點(diǎn)
指向點(diǎn)
,可以理解為,從點(diǎn)
出發(fā),沿著向量
的方向前進(jìn),經(jīng)過(guò)
個(gè)單位向量長(zhǎng)度,到達(dá)了點(diǎn)
,由所有符合此表達(dá)式的點(diǎn)
所組成的直線,就是所要計(jì)算的觀測(cè)光線,其方向與向量
同向:

可以注意到,,
,并且,如果
,則點(diǎn)
相比點(diǎn)
來(lái)說(shuō)更加接近于觀測(cè)點(diǎn);如果
,則點(diǎn)
在眼睛的后方。在OOP編程中,想要將此表達(dá)式表示為一個(gè)類的函數(shù),大致是:
要計(jì)算一條觀測(cè)光線,最常見的構(gòu)建正交直角坐標(biāo)系的方法就是以視點(diǎn)為原點(diǎn),觀測(cè)方向是
,垂直觀測(cè)方向向上是
,另一個(gè)基向量則為
,如下圖所示:

正交視圖
對(duì)于正交視圖來(lái)說(shuō),所有光線的方向都是。視圖光線應(yīng)該從點(diǎn)
和向量
和
所在的平面出發(fā),現(xiàn)在還需要的就是圖像平面的位置信息??梢杂盟臈l邊來(lái)表示圖像平面在
和
方向上的邊界:
和
分別表示圖像的左右邊界,
和
分別表示圖像的上下邊界,一般情況下會(huì)有:
且
:

假設(shè)我們現(xiàn)在需要在這個(gè)大小為的連續(xù)平面上擬合出一張像素大小為
的圖像,則垂直方向上的像素點(diǎn)間隔為
,水平方向上的像素點(diǎn)間隔為
,并且像素點(diǎn)處于每一個(gè)像素網(wǎng)格的中心。所以,假設(shè)某一像素點(diǎn)的索引坐標(biāo)為
,在
平面上的實(shí)際實(shí)數(shù)域坐標(biāo)為
,坐標(biāo)系原點(diǎn)為
,
方向的單位向量分別為
,則有:
給定一個(gè)像素點(diǎn)$(i,j)$,現(xiàn)在可以計(jì)算觀測(cè)光線的出發(fā)點(diǎn)(O)和光線方向(D)了:
所以,正交視圖的觀測(cè)光線可表示為:
透視視圖
明白了正交視圖的計(jì)算方法后,透視視圖的計(jì)算方法就簡(jiǎn)單了,所有的光線擁有相同的起點(diǎn),即視點(diǎn)。但是對(duì)于不同的像素點(diǎn),光線方向不同,由于最后的圖像和視點(diǎn)位置有關(guān),假設(shè)視點(diǎn)
到圖像平面的距離為
,此時(shí)觀測(cè)光線的出發(fā)點(diǎn)(O)和光線方向(D)為:

故透視視圖的觀測(cè)光線可表示為:
光線相交計(jì)算
現(xiàn)在已經(jīng)得到了正交和透視視圖的觀測(cè)光線的計(jì)算方法,接下來(lái)需要找到光線在的范圍內(nèi)與物體的第一個(gè)交點(diǎn),也就是說(shuō),尋找光線在區(qū)間
的
處與物體表面的第一個(gè)交點(diǎn)。
與球體的相交計(jì)算
假設(shè)一個(gè)球體的中心點(diǎn)為,半徑為
,對(duì)一個(gè)球面上的任意一點(diǎn)
,可表示為:
故,對(duì)于觀測(cè)光線上一點(diǎn),只要滿足上式,就是該光線與球面的交點(diǎn),將
代入上式:
整理可得,
這個(gè)式子是一個(gè)關(guān)于的一元二次方程,根據(jù)求根公式
,可以得到:
如果兩個(gè)解中更小的解在區(qū)間內(nèi),那么更小的解是交點(diǎn),否則更大的解是交點(diǎn)。若兩者都不在區(qū)間內(nèi),則該觀測(cè)光線在此區(qū)間內(nèi)與該球體沒有交點(diǎn)。
與三角形平面的相交計(jì)算
假設(shè)一個(gè)三角形的三個(gè)頂點(diǎn)分別為,那三角形內(nèi)部的任何一點(diǎn)
都可以描述為:
那么觀測(cè)光線與三角形內(nèi)部某點(diǎn)相交就可以寫成:
轉(zhuǎn)換成三維坐標(biāo)值的形式就是一個(gè)方程組:
再轉(zhuǎn)換成標(biāo)準(zhǔn)的線性系統(tǒng):
其中均為未知數(shù),求解3*3的線性方程組經(jīng)典方法是克萊姆法則,推導(dǎo)過(guò)程比較復(fù)雜在此省略,直接給出解,對(duì)于一個(gè)方程組:
它的解為:
當(dāng)然,得到的解應(yīng)該滿足,否則代表該光線在該三角形內(nèi)部沒有交點(diǎn)。
代碼表示
在OOP編程中,可以把此求交點(diǎn)的函數(shù)放在物體表面類中:
當(dāng)物體不止一個(gè)時(shí),我們需要找到沿著光線距離觀測(cè)點(diǎn)最近的那個(gè)交點(diǎn),最簡(jiǎn)單方法是將一組物體本身看作另一個(gè)物體: