計(jì)算機(jī)圖形學(xué)入門(3D渲染指南)_第1頁(yè)
計(jì)算機(jī)圖形學(xué)入門(3D渲染指南)_第2頁(yè)
計(jì)算機(jī)圖形學(xué)入門(3D渲染指南)_第3頁(yè)
計(jì)算機(jī)圖形學(xué)入門(3D渲染指南)_第4頁(yè)
計(jì)算機(jī)圖形學(xué)入門(3D渲染指南)_第5頁(yè)
已閱讀5頁(yè),還剩182頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

計(jì)算機(jī)圖形學(xué)入門3D渲染指南目錄TOC\h\h第1章基礎(chǔ)入門概念\h1.1畫布\h坐標(biāo)系\h1.2顏色模型\h1.2.1減色法模型\h1.2.2加色法模型\h1.2.3忽略細(xì)節(jié)\h1.3顏色深度和顏色表示法\h1.4顏色的處理方法\h1.5場(chǎng)景\h1.6總結(jié)\h第一部分光線追蹤\h第2章基礎(chǔ)光線追蹤知識(shí)\h2.1渲染一幅瑞士風(fēng)景圖\h2.2基本假設(shè)\h2.3畫布空間到視口空間\h2.4追蹤射線\h2.4.1射線方程\h2.4.2球體方程\h2.4.3射線與球體相交\h2.5渲染我們的第一組球體\h2.6總結(jié)\h第3章光\h3.1簡(jiǎn)化的假設(shè)\h3.2光源\h3.2.1點(diǎn)光\h3.2.2方向光\h3.2.3環(huán)境光\h3.3單點(diǎn)光照\(chéng)h3.4漫反射\h3.4.1對(duì)漫反射的建模\h3.4.2漫反射方程\h3.4.3球體的法線\h3.4.4漫反射的渲染\h3.5鏡面反射\h3.5.1對(duì)鏡面反射的建模\h3.5.2鏡面反射的計(jì)算項(xiàng)\h3.5.3完整的光照方程\h3.5.4鏡面反射的渲染\h3.6總結(jié)\h第4章陰影和反射\h4.1陰影\h4.1.1理解陰影\h4.1.2包含陰影的渲染\h4.2反射\h4.2.1鏡子和反射\h4.2.2包含反射的渲染\h4.3總結(jié)\h第5章擴(kuò)展光線追蹤渲染器\h5.1任意相機(jī)定位\h5.2性能優(yōu)化\h5.2.1并行運(yùn)算\h5.2.2緩存不變值\h5.2.3陰影的優(yōu)化\h5.2.4空間結(jié)構(gòu)\h5.2.5子采樣\h5.3支持其他圖元\h5.4體素構(gòu)造表示法\h5.5透明度\h光線折射\h5.6超采樣\h5.7總結(jié)\h第二部分光柵化\h第6章直線\h6.1描述直線\h6.2繪制直線\h6.3繪制任意斜率的直線\h6.4線性插值函數(shù)\h6.5總結(jié)\h第7章填充三角形\h7.1繪制線框三角形\h7.2繪制填充三角形\h7.3總結(jié)\h第8章著色三角形\h8.1定義問(wèn)題\h8.2計(jì)算邊緣著色\h8.3計(jì)算內(nèi)部著色\h8.4總結(jié)\h第9章透視投影\h9.1基本假設(shè)\h9.2查找P'點(diǎn)\h9.3透視投影方程\h9.4透視投影方程的性質(zhì)\h9.5投影我們的第一個(gè)3D物體\h9.6總結(jié)\h第10章場(chǎng)景的描述和渲染\h10.1表示一個(gè)立方體\h10.2模型和模型實(shí)例\h10.3模型變換\h10.4相機(jī)變換\h10.5變換矩陣\h10.6齊次坐標(biāo)\h10.6.1齊次旋轉(zhuǎn)矩陣\h10.6.2齊次縮放矩陣\h10.6.3齊次平移矩陣\h10.6.4齊次投影矩陣\h10.6.5齊次視口-畫布變換矩陣\h10.7回顧變換矩陣\h10.8總結(jié)\h第11章裁剪\h11.1裁剪過(guò)程概述\h11.2裁剪體\h11.3使用平面裁剪場(chǎng)景\h11.4定義裁剪平面\h11.5裁剪整個(gè)物體\h11.6裁剪三角形\h線段與平面的交點(diǎn)\h11.7裁剪過(guò)程的偽代碼\h11.8渲染管線中的裁剪過(guò)程\h11.9總結(jié)\h第12章移除隱藏表面\h12.1渲染實(shí)體物體\h12.2畫家算法\h12.3深度緩沖\h使用1/z代替z\h12.4背面剔除\h三角形的分類\h12.5總結(jié)\h第13章著色\h13.1著色與光照\(chéng)h13.2扁平化著色\h13.3高洛德著色\h13.4馮氏著色\h13.5總結(jié)\h第14章紋理\h14.1繪制木條箱\h14.2雙線性濾波\h14.3貼圖分級(jí)細(xì)化\h14.4三線性濾波\h14.5總結(jié)\h第15章擴(kuò)展光柵化渲染器\h15.1法線映射\h15.2環(huán)境映射\h15.3陰影\h15.3.1模板陰影\h15.3.2陰影映射\h15.4總結(jié)\h附錄線性代數(shù)第1章基礎(chǔ)入門概念光線追蹤渲染器和光柵化渲染器采用不同的方法將3D場(chǎng)景渲染到2D屏幕上。但是,這兩種方法有一些共同的基本概念。在本章中,我們將探索畫布(canvas),這是一個(gè)抽象表面,我們將在其上渲染圖像。我們還將探索坐標(biāo)系(coordinatesystem),我們將通過(guò)它來(lái)“引用”畫布上的像素(pixel)。我們將學(xué)習(xí)如何表示和處理顏色,以及學(xué)習(xí)如何描述一個(gè)3D場(chǎng)景,以便我們的渲染器可以使用它。1.1畫布在本書中,我們將在畫布上繪制東西:畫布是一個(gè)矩形像素陣列,我們可以單獨(dú)設(shè)置每一個(gè)像素的顏色。我們并不關(guān)心畫布是顯示在屏幕上還是印刷在紙上。我們的目標(biāo)是在2D畫布上呈現(xiàn)一個(gè)3D場(chǎng)景,所以我們把精力集中于在這個(gè)抽象的矩形像素陣列上進(jìn)行渲染。我們將通過(guò)一個(gè)簡(jiǎn)單的函數(shù)來(lái)延伸并構(gòu)建本書中的所有內(nèi)容,該函數(shù)可為畫布上的某一個(gè)像素設(shè)置顏色,如下面代碼所示。canvas.PutPixel(x,?y,?color)

這個(gè)函數(shù)有3個(gè)參數(shù):x坐標(biāo)、y坐標(biāo)和color(顏色值)?,F(xiàn)在讓我們先把重點(diǎn)放在坐標(biāo)上。坐標(biāo)系畫布有寬度和高度(均以像素為單位),我們稱之為和。我們需要一個(gè)坐標(biāo)系來(lái)引用畫布的像素。對(duì)于大多數(shù)計(jì)算機(jī)屏幕,坐標(biāo)原點(diǎn)位于屏幕左上角,軸向屏幕右側(cè)延伸,軸向屏幕底部延伸,如圖1-1所示。圖1-1大多數(shù)計(jì)算機(jī)屏幕采用的坐標(biāo)系考慮到視頻內(nèi)存的組織方式,這個(gè)坐標(biāo)系對(duì)于計(jì)算機(jī)來(lái)說(shuō)是非常自然、合理的,但對(duì)于人類來(lái)說(shuō)卻不是最自然、合理的使用方式。相反,3D圖形程序員傾向于使用另一種坐標(biāo)系,這也是我們通常在紙上繪制圖形時(shí)所使用的坐標(biāo)系:它的原點(diǎn)位于中心,軸“向右增大、向左減小”,而軸“向上增大、向下減小”,如圖1-2所示。圖1-2我們的畫布將采用的坐標(biāo)系使用這個(gè)坐標(biāo)系的話,軸的范圍變成,軸的范圍變成。同時(shí)我們假設(shè),當(dāng)坐標(biāo)值超出這一范圍時(shí),使用PutPixel函數(shù)沒有任何作用。在我們的示例中,畫布會(huì)被繪制在屏幕上,因此我們需要從一個(gè)坐標(biāo)系轉(zhuǎn)換到另一個(gè)坐標(biāo)系。要做到這一點(diǎn),我們需要改變坐標(biāo)系的中心,并反轉(zhuǎn)軸的方向。由此可以得到如下的轉(zhuǎn)換方程。我們假設(shè)PutPixel函數(shù)會(huì)自動(dòng)進(jìn)行這種轉(zhuǎn)換。我們可以認(rèn)為畫布的坐標(biāo)原點(diǎn)在中心,軸向屏幕右側(cè)延伸,軸向屏幕頂部延伸。讓我們?cè)賮?lái)看看PutPixel函數(shù)剩下的參數(shù):color。1.2顏色模型關(guān)于顏色如何作用的理論很吸引人,但它超出了本書的范圍。以下僅簡(jiǎn)要介紹與計(jì)算機(jī)圖形學(xué)相關(guān)的顏色理論方面的相關(guān)知識(shí)。當(dāng)光照射到我們的眼睛時(shí),它會(huì)刺激眼睛后面的感光細(xì)胞。這些細(xì)胞根據(jù)入射光的波長(zhǎng)產(chǎn)生對(duì)應(yīng)的大腦信號(hào)。我們把對(duì)這些大腦信號(hào)的主觀體驗(yàn)稱為顏色(color)。我們通??床坏讲ㄩL(zhǎng)在可見光范圍(visiblerange)以外的光。波長(zhǎng)和頻率呈反比關(guān)系(波的頻率越高,波峰之間的距離越?。?。紅外線(波長(zhǎng)大于770nm,對(duì)應(yīng)的頻率低于405THz)是無(wú)害的,而紫外線(波長(zhǎng)小于390nm,對(duì)應(yīng)的頻率高于790THz)會(huì)灼傷你的皮膚。每一種你可以想象到的顏色都可以用某些顏色的不同組合來(lái)描述。“白色”是所有顏色的總和,而“黑色”可理解為沒有任何顏色。用精確的波長(zhǎng)來(lái)描述顏色是不切實(shí)際的。幸運(yùn)的是,幾乎所有的顏色都可以由3種顏色線性組合而成,這3種顏色稱為原色(primarycolor)。1.2.1減色法模型我們?cè)谟變簳r(shí)會(huì)用蠟筆畫各種奇奇怪怪的圖形,減色法模型(subtractivecolormodel)就是我們用蠟筆所做事情的一個(gè)專業(yè)的名字。我們拿一張白紙和紅、黃、藍(lán)3種顏色的蠟筆。我們先畫一個(gè)黃色的圓圈,然后畫一個(gè)藍(lán)色的圓圈與它重疊,這樣就得到了綠色!黃色和紅色一起就會(huì)得到橙色!紅色和藍(lán)色一起就會(huì)得到紫色!將三者混合在一起,就會(huì)得到一種很暗的顏色!幼兒園是不是一個(gè)神奇的地方?圖1-3顯示了減色法模型的原色以及它們混合后得到的顏色。不同的物體有不同的顏色,因?yàn)樗鼈兾蘸头瓷涔獾姆绞讲煌N覀兿葋?lái)分析一下白光,比如陽(yáng)光(陽(yáng)光不是很白,但對(duì)我們的目的來(lái)說(shuō)已經(jīng)足夠了)。白光包含各種波長(zhǎng)的光。當(dāng)光照射到一個(gè)物體的表面時(shí),物體的表面會(huì)吸收一部分波長(zhǎng)的光,反射其他部分波長(zhǎng)的光,這取決于物體的材質(zhì)。一些反射光會(huì)進(jìn)入我們的眼睛,然后我們的大腦將其轉(zhuǎn)換成顏色。具體是什么顏色呢?就是被物體表面反射的波長(zhǎng)總和所形成的顏色。圖1-3減色法的三原色以及它們的組合那這些蠟筆是怎么回事?我們從白紙反射白光開始分析。因?yàn)槭前准?,所以它反射了大部分接收到的光。?dāng)我們用“黃色”蠟筆畫畫時(shí),我們是在紙張上添加了一層材料,這層材料可以吸收一部分波長(zhǎng)的光,但會(huì)讓其他波長(zhǎng)的光通過(guò)。這部分光經(jīng)過(guò)紙張的反射,再次穿過(guò)這一層“黃色”材料,進(jìn)入我們的眼睛,我們的大腦就把這種特定波長(zhǎng)的光組合解釋為“黃色”。這一層“黃色”材料的作用就是從原始的白光中減去(subtract)一部分波長(zhǎng)的光。我們可以把每種顏色的圓看作一個(gè)濾波器:當(dāng)我們畫一個(gè)藍(lán)色圓疊加到黃色圓上面的時(shí)候,相當(dāng)于我們從原來(lái)的光中過(guò)濾掉了更多波長(zhǎng)的光,所以進(jìn)入我們眼睛的是那些沒有被藍(lán)色或黃色的圓過(guò)濾掉的波長(zhǎng)的光,我們的大腦認(rèn)為它們是“綠色”的??傊?,我們從包含所有波長(zhǎng)的光開始,減去一部分?jǐn)?shù)量的原色,從而創(chuàng)建任何其他顏色。這種顏色模型的名字就來(lái)源于我們通過(guò)減去其中一部分波長(zhǎng)的光來(lái)創(chuàng)造顏色這樣一個(gè)事實(shí)。不過(guò),這種模型并不完全正確。其實(shí)減色法模型中的實(shí)際原色并不是教給幼兒和美術(shù)學(xué)生的藍(lán)色、紅色和黃色,而是青色(cyan,C)、品紅色(magenta,M)和黃色(yellow,Y)。此外,混合這3種原色會(huì)產(chǎn)生一種稍暗的顏色,但不是完全的黑色,因此需要添加純黑色作為第四種“原色”。因?yàn)锽已經(jīng)用于表示藍(lán)色,所以黑色(black)用K表示,因此我們得出了CMYK顏色模型(CMYKcolormodel),如圖1-4所示。圖1-4打印機(jī)使用的4種減色法原色我們可以直接在彩色打印機(jī)的墨盒上看到這種顏色模型的應(yīng)用,有時(shí)也可以在廉價(jià)的傳單上看到這種顏色模型的應(yīng)用,在廉價(jià)的傳單上,不同的顏色彼此會(huì)有略微偏移錯(cuò)位。1.2.2加色法模型減色法模型只是故事的一半。如果你曾經(jīng)近距離或用放大鏡觀察屏幕(或者,老實(shí)說(shuō),不小心對(duì)著屏幕打了個(gè)噴嚏),你可能會(huì)看到一些彩色的小點(diǎn)。它們是紅色、綠色和藍(lán)色的。屏幕與紙張是相反的。紙張不會(huì)發(fā)光,它只是反射了照射它的光的其中一部分。另一方面,屏幕本身是黑色的,但它們自身會(huì)發(fā)光。對(duì)于紙張,我們從白光開始,減去我們不想要的波長(zhǎng)的光;對(duì)于屏幕,我們從沒有光開始,然后添加(add)我們想要的波長(zhǎng)的光。為此我們需要使用不同的原色。大多數(shù)顏色可以通過(guò)在黑色表面上添加不同“數(shù)量”的紅色(red,R)、綠色(green,G)和藍(lán)色(blue,B)來(lái)創(chuàng)建,這就是RGB顏色模型(RGBcolormodel),它是一種加色法模型(additivecolormodel),如圖1-5所示。圖1-5加色法的三原色及其部分組合加色法原色的混合色會(huì)比它的各組成顏色更亮(lighter),而減色法原色的混合色會(huì)比各組成顏色更暗(darker)。所有加色法原色相加可以得到白色,而所有減色法原色相加得到的卻是黑色。1.2.3忽略細(xì)節(jié)既然大家已經(jīng)知道了所有細(xì)節(jié),那么我們就可以選擇性地忘記大部分細(xì)節(jié),專注于對(duì)我們的工作至關(guān)重要的事情。大多數(shù)顏色可以用RGB顏色模型或CMYK顏色模型(或許多其他顏色模型中的任何一種)表示,并且可以從一種顏色空間(colorspace)轉(zhuǎn)換為另一種顏色空間。由于我們專注于在屏幕上渲染東西,因此我們?cè)诒緯钠溆嗖糠质褂肦GB顏色模型。如上所述,物體吸收照射它們的部分光,反射其余的光。一些波長(zhǎng)的光被吸收,一些被反射,然后就形成了我們所感知的物體表面的“顏色”。從現(xiàn)在開始,我們將簡(jiǎn)單地把顏色看作物體表面的一種屬性,而忽略光的波長(zhǎng)。1.3顏色深度和顏色表示法顯示器通過(guò)混合不同數(shù)量的紅色、綠色和藍(lán)色來(lái)創(chuàng)建顏色。它們通過(guò)給屏幕上微小的顏色點(diǎn)提供不同的電壓,以不同的強(qiáng)度點(diǎn)亮這些微小的顏色點(diǎn),從而創(chuàng)造不同的顏色。我們可以得到多少種不同的強(qiáng)度呢?雖然電壓是連續(xù)的,但我們使用計(jì)算機(jī)來(lái)處理顏色,計(jì)算機(jī)使用的是離散值(有限數(shù)量的值)。我們可以表示的紅色、綠色和藍(lán)色的色調(diào)越多,我們就能產(chǎn)生越多的顏色?,F(xiàn)如今我們看到的大多數(shù)圖像都是使用8位二進(jìn)制數(shù)來(lái)表示一種原色,在這里我們稱原色為顏色通道(colorchannel)。每個(gè)通道使用8位二進(jìn)制數(shù)的話,對(duì)于一個(gè)像素(由3個(gè)通道組成)而言就是24位二進(jìn)制數(shù),總共有種(大約1670萬(wàn)種)不同的顏色。這種格式,稱為R8G8B8格式或簡(jiǎn)稱為888格式,是我們將在本書中使用的格式。我們認(rèn)為這種格式的顏色深度(colordepth)為24位。這絕不是唯一可能的格式。不久前,為了節(jié)省存儲(chǔ)器,15位和16位格式很受歡迎,在15位的情況下我們?yōu)槊總€(gè)通道分配5位,在16位的情況下我們?yōu)榧t色通道分配5位,為綠色通道分配6位,為藍(lán)色通道分配5位(稱為R5G6B5格式或565格式)。綠色通道得到了額外的1位,因?yàn)槲覀兊难劬?duì)綠色的變化比對(duì)紅色或藍(lán)色的變化更敏感。使用16位二進(jìn)制數(shù),我們可以獲得種(大約65000種)顏色。這意味著24位格式中每256種顏色值對(duì)應(yīng)16位格式中的1種顏色。盡管65000種顏色已經(jīng)足夠了,但對(duì)于顏色變化非常緩慢的圖像,我們將能夠看到非常微妙的“階梯”現(xiàn)象,而這在1670萬(wàn)種顏色中是看不到這種現(xiàn)象的,其中有足夠的二進(jìn)制位來(lái)表示介于兩者之間的顏色。對(duì)于一些特殊的應(yīng)用場(chǎng)合,例如電影的色彩分級(jí),最好要能夠表現(xiàn)更多的顏色細(xì)節(jié),因此每個(gè)顏色通道需要使用更多的二進(jìn)制位。我們將使用3個(gè)字節(jié)來(lái)表示一種顏色,每個(gè)字節(jié)保存從0到255的8位顏色通道的值。我們將顏色表示為(R,G,B)。例如,(255,0,0)表示純紅色;(255,255,255)表示白色;(255,0,128)表示紅紫色。1.4顏色的處理方法我們將使用一些運(yùn)算來(lái)處理顏色。如果你有一些線性代數(shù)知識(shí),你可以把顏色想象成3D顏色空間中的向量。如果沒有,請(qǐng)不要擔(dān)心,我們將介紹我們現(xiàn)在將要使用的基本操作。我們可以通過(guò)將每個(gè)顏色通道值乘一個(gè)常量來(lái)修改顏色的強(qiáng)度,如下所示。例如,顏色(32,0,128)的強(qiáng)度是顏色(16,0,64)的兩倍。我們可以通過(guò)將每個(gè)顏色通道值分別相加來(lái)將兩個(gè)顏色相加:例如,如果我們想要組合紅色(255,0,0)和綠色(0,255,0),我們將它們按通道值分別相加,得到(255,255,0),也就是黃色。這些運(yùn)算可能產(chǎn)生無(wú)效的值,例如,將(192,64,32)的強(qiáng)度增加一倍產(chǎn)生的紅色通道值(R)超出了我們的顏色范圍。我們將任何超過(guò)255的值視為255,任何低于0的值視為0,我們把這稱為將值范圍限制(clamp)為。這或多或少等同于我們?cè)诂F(xiàn)實(shí)生活中拍攝曝光不足或過(guò)度曝光的照片時(shí)所發(fā)生的情況:我們會(huì)得到全黑或全白區(qū)域。這大致就是我們對(duì)于顏色的入門知識(shí)和PutPixel函數(shù)操作的總結(jié)。在我們繼續(xù)第2章之前,讓我們花一點(diǎn)兒時(shí)間來(lái)研究如何表示要渲染的3D物體。1.5場(chǎng)景到目前為止,我們已經(jīng)介紹了畫布,就是我們可以在其上為像素著色的抽象表面?,F(xiàn)在我們引入另一個(gè)抽象概念——場(chǎng)景(scene),從而將注意力轉(zhuǎn)移到我們感興趣的要表示的物體上。場(chǎng)景是在渲染中我們感興趣的一組物體的集合。它可以代表任何事物,從飄浮在無(wú)限空曠空間中的單個(gè)球體(我們將從那里開始)到脾氣暴躁的怪獸鼻子內(nèi)部的令人難以置信的詳細(xì)模型。我們需要一個(gè)坐標(biāo)系來(lái)討論場(chǎng)景中的物體。我們不能使用與畫布相同的坐標(biāo)系,其中有兩個(gè)原因。首先,畫布是2D的,而場(chǎng)景是3D的。其次,畫布和場(chǎng)景使用不同的單位:畫布使用像素,場(chǎng)景使用真實(shí)單位(如英制或公制)。圖1-6場(chǎng)景使用的坐標(biāo)系場(chǎng)景坐標(biāo)系中,坐標(biāo)軸的選擇是任意的,因此我們的選擇需要對(duì)我們的目的有幫助。我們說(shuō)軸是向上的,軸和軸是水平的,并且3個(gè)軸都相互垂直。把平面想象成“地板”,而平面和是方形房間里垂直的“墻”。與我們?yōu)楫嫴歼x擇的坐標(biāo)系一致,場(chǎng)景坐標(biāo)系中軸是向上的,軸是水平的。圖1-6展示了場(chǎng)景使用的坐標(biāo)系。場(chǎng)景單位的選擇取決于我們的場(chǎng)景代表什么。如果我們正在對(duì)一個(gè)茶杯進(jìn)行建模,那么測(cè)量值“1”可以表示1英寸(1英寸≈2.54cm);如果我們是對(duì)太陽(yáng)系進(jìn)行建模,那么“1”可以表示1個(gè)天文單位。只要我們堅(jiān)持使用所選擇的單位,它們是什么并不重要,所以我們可以從現(xiàn)在開始安心地忽略它們。1.6總結(jié)在本章中,我們介紹了畫布,這是一種表示矩形表面的抽象概念,我們可以在其上繪制圖像。還介紹了一個(gè)函數(shù)——PutPixel,我們將使用它構(gòu)建其他所有內(nèi)容。我們還選擇了一個(gè)坐標(biāo)系來(lái)“引用”畫布上的像素,并描述了一種表示這些像素顏色的方法。最后,我們介紹了場(chǎng)景的概念,并選擇了在場(chǎng)景中使用的坐標(biāo)系。奠定了這些基礎(chǔ)之后,我們可以開始構(gòu)建光線追蹤渲染器和光柵化渲染器了。第一部分光線追蹤第2章基礎(chǔ)光線追蹤知識(shí)在本章中,我們將介紹光線追蹤(raytracing),這是我們將要介紹的第一個(gè)重要算法。首先我們會(huì)解釋此算法的目的——人們是為了解決什么問(wèn)題才想到了這樣的算法,然后會(huì)列出一些算法實(shí)現(xiàn)過(guò)程的偽代碼。之后我們會(huì)學(xué)習(xí)如何在場(chǎng)景中表示光線和物體。最后,我們推導(dǎo)出一種方法,用來(lái)計(jì)算哪些光線構(gòu)成了我們場(chǎng)景中每個(gè)物體的可見圖像,并了解如何在畫布上表示它們。2.1渲染一幅瑞士風(fēng)景圖假設(shè)我們正在游覽一處旅游勝地,并看到了令人驚嘆的風(fēng)景——它是如此令人著迷,我們恰好可以繪制一幅畫來(lái)捕捉它的美景。圖2-1展示了這樣一處風(fēng)景。假設(shè)我們有畫布和畫筆,但我們并沒有太多藝術(shù)天賦。難道繪制圖畫來(lái)捕捉美景的愿望就要因此破滅了嗎?不一定。我們可能沒有藝術(shù)天賦,但我們是有條理、有方法的。所以我們可以順理成章地想到一件事:去找一張捕蟲網(wǎng)。切割出一張長(zhǎng)方形的網(wǎng),把它用木框框起來(lái),然后把它固定在一根木棍上?,F(xiàn)在我們可以透過(guò)一扇網(wǎng)狀的窗戶觀察風(fēng)景了。接下來(lái),我們選擇最佳視角來(lái)欣賞風(fēng)景,并且再插一根木棍來(lái)標(biāo)記此時(shí)我們眼睛所處的確切位置。圖2-1令人嘆為觀止的瑞士風(fēng)景我們還沒有開始畫畫,但此時(shí)我們有了一個(gè)固定的視角和一個(gè)固定的木框,通過(guò)這個(gè)木框我們可以觀察風(fēng)景。而且這個(gè)固定的木框,被捕蟲網(wǎng)分割成了一個(gè)個(gè)的小方塊。然后我們可以開始有條不紊地繪畫了。我們?cè)诋嫴忌侠L制一個(gè)網(wǎng)格,網(wǎng)格中格子的數(shù)量和我們之前木框上捕蟲網(wǎng)的格子數(shù)量相同。然后我們觀察一下木框上捕蟲網(wǎng)左上角的格子,我們透過(guò)它可以看到的最主要的顏色是什么?是天藍(lán)色。所以我們把畫布上左上角格子的顏色也涂成天藍(lán)色。我們不斷重復(fù)這個(gè)過(guò)程,對(duì)畫布上的每個(gè)格子都這樣處理,很快畫布上就有了一幅“美麗的”風(fēng)景畫,就像我們通過(guò)木框看到的那樣。最終繪制的圖如圖2-2所示。圖2-2對(duì)風(fēng)景的粗略描述仔細(xì)想想,計(jì)算機(jī)本質(zhì)上是一臺(tái)非常有條理的機(jī)器,完全缺乏藝術(shù)天賦\h\h[1]。我們可以像下面這樣描述我們的繪畫創(chuàng)作過(guò)程。\h[1]現(xiàn)在的人工智能(AI)算法,在圖像處理方面,已經(jīng)展現(xiàn)出了一定的藝術(shù)性,感興趣的讀者可以搜索機(jī)器學(xué)習(xí)在圖像處理方面的應(yīng)用?!g者注For

each

little

square

on

the

canvas

Paint

it

the

right

color

非常簡(jiǎn)單!但是這個(gè)過(guò)程太抽象了,無(wú)法直接在計(jì)算機(jī)上實(shí)現(xiàn)。我們可以描述得更詳細(xì)一點(diǎn)兒。Place

the

eye

and

the

frame

as

desired

For

each

square

on

the

canvas

Determine

which

square

on

the

grid

corresponds

to

this

square

on

the

canvas

Determine

the

color

seen

through

that

grid

square

Paint

the

square

with

that

color

這仍然太抽象了,但它開始看起來(lái)像一個(gè)算法——也許會(huì)令大家驚訝,這其實(shí)是對(duì)一個(gè)完整光線追蹤算法的較高層面的概述!是的,就是這么簡(jiǎn)單。2.2基本假設(shè)計(jì)算機(jī)圖形學(xué)的魅力之一是可以在屏幕上繪制各種東西。為了盡快實(shí)現(xiàn)這一點(diǎn),我們需要做一些經(jīng)過(guò)簡(jiǎn)化的假設(shè)。當(dāng)然,這些假設(shè)對(duì)我們可以做的事情施加了一些限制,但我們將在后面的章節(jié)中解除這些限制。首先,我們假定有一個(gè)固定的觀察位置。觀察位置,也就是2.1節(jié)我們觀察瑞士風(fēng)景時(shí)眼睛所處的位置,我們通常稱其為相機(jī)位置(cameraposition),用表示。我們假設(shè)相機(jī)在空間中占據(jù)一個(gè)點(diǎn),它位于坐標(biāo)系的原點(diǎn),并且它永遠(yuǎn)不會(huì)從那里移走,所以現(xiàn)在相機(jī)的位置是。其次,我們假設(shè)有一個(gè)固定的相機(jī)方位。相機(jī)方位決定了相機(jī)指向哪里。我們假設(shè)相機(jī)指向軸正方向(簡(jiǎn)寫為),并且軸正方向()是向上的,軸正方向()是向右的,如圖2-3所示。圖2-3相機(jī)的位置和方位相機(jī)位置和方位現(xiàn)已固定。在觀察瑞士風(fēng)景這個(gè)示例中,我們?nèi)匀蝗鄙俚木褪怯糜谟^察場(chǎng)景的“木框”。我們假設(shè)這個(gè)木框的尺寸為和,并且在相機(jī)方位的正前方,也就是垂直于。我們還假設(shè)木框到相機(jī)的距離是,它的兩條邊平行于軸和軸,它的中心在軸上。說(shuō)得有點(diǎn)兒?jiǎn)?,但其?shí)質(zhì)很簡(jiǎn)單,如圖2-4所示。圖2-4所示的矩形作為我們觀察世界的窗口,我們稱之為視口(viewport)。本質(zhì)上,我們將在畫布上繪制我們通過(guò)視口看到的任何內(nèi)容。請(qǐng)注意,視口的大小和視口到相機(jī)的距離決定了從相機(jī)可以觀察的角度,稱為視野(fieldofview),或簡(jiǎn)稱FOV。人類有將近180°的水平視野(盡管大部分是模糊的周邊視覺,沒有深度感)。為簡(jiǎn)單起見,我們?cè)O(shè)置;這樣會(huì)使得相機(jī)視野大約為53°,從而可以生成合理的而且不會(huì)過(guò)度扭曲失真的圖像。圖2-4視口的位置和方位讓我們回到前面介紹的“算法”,使用適當(dāng)?shù)募夹g(shù)術(shù)語(yǔ),并為清單2-1中的步驟編號(hào)。清單2-1光線追蹤算法的簡(jiǎn)要描述①Place

the

camera

and

the

viewport

as

desired

For

each

pixel

on

the

canvas

②Determine

which

square

on

the

viewport

corresponds

to

this

pixel

③Determine

the

color

seen

through

that

square

④Paint

the

pixel

with

that

color

我們剛剛完成了步驟①(或者更準(zhǔn)確地說(shuō),暫時(shí)解決了這個(gè)問(wèn)題)。步驟④很簡(jiǎn)單:我們只需使用canvas.PutPixel(x,y,color)。我們需要快速地完成步驟②,然后在接下來(lái)的幾章中,我們將專注于完成步驟③所涉及的越來(lái)越復(fù)雜的方法。2.3畫布空間到視口空間清單2-1中算法的步驟②要求我們確定視口上的哪個(gè)正方形格子對(duì)應(yīng)于畫布上的某一像素。我們知道像素的畫布坐標(biāo)——我們稱之為和。需要注意的是,我們要怎樣放置視口,才能便捷地把它的軸與畫布的方位相匹配,把它的中心與畫布的中心相匹配。因?yàn)橐暱谑且允澜缈臻g的單位衡量的,而畫布是以像素衡量的\h\h[2],所以從畫布坐標(biāo)到空間坐標(biāo)只是比例的改變!\h[2]因?yàn)橐暱谑窃谑澜缈臻g,所以是以世界空間的單位衡量的,而畫布是與最終的渲染目標(biāo)(例如屏幕)相關(guān)聯(lián)的,所以以像素作為衡量單位?!g者注還有一個(gè)額外的細(xì)節(jié)。盡管視口是2D的,但它是嵌在3D空間中的。我們定義它與相機(jī)的距離為。根據(jù)定義,這個(gè)平面,也就是投影平面(projectionplane)上的每個(gè)點(diǎn)都有。因此,有如下方程。這樣步驟②就完成了。對(duì)于畫布上的每個(gè)像素,我們可以確定其在視口上對(duì)應(yīng)的點(diǎn)。2.4追蹤射線下一步是弄清楚從相機(jī)的位置觀察,穿過(guò)視口上的某個(gè)點(diǎn)的光是什么顏色的。在現(xiàn)實(shí)世界中,光來(lái)自光源(如太陽(yáng)、燈泡等),經(jīng)過(guò)幾個(gè)物體反射之后,最終到達(dá)我們的眼睛。對(duì)于場(chǎng)景中的模擬光源,我們可以嘗試模擬每個(gè)光子離開模擬光源的路徑,但這會(huì)非常耗時(shí)。我們不僅要模擬數(shù)量驚人的光子(一個(gè)100W的燈泡每秒發(fā)出個(gè)光子?。抑挥幸恍〔糠止庾釉谕ㄟ^(guò)視口后會(huì)剛好到達(dá)。這種技術(shù)稱為光子追蹤(photontracing)或光子映射(photonmapping)。不幸的是,這超出了本書的范圍。相反,我們將考慮“反向”的光線:相機(jī)發(fā)射出射線,我們從這里開始,穿過(guò)視口中的某個(gè)點(diǎn),并跟蹤射線的路徑,直到它“擊中”場(chǎng)景中的某個(gè)物體。這個(gè)物體就是相機(jī)通過(guò)視口的那個(gè)點(diǎn)“看到”的物體。因此,作為第一近似值,我們只需要將該物體的顏色作為“通過(guò)該點(diǎn)的光的顏色”,如圖2-5所示。圖2-5視口中的一個(gè)小方塊,代表了畫布上的一個(gè)像素,我們用相機(jī)通過(guò)它看到的物體的顏色繪制該像素現(xiàn)在我們只需要用一些方程來(lái)描述這些幾何圖形。2.4.1射線方程對(duì)我們來(lái)說(shuō),表示射線最方便的方法是用參數(shù)方程。我們知道射線通過(guò)點(diǎn),而且知道它的方向(從點(diǎn)指向點(diǎn)),所以我們可以把射線中的任意點(diǎn)表示為如下方程。其中是任意實(shí)數(shù)。通過(guò)把從到的每個(gè)值代入這個(gè)方程,我們可得到沿射線的每個(gè)點(diǎn)。我們稱射線的方向?yàn)?。這樣方程變?yōu)橄旅孢@樣。理解這個(gè)方程的一種直觀方式是,我們從原點(diǎn)()發(fā)出射線,并沿著射線的方向()“前進(jìn)”某個(gè)量(),很容易看出這包括了沿射線的所有點(diǎn)。你可以在本書附錄中了解更多關(guān)于向量運(yùn)算的細(xì)節(jié)。圖2-6顯示了這些方程的實(shí)際應(yīng)用。圖2-6射線上不同值的點(diǎn)圖2-6顯示了沿射線對(duì)應(yīng)和的點(diǎn)。的每個(gè)值沿射線產(chǎn)生不同的點(diǎn)。2.4.2球體方程現(xiàn)在我們需要在場(chǎng)景中假設(shè)一些物體,這樣我們的射線就能擊中這些物體。我們可以選擇任意的幾何圖元作為場(chǎng)景的構(gòu)建塊。對(duì)于光線追蹤,我們使用球體,因?yàn)樗鼈兒苋菀子梅匠虂?lái)處理。什么是球體?球體是距離一個(gè)固定點(diǎn)有固定距離的點(diǎn)的集合\h\h[3]。這個(gè)距離叫作球的半徑(radius),這個(gè)點(diǎn)叫作球的球心(center)。圖2-7顯示了一個(gè)由球心和半徑定義的球體。\h[3]在計(jì)算機(jī)圖形學(xué)中,除了一些特殊的材質(zhì)(例如體渲染材質(zhì)),大部分是表面渲染,因此相應(yīng)的著色器被稱為surfaceshader。作者沒有按照嚴(yán)格的幾何定義,因此球體和球面使用了相同的描述函數(shù)。本書其余部分,除非特殊說(shuō)明,一般會(huì)沿用這種方式?!g者注圖2-7一個(gè)球體,由它的球心和半徑定義根據(jù)上面的定義,如果是球心,是球的半徑,那么球體表面上的點(diǎn)必須滿足下面的函數(shù)。我們來(lái)研究一下這個(gè)函數(shù)。如果你對(duì)這些數(shù)學(xué)知識(shí)不熟悉,可參閱附錄。點(diǎn)和點(diǎn)之間的距離就是從點(diǎn)到點(diǎn)的向量的長(zhǎng)度,如下所示\h\h[4]。\h[4]作者使用了簡(jiǎn)化形式,意為從點(diǎn)指向點(diǎn)的向量。——譯者注一個(gè)向量的長(zhǎng)度(記為)是它與自身的點(diǎn)積(記為)的平方根,如下所示。為了消去平方根,我們可以兩邊同時(shí)取平方,得到下面的方程。上述這些球體方程都是等價(jià)的,但最后一個(gè)方程在下面的步驟中最便于操作。2.4.3射線與球體相交現(xiàn)在我們有兩個(gè)方程:一個(gè)描述球體上的點(diǎn),一個(gè)描述射線上的點(diǎn)。如下所示。射線和球體是否相交呢?如果相交,交點(diǎn)在哪里呢?假設(shè)射線和球體確實(shí)在點(diǎn)相交。這個(gè)點(diǎn)既在射線上又在球體的表面上,所以它必須同時(shí)滿足兩個(gè)方程。請(qǐng)注意,這些方程中唯一的未知量就是參數(shù),因?yàn)?、和都是已知的,而是我們要找的點(diǎn)。由于在兩個(gè)方程中代表相同的點(diǎn),我們可以用第二個(gè)方程中的表達(dá)式代替第一個(gè)方程中的。這樣我們可以得到如下方程。如果我們能找到滿足這個(gè)方程的值,我們可以把它代入射線方程從而找到射線與球體的交點(diǎn)。從目前的方程形式來(lái)看,這個(gè)方程有點(diǎn)兒難以理解。我們來(lái)做一些代數(shù)運(yùn)算看看能得到什么。首先,讓。然后我們可以把方程改寫成下面這樣。然后,我們利用分配律將點(diǎn)積展開(同樣,可參閱附錄),如下所示。稍微整理一下這些項(xiàng),我們得到下面的方程。將參數(shù)移出點(diǎn)積并將移到等式的另一側(cè),我們得到下面的方程。記住,兩個(gè)向量的點(diǎn)積是實(shí)數(shù),所以前文方程中每個(gè)圓括號(hào)內(nèi)的項(xiàng)都是實(shí)數(shù)。如果我們給它們分別起個(gè)名字,我們會(huì)得到更熟悉的東西,如下所示。這剛好就是一個(gè)經(jīng)典的一元二次方程!它的解就是射線與球體相交處參數(shù)的值,如下所示。幸運(yùn)的是,這在幾何上是合理的。你們可能還記得,一元二次方程可以沒有解,有一個(gè)解,或者有兩個(gè)不同的解,這取決于判別式的值。這正好分別對(duì)應(yīng)射線不與球體相交、射線與球體相切、射線進(jìn)入和離開球體3種情況,如圖2-8所示。圖2-8一元二次方程解的幾何解釋:無(wú)解、一個(gè)解或兩個(gè)解一旦我們求出了的值,我們就可以將其代入射線方程,最終得到與該值對(duì)應(yīng)的交點(diǎn)。2.5渲染我們的第一組球體總而言之,對(duì)于畫布上的每個(gè)像素,我們可以計(jì)算視口中對(duì)應(yīng)的點(diǎn)。給定相機(jī)的位置,我們可以表示從相機(jī)出發(fā)并穿過(guò)視口中某一點(diǎn)的射線方程。給定一個(gè)球體,我們可以計(jì)算出射線與球體相交的位置。所以我們需要做的就是計(jì)算射線和每個(gè)球體的交點(diǎn),保留距離相機(jī)最近的那個(gè)交點(diǎn),然后用適當(dāng)?shù)念伾诋嫴忌侠L制像素。我們已經(jīng)準(zhǔn)備好渲染我們的第一組球體了!不過(guò),參數(shù)的值得特別注意。讓我們回到射線方程。由于射線的原點(diǎn)和方向是固定的,在所有實(shí)數(shù)范圍內(nèi)改變將產(chǎn)生這條射線中的每個(gè)點(diǎn)。我們注意到,對(duì)于,我們得到;對(duì)于,我們得到。的負(fù)值產(chǎn)生相反方向的點(diǎn),即在相機(jī)后面。因此,我們可以將參數(shù)空間分為3個(gè)部分,如表2-1所示。圖2-9展示了參數(shù)空間的示意。表2-1參數(shù)空間的細(xì)分t值參數(shù)空間劃分在相機(jī)后面在相機(jī)和投影平面/視口之間在投影平面/視口前面請(qǐng)注意,相交方程并沒有表明球體必須在相機(jī)前面;該方程也可以求解出位于相機(jī)后面的交點(diǎn)。顯然,這不是我們想要的,所以我們應(yīng)該忽略任何的解。為了進(jìn)一步避免數(shù)學(xué)計(jì)算上的煩瑣,我們將方程的解限制為,即我們將渲染投影平面前面的任何內(nèi)容。圖2-9參數(shù)空間中的一些點(diǎn)另一方面,我們不想為的值設(shè)置上限,我們希望看到相機(jī)前的所有物體,無(wú)論它們有多遠(yuǎn)。但是,因?yàn)樵谝院蟮碾A段我們想要縮短射線段的長(zhǎng)度,所以我們現(xiàn)在將引入這種形式,并給一個(gè)的上限(對(duì)于不能直接表示“無(wú)窮”的編程語(yǔ)言,一個(gè)非常大的數(shù)字就可以了)。我們現(xiàn)在可以用一些偽代碼來(lái)表示我們到目前為止所做的一切。一般來(lái)說(shuō),我們會(huì)假設(shè)代碼可以訪問(wèn)它需要的任何數(shù)據(jù),這樣我們就不需要費(fèi)心地顯式傳遞諸如canvas之類的參數(shù),而將重點(diǎn)放在真正必要的參數(shù)上。main函數(shù)現(xiàn)在如清單2-2所示。清單2-2main函數(shù)main()?{

O

=

(0,0,0)

for

x

=

-Cw/2

to

Cw/2

{

for

y

=

-Ch/2

to

Ch/2

{

D

=

CanvasToViewport(x,

y)

color

=

TraceRay(O,

D,

1,

inf)

canvas.PutPixel(x,

y,

color)

}

}

}

CanvasToViewport函數(shù)非常簡(jiǎn)單,如清單2-3所示。常數(shù)d表示相機(jī)和投影平面之間的距離。清單2-3CanvasToViewport函數(shù)CanvasToViewport(x,

y){

return

(x

*

Vw

/

Cw,

y

*

Vh

/

Ch,

d)

}

TraceRay函數(shù)計(jì)算射線與每個(gè)球體的交點(diǎn),如清單2-4所示,并且返回在的取值范圍內(nèi)最近的交點(diǎn)處球體的顏色。清單2-4TraceRay函數(shù)TraceRay(O,

D,

t_min,

t_max){

closest_t

=

inf

closest_sphere

=

NULL

for

sphere

in

scene.spheres

{

t1,

t2

=

IntersectRaySphere(O,

D,

sphere)

if

t1

in

[t_min,

t_max]

and

t1

<

closest_t

{

closest_t

=

t1

closest_sphere

=

sphere

}

if

t2

in

[t_min,

t_max]

and

t2

<

closest_t

{

closest_t

=

t2

closest_sphere

=

sphere

}

}

if

closest_sphere

==

NULL

{

①return

BACKGROUND_COLOR

}

return

closest_sphere.color

}

在清單2-4中,O表示射線的原點(diǎn)。雖然我們追蹤的是相機(jī)的射線,它位于原點(diǎn),但在后面的階段不一定是這樣,所以它必須是一個(gè)參數(shù)。這同樣適用于t_min和t_max。請(qǐng)注意,當(dāng)射線不與任何球體相交時(shí),我們?nèi)匀恍枰祷匾恍╊伾佟以诖蠖鄶?shù)示例中選擇了背景色。最后,用IntersectRaySphere函數(shù)求解這個(gè)一元二次方程,如清單2-5所示。清單2-5IntersectRaySphere函數(shù)IntersectRaySphere(O,

D,

sphere){

r

=

sphere.radius

CO

=

O

-

sphere.center

a

=

dot(D,

D)

b

=

2*dot(CO,

D)

c

=

dot(CO,

CO)

-

r*r

discriminant

=

b*b

-

4*a*c

if

discriminant

<

0

{

return

inf,

inf

}

t1

=

(-b

+

sqrt(discriminant))

/

(2*a)

t2

=

(-b

-

sqrt(discriminant))

/

(2*a)

return

t1,

t2

}

為了將這些付諸實(shí)踐,我們需要定義一個(gè)非常簡(jiǎn)單的場(chǎng)景,如圖2-10所示。圖2-10一個(gè)非常簡(jiǎn)單的場(chǎng)景,分別從上面(左圖)和從右面(右圖)觀察在偽場(chǎng)景語(yǔ)言中,場(chǎng)景是像下面這樣表示的。viewport_size

=

1

x

1

projection_plane_d

=

1

sphere

{

center

=

(0,

-1,

3)

radius

=

1

color

=

(255,

0,

0)

#紅色

}

sphere

{

center

=

(2,

0,

4)

radius

=

1

color

=

(0,

0,

255)

#藍(lán)色

}

sphere

{

center

=

(-2,

0,

4)

radius

=

1

color

=

(0,

255,

0)

#綠色

}

當(dāng)我們?cè)谶@個(gè)場(chǎng)景上運(yùn)行我們的算法時(shí),我們最終得到了一個(gè)非常棒的光線追蹤渲染場(chǎng)景,如圖2-11所示。你可以在本書附件的/cgfs/basic-rays-demo目錄下面找到該算法的實(shí)時(shí)實(shí)現(xiàn),雙擊Basicraytracingdemo.html文件或者用瀏覽器打開該文件即可。圖2-11一個(gè)非常棒的光線追蹤渲染場(chǎng)景我知道,這一效果有點(diǎn)兒令人失望,不是嗎?反射、陰影和高光效果去哪里啦?別擔(dān)心,我們會(huì)實(shí)現(xiàn)這些的。這是個(gè)很好的開端。這些球體看起來(lái)像圓形,這總比它們看起來(lái)像貓要好。它們看起來(lái)不太像球體的原因是,缺少了人類如何決定物體形狀的一個(gè)關(guān)鍵組成部分:物體與光的相互作用方式。我們將在第3章討論這個(gè)問(wèn)題。2.6總結(jié)在本章中,我們已經(jīng)奠定了光線追蹤渲染器的基礎(chǔ)。我們選擇了一套固定的設(shè)置(相機(jī)和視口的位置和方位,以及視口的大?。晃覀冞x擇了球體和射線的表示方法;我們探索了必要的數(shù)學(xué)知識(shí)來(lái)弄清楚球體和射線如何相交;我們把這些都放在一起,從而可以用純色在畫布上繪制球體。接下來(lái)的章節(jié)將在此基礎(chǔ)上,對(duì)光與場(chǎng)景中物體的交互方式進(jìn)行更詳細(xì)的建模。第3章光我們將通過(guò)引入光開始為場(chǎng)景渲染添加“真實(shí)感”。光是一個(gè)龐大而復(fù)雜的主題,因此我們將提出一個(gè)簡(jiǎn)化的模型,它足以達(dá)到我們的目的。這個(gè)模型的大部分靈感來(lái)自現(xiàn)實(shí)世界中光的作用方式,但它也需要一些自由發(fā)揮的部分,目的是使渲染的場(chǎng)景看起來(lái)更好。我們將從一些簡(jiǎn)化的假設(shè)開始,這將使我們的工作更輕松,然后我們將介紹3種類型的光源:點(diǎn)光(pointlight)、方向光(directionallight)\h\h[1]和環(huán)境光(ambientlight)。我們將通過(guò)討論這些光源如何影響物體的表面來(lái)結(jié)束本章,包括漫反射和鏡面反射。\h[1]directionallight,此處譯為方向光,也經(jīng)常被翻譯為平行光或者定向光?!g者注3.1簡(jiǎn)化的假設(shè)讓我們做一些假設(shè),讓事情變得更簡(jiǎn)單。首先,我們假設(shè)所有的光都是白色的。這讓我們可以使用單個(gè)實(shí)數(shù)來(lái)表征任何光,源于光的強(qiáng)度(intensity)。模擬彩色光并不那么復(fù)雜(我們只需要使用3個(gè)強(qiáng)度值——每個(gè)顏色通道一個(gè)——并按照通道來(lái)計(jì)算所有顏色和光照),但我們這里依然使用白光從而保證事情可以簡(jiǎn)單一點(diǎn)兒。其次,我們將忽略空氣。在現(xiàn)實(shí)生活中,光源離得越遠(yuǎn),看起來(lái)就越暗,這是因?yàn)榭諝庵酗h浮的粒子會(huì)在光線穿過(guò)它們時(shí)吸收部分光。雖然這在光線追蹤渲染器中實(shí)現(xiàn)起來(lái)并不復(fù)雜,但我們?yōu)榱吮WC事情簡(jiǎn)單一點(diǎn)兒,將忽略空氣的影響。在我們的場(chǎng)景中,距離并不會(huì)降低光的強(qiáng)度。3.2光源光必須來(lái)自某個(gè)地方。在本節(jié)中,我們將定義3種不同類型的光源。3.2.1點(diǎn)光點(diǎn)光從3D空間中的一個(gè)固定的點(diǎn)發(fā)射光,這個(gè)點(diǎn)被稱為點(diǎn)光源的位置。點(diǎn)光源向每個(gè)方向均勻地發(fā)射光,這就是它也被稱為全向光(omnidirectionallight)的原因。因此,點(diǎn)光可以完全用位置和強(qiáng)度來(lái)描述。燈泡是點(diǎn)光在現(xiàn)實(shí)生活中的一個(gè)很好的例子。雖然現(xiàn)實(shí)生活中的燈泡并不是從單個(gè)點(diǎn)發(fā)出光,也不是完全全方向的,但它是一個(gè)相當(dāng)準(zhǔn)確的例子。我們定義向量作為從場(chǎng)景中的點(diǎn)到光源的方向。我們可以計(jì)算這個(gè)向量,稱其為光向量(lightvector),即。需要注意的是,由于是固定的,可以是場(chǎng)景中的任何點(diǎn),因此對(duì)于場(chǎng)景中的每個(gè)點(diǎn)都是不同的,如圖3-1所示。圖3-1位于的點(diǎn)光。向量對(duì)于每個(gè)點(diǎn)都是不同的3.2.2方向光如果燈泡是點(diǎn)光的一個(gè)很好的例子,太陽(yáng)是否也可以作為點(diǎn)光的例子呢?這是一個(gè)棘手的問(wèn)題,答案取決于我們?cè)噲D渲染的內(nèi)容。在太陽(yáng)系這樣的尺度上,太陽(yáng)可以近似為點(diǎn)光。畢竟它是從一個(gè)點(diǎn)發(fā)射光的,而且是向四面八方發(fā)射光的,所以這似乎是合理的。然而,如果我們的場(chǎng)景代表地球上發(fā)生的事情,太陽(yáng)就不可以近似為點(diǎn)光。太陽(yáng)是如此遙遠(yuǎn),以至于到達(dá)我們身邊的每一束光線幾乎都具有相同的方向。我們可以用一個(gè)離場(chǎng)景中的物體非常遙遠(yuǎn)的點(diǎn)光來(lái)近似表示太陽(yáng)。然而,光源和物體之間的距離會(huì)比物體之間的距離大幾個(gè)數(shù)量級(jí),所以我們會(huì)遇到數(shù)值精度誤差。為了更好地處理這些情況,我們定義了方向光。和點(diǎn)光一樣,方向光也有強(qiáng)度,但不同的是,它沒有位置;相反,它有一個(gè)固定的方向。你可以把它想象成位于特定的方向上而且無(wú)限遠(yuǎn)的點(diǎn)光。在點(diǎn)光的情況下,我們需要為場(chǎng)景中的每個(gè)點(diǎn)計(jì)算不同的光向量,在方向光的情況下,是給定的。在太陽(yáng)到地球的場(chǎng)景示例中,將會(huì)是(太陽(yáng)中心)-(地球中心)。圖3-2為方向光的示例。正如我們?cè)趫D3-2中看到的,方向光的光向量對(duì)于場(chǎng)景中的每個(gè)點(diǎn)都是相同的。與圖3-1相比,圖3-1中點(diǎn)光的光向量對(duì)于場(chǎng)景中的每個(gè)點(diǎn)都是不同的。圖3-2方向光。向量對(duì)于每個(gè)點(diǎn)都是相同的3.2.3環(huán)境光現(xiàn)實(shí)生活中的每個(gè)光源都可以被建模為點(diǎn)光或方向光嗎?差不多如此。這兩種光源是否足以照亮一個(gè)場(chǎng)景?不幸的是不能。想想月球所發(fā)生的事情。月球附近唯一重要的光源是太陽(yáng)。所以相對(duì)于太陽(yáng)而言,月球的“前半部分”得到了幾乎所有的光,而“后半部分”則幾乎完全處于黑暗之中。我們從地球的不同角度觀察這一現(xiàn)象,形成了我們所說(shuō)的“月相”。然而,在地球上的情況有些不同。即使沒有直接接收光源光線的點(diǎn)也不會(huì)完全處于黑暗中(看看你椅子下面的地板就知道了)。如果光源的“視野”被其他東西阻擋,光線如何到達(dá)這些點(diǎn)呢?正如“1.2顏色模型”中提到的,當(dāng)光照射到一個(gè)物體上時(shí),它的一部分被吸收,但其余的光會(huì)散射回場(chǎng)景中。這意味著光不僅可以來(lái)自光源,也可以來(lái)自從光源獲得光并將其部分散射回場(chǎng)景的物體。但會(huì)止步于此嗎?散射的光會(huì)反過(guò)來(lái)照射到其他物體,一部分會(huì)被吸收,一部分會(huì)被散射回場(chǎng)景。以此類推,直到原始光的所有能量都被場(chǎng)景中的物體表面吸收。這意味著我們應(yīng)該把每個(gè)物體當(dāng)作光源??梢韵胂螅@會(huì)給我們的模型增加很多復(fù)雜性,所以我們不會(huì)在本書中探討這種機(jī)制。如果你好奇,可以搜索全局光照(globalillumination),你一定會(huì)驚嘆于它生成的漂亮渲染效果。但我們?nèi)匀徊幌M總€(gè)物體被直接照亮或者完全黑暗(除非我們實(shí)際上是在渲染一個(gè)太陽(yáng)系的模型)。為了突破這一限制,我們將定義第三種光源,稱為環(huán)境光,它只以其強(qiáng)度為特征。我們將聲明環(huán)境光為場(chǎng)景中的每個(gè)點(diǎn)貢獻(xiàn)一些光,不管它在哪里。這是對(duì)光源和場(chǎng)景中物體表面之間非常復(fù)雜的交互過(guò)程的一種粗略簡(jiǎn)化,但它的效果還不錯(cuò)。一般來(lái)說(shuō),一個(gè)場(chǎng)景會(huì)有單個(gè)環(huán)境光(因?yàn)榄h(huán)境光只有一個(gè)強(qiáng)度值,任意數(shù)量的環(huán)境光都可以簡(jiǎn)單地組合成一個(gè)環(huán)境光)和任意數(shù)量的點(diǎn)光及方向光。3.3單點(diǎn)光照現(xiàn)在我們知道了如何定義場(chǎng)景中的光源,我們需要弄清楚光源如何與場(chǎng)景中物體的表面相互作用。為了計(jì)算單個(gè)點(diǎn)的光照,我們將計(jì)算每個(gè)光源貢獻(xiàn)的光,并將它們加在一起,得到一個(gè)代表該點(diǎn)接收到的光的總量的數(shù)字。然后我們可以用這個(gè)總量乘物體表面在該點(diǎn)的顏色,從而獲得該點(diǎn)的著色顏色,用以代表該點(diǎn)接收了多少光。那么,當(dāng)一束光線(無(wú)論是來(lái)自方向光還是來(lái)自點(diǎn)光)照射到場(chǎng)景中某個(gè)物體上的某個(gè)點(diǎn)時(shí)會(huì)發(fā)生什么?我們可以根據(jù)物體反射光的方式直觀地將物體分為兩大類:“啞光”和“閃亮”物體。由于我們周圍的大多數(shù)物體都可以歸類為啞光物體,因此我們將首先關(guān)注這一組。3.4漫反射當(dāng)一束光線照射到一個(gè)啞光物體上時(shí),光線會(huì)沿著每個(gè)方向均勻地散射回場(chǎng)景中,這個(gè)過(guò)程叫作漫反射(diffusereflection),這就是使啞光物體看起來(lái)無(wú)光澤的原因。為了驗(yàn)證這一點(diǎn),看看你周圍的一些啞光物體,比如一堵墻。如果你相對(duì)于墻壁移動(dòng),它的顏色不會(huì)改變。也就是說(shuō),無(wú)論你從哪里看,你看到的物體反射的光都是一樣的。另一方面,反射的光的數(shù)量取決于光線和物體表面之間的角度。直觀地看,這是因?yàn)楣饩€所攜帶的能量必須根據(jù)角度分散在更小或更大的區(qū)域上,所以單位面積上反射到場(chǎng)景的能量分別更高或更低,如圖3-3所示。圖3-3一束光線的能量根據(jù)它與物體表面的角度不同而分布在不同大小的區(qū)域在圖3-3中,我們可以看到相同強(qiáng)度(用相同寬度表示)的兩束光線分別以垂直方向以及一定角度照射在一個(gè)表面上。光線所攜帶的能量在它們照射到的區(qū)域均勻地分布。圖中右側(cè)光線的能量分布的區(qū)域比左側(cè)光線的能量分布的區(qū)域更大,因此右側(cè)區(qū)域中的每個(gè)點(diǎn)接收的能量都比左側(cè)的情況少。為了從數(shù)學(xué)上探討這個(gè)問(wèn)題,讓我們用法向量(normalvector)來(lái)描述物體表面的方位。物體表面點(diǎn)處的法向量(或者簡(jiǎn)稱法線)是一個(gè)在點(diǎn)處垂直于物體表面的向量。它也是一個(gè)單位向量,意味著它的長(zhǎng)度是1。我們稱法向量為。3.4.1對(duì)漫反射的建模方向?yàn)榍覐?qiáng)度為的光線照射到法線為的表面上。作為、和的函數(shù),的哪一部分被反射回場(chǎng)景呢?作為一個(gè)幾何類比,我們用光線的“寬度”來(lái)表示光的強(qiáng)度。它的能量分布在大小為的表面上。當(dāng)和方向相同,也就是光線垂直于表面時(shí),那么,這意味著每單位面積反射的能量與每單位面積入射的能量相同:。另一方面,隨著和之間的夾角趨于90°,趨于,因此單位面積的能量趨于0,也就是。但是如果條件在這兩種情況之間,會(huì)發(fā)生什么呢?這種情況如圖3-4所示。我們知道了、和,圖中添加了角度和,以及點(diǎn)、和,以便更輕松地討論圖中的幾何關(guān)系。圖3-4漫反射計(jì)算中涉及的向量和角度因?yàn)閺募夹g(shù)上講,一束光線是沒有寬度的,所以我們可以假設(shè)一切都發(fā)生在表面上一個(gè)平坦的、無(wú)限小的方塊上。即使它是一個(gè)球體的表面,我們考慮的面積無(wú)窮小,以至于與球體的大小相比它幾乎是平的,就像地球在小尺度下看起來(lái)是平的一樣。寬度為的光線以角度照射到物體表面上的處。處的法線為,光線所攜帶的能量分布在面積上。我們需要計(jì)算??紤]線段,也就是光線的“寬度”。根據(jù)定義,它垂直于向量,這也是線段的方向。因此,和構(gòu)成一個(gè)直角,使△成為一個(gè)直角三角形。三角形的一個(gè)角是,另一個(gè)角是。因此剩下的角是。但是要注意和也形成一個(gè)直角,這意味著也是。因此。我們來(lái)關(guān)注一下△,如圖3-5所示。它的3個(gè)角分別是、和。側(cè)邊的長(zhǎng)度是,側(cè)邊的長(zhǎng)度是。圖3-5三角函數(shù)中的△現(xiàn)在,我們需要三角函數(shù)了!根據(jù)定義,。我們用替換,用替換,這樣我們可以得到下面的方程??梢宰儞Q成下面這樣。我們馬上就要得到最終結(jié)果了。是向量和的夾角。我們可以利用點(diǎn)積的性質(zhì)(可參閱附錄)將表示為下面這樣。最終我們可以得到如下方程。我們得到一個(gè)簡(jiǎn)化的方程,該方程給出了反射光的比例,這一比例是物體表面法線和光線方向之間夾角的函數(shù)。請(qǐng)注意,對(duì)于超過(guò)的角度,的值變?yōu)樨?fù)值。如果我們盲目地使用這個(gè)值,我們最終可能會(huì)得到一個(gè)使表面變暗的光源!這沒有任何物理意義。超過(guò)的角度僅僅意味著光線實(shí)際上照亮了物體表面的背面,它不會(huì)為我們要照亮的點(diǎn)貢獻(xiàn)任何光線。因此,如果值為負(fù)數(shù),我們需要將其視為0。3.4.2漫反射方程我們現(xiàn)在可以編寫一個(gè)方程來(lái)計(jì)算場(chǎng)景中點(diǎn)所接收到的全部光線,已知該點(diǎn)的法線為,其所在的場(chǎng)景包含一個(gè)環(huán)境光(強(qiáng)度為),以及個(gè)點(diǎn)光或者方向光。第個(gè)點(diǎn)光或者方向光的強(qiáng)度為,光向量為(對(duì)于方向光,它是已知的;對(duì)于點(diǎn)光,則需要為每個(gè)點(diǎn)單獨(dú)計(jì)算)。這個(gè)方程如下。這里我們需要重復(fù)指出,在利用上述方程計(jì)算每個(gè)光源的貢獻(xiàn)值時(shí),如果,則這一項(xiàng)忽略,不被添加到最終的光照計(jì)算結(jié)果中。3.4.3球體的法線圖3-6球體在點(diǎn)的法線方向與方向相同只有一個(gè)小細(xì)節(jié)被遺漏了:法線從何而來(lái)?這是一個(gè)很普遍的問(wèn)題,但這個(gè)問(wèn)題的答案遠(yuǎn)比它看起來(lái)要復(fù)雜得多,我們將在本書的第二部分看到詳細(xì)解答。幸運(yùn)的是,現(xiàn)在我們只討論球體,對(duì)于球體而言,有一個(gè)很簡(jiǎn)單的答案:球體上任何一點(diǎn)的法向量都在穿過(guò)球心的直線上。如圖3-6所示,如果球心為,點(diǎn)處法線的方向?yàn)?。為什么這里是“法線方向”而不是“法線”呢?法向量需要垂直于表面,但它的長(zhǎng)度也需要是1。為了將這個(gè)向量歸一化(normalize)并將其轉(zhuǎn)化成真正的法線,我們需要將它除以它自己的長(zhǎng)度,從而保證結(jié)果的長(zhǎng)度為1,計(jì)算過(guò)程如下所示。3.4.4漫反射的渲染讓我們將上面這些討論內(nèi)容轉(zhuǎn)換為偽代碼。首先,讓我們?cè)趫?chǎng)景中添加幾個(gè)光源。light

{

type

=

ambient

intensity

=

0.2

}

light

{

type

=

point

intensity

=

0.6

position

=

(2,

1,

0)

}

light

{

type

=

directional

intensity

=

0.2

direction

=

(1,

4,

4)

}

需要注意的是,所有光源的強(qiáng)度加起來(lái)剛好為1.0。光照方程的工作方式可以確保場(chǎng)景中任意點(diǎn)接收到的光照強(qiáng)度都不會(huì)大于該值。這意味著我們不會(huì)有任何“過(guò)度曝光”的點(diǎn)。光照方程可以很容易地被轉(zhuǎn)換成偽代碼,如清單3-1所示。清單3-1一個(gè)計(jì)算漫反射光照的函數(shù)ComputeLighting(P,

N)

{

i

=

0.0

for

light

in

scene.Lights

{

if

light.type

==

ambient

{

①i

+=

ensity

}

else

{

if

light.type

==

point

{

②L

=

light.position

-

P

}

else

{

③L

=

light.direction

}

n_dot_l

=

dot(N,

L)

④if

n_dot_l

>

0

{

⑤i

+=

ensity

*

n_dot_l

/

(length(N)

*

length(L))

}

}

}

return

i

}

在清單3-1中,我們以略微不同的方式處理這3種類型的光源。環(huán)境光是最簡(jiǎn)單的,可以直接處理①。點(diǎn)光和方向光共享大部分代碼,尤其是強(qiáng)度計(jì)算⑤,但是方向向量的計(jì)算方式是不同的(②和③),取決于它們的類型。④中的條件判斷確保我們不會(huì)添加負(fù)值,正如我們之前討論的那樣,負(fù)值代表照亮物體表面的背面的光源。余下唯一一件要做的事情就是在函數(shù)TraceRay中使用函數(shù)ComputeLighting。我們需要將原來(lái)返回球體顏色的這一行偽代碼替換掉。return?closest_sphere.color

將其替換為以下的偽代碼段。P

=

O

+

closest_t

*

D

//

計(jì)算交點(diǎn)

N

=

P

-

closest_sphere.center

//

計(jì)算交點(diǎn)處的球面法線

N

=

N

/

length(N)

return

closest_sphere.color

*

ComputeLighting(P,

N)

為了讓場(chǎng)景變得更有趣,我們添加一個(gè)很大的黃色球體,如下所示。sphere?{

color?=?(255,?255,?0)?//?黃色

center?=?(0,?-5001,?0)

radius?=?5000

}

此時(shí)我們?cè)龠\(yùn)行渲染器,渲染的圖形現(xiàn)在開始看起來(lái)像球體了,如圖3-7所示!圖3-7漫反射為場(chǎng)景增添了深度感和體積感你可以在本書附件的/cgfs/diffuse-demo目錄下面找到該算法的實(shí)時(shí)實(shí)現(xiàn),雙擊Diffusereflectiondemo.html文件或者用瀏覽器打開該文件即可。但是等等,黃色的球體怎么變成平坦的黃色地板了呢?它沒有。與其他3個(gè)球體相比,它是如此之大,而且相機(jī)離它如此之近,以至于它看起來(lái)是平的——就像我們站在地球上時(shí),地球表面看起來(lái)是平的一樣。3.5鏡面反射讓我們把注意力轉(zhuǎn)向閃亮的物體。與啞光物體不同,閃亮物體的視覺效果會(huì)因你的視線位置不同而略有不同。想象一個(gè)臺(tái)球或一輛剛從洗車場(chǎng)出來(lái)的汽車。這類物體表現(xiàn)出非常獨(dú)特的光圖案,通常是亮點(diǎn),似乎會(huì)隨著你在它們周圍移動(dòng)而移動(dòng)。與啞光物體不同,你感知這些閃亮物體表面的方式實(shí)際上取決于你的視角。請(qǐng)注意,如果你繞著一個(gè)紅色的臺(tái)球走,它仍然是紅色的,但是讓它看起來(lái)閃閃發(fā)光的亮白點(diǎn)會(huì)隨著你的移動(dòng)而移動(dòng)。這表明我們想要建模的新效果并沒有取代漫反射,而是補(bǔ)充了漫反射。為了理解為什么會(huì)發(fā)生這種情況,讓我們仔細(xì)看看物體表面是如何反射光的。正如我們?cè)?.4節(jié)所看到的,當(dāng)一束光線照射到啞光物體的表面時(shí),它會(huì)在每個(gè)方向上均勻地散射回場(chǎng)景。這是因?yàn)槲矬w的表面是不規(guī)則的,所以在微觀層面上,啞光物體的表面就像一組指向隨機(jī)方向的微小平面,如圖3-8所示。圖3-8通過(guò)顯微鏡觀察粗糙的啞光物體表面。入射光以隨機(jī)方向反射但如果表面不是那么不規(guī)則呢?讓我們走向一個(gè)極端:一面“完美拋光”的鏡子。當(dāng)一束光線照射到鏡子上時(shí),它會(huì)向同一個(gè)方向反射。如果我們稱反射光的方向?yàn)?,并且按照約定指向光源\h\h[2],圖3-9說(shuō)明了這種情況。\h[2]此處的方向是正確的。在計(jì)算機(jī)圖形學(xué)中,除非特殊說(shuō)明,光源方向都是從場(chǎng)景中任意一點(diǎn)指向光源的方向,與物理中入射光的方向相反,是為了方便后續(xù)光照模型中的計(jì)算?!g者注圖3-9一面鏡子反射的光線根據(jù)表面的“拋光程度”,閃亮物體的表面或多或少像一面鏡子,這就是為什么它被稱為鏡面反射(specularreflection),specular這個(gè)詞來(lái)源于拉丁文“speculum”,意思是“鏡子”。對(duì)于完美拋光的鏡子,入射光線會(huì)沿著單一的方向被反射。這就是你可以非常清楚地看到反射物體的原因:對(duì)于每一束入射光線,都有一束單一的反射光線。但是并非每一個(gè)物體都是經(jīng)過(guò)完美拋光的。盡管大部分光線會(huì)沿著的方向被反射,但是總有一部分光線會(huì)沿著接近的方向被反射。越是接近,該方向反射的光線越多,如圖3-10所示。當(dāng)反射光線遠(yuǎn)離方向時(shí),物體的“光澤度”(shininess)決定了反射光線衰減的程度。圖3-10對(duì)于沒有完美拋光的表面,方向越接近,該方向反射的光線就越多圖3-11鏡面反射計(jì)算中涉及的向量和角度我們想要知道有多少來(lái)自的光被反射回我們的視野方向。如果表示從點(diǎn)指向相機(jī)的“視線向量”,是向量與之間的夾角,我們得到圖3-11。對(duì)于°,所有的光都反射到的方向。對(duì)于°,沒有光被反射到的方向。就像漫反射一樣,我們需要一個(gè)數(shù)學(xué)表達(dá)式來(lái)確定取中間值時(shí)會(huì)發(fā)生什么。3.5.1對(duì)鏡面反射的建模在本章的開頭,我就提到過(guò)有一些模型不是基于物理的模型,本小節(jié)所使用的模型便是其中之一。接下來(lái)要介紹的模型是根據(jù)人們的主觀意愿設(shè)計(jì)的,但之所以使用它是因?yàn)樗子谟?jì)算并且看起來(lái)效果不錯(cuò)。我們來(lái)考慮三角函數(shù)。它具有以下性質(zhì),和。這正如我們需要的那樣。而且從到,其數(shù)值逐漸變小,可繪制一條平滑的曲線,如圖3-12所示。圖3-12的圖像這意味著符合我們對(duì)鏡面反射函數(shù)的所有要求,那么為什么不使用它呢?還有一個(gè)細(xì)節(jié)。如果我們直接用這個(gè)公式,每個(gè)物體的光澤效果都是一樣的。我們應(yīng)該如何調(diào)整這個(gè)公式來(lái)代表不同程度的光澤效果呢?請(qǐng)記住,光澤度用于衡量反射函數(shù)隨著增加而衰減的程度。獲得不同光澤度曲線的一種簡(jiǎn)單方法是計(jì)算對(duì)某些正指數(shù)的冪。由于,我們可以保證,所以的圖像就像的圖像一樣,只是“更窄”了。圖3-13顯示了取不同值時(shí)的圖像。圖3-13的圖像的值越大,函數(shù)在0°附近變得越“窄”,物體看起來(lái)越閃亮。稱為鏡面反射指數(shù)(specularexponent),它是物體表面的一個(gè)屬性。由于這個(gè)模型不是基于物理的,的值只能通過(guò)試錯(cuò)法反復(fù)試驗(yàn)來(lái)確定——本質(zhì)上,就是調(diào)整這些值直到它們看起來(lái)“正確”。對(duì)于基于物理的模型,你可以查看雙向反射函數(shù)(bi-directionalreflectancefunction,BDRF)的相關(guān)資料。讓我們來(lái)做一個(gè)總結(jié)。一束光線從方向照射到表面的點(diǎn)處,該表面的鏡面反射指數(shù)為,該點(diǎn)的法線為。有多少光會(huì)沿著視線方向被反射呢?圖3-14將分解為和兩個(gè)分量根據(jù)我們的光照模型,這個(gè)值是,其中是向量與的夾角;向量是向量以法向量為基準(zhǔn)經(jīng)過(guò)反射獲得的。所以第一步就是通過(guò)和計(jì)算。我們可以將分解成兩個(gè)向量——和,使,其中平行于,垂直于,如圖3-14所示。向量是在上面的投影。根據(jù)點(diǎn)積的性質(zhì)和這一事實(shí),這個(gè)投影的長(zhǎng)度為。我們定義平行于,因此。由于,我們可以立即得到。圖3-15計(jì)算現(xiàn)在我們來(lái)看。由于它與相對(duì)對(duì)稱,因此它平行于的分量與平行于的分量相同,它垂直于的分量與垂直于的分量相反,即。我們可以在圖3-15中看到這一情況。用我們前文找到的表達(dá)式替換,我們可以得到下面的方程。然后我們稍微簡(jiǎn)化一下,得到下面的方程。3.5.2鏡面反射的計(jì)算項(xiàng)現(xiàn)在我們已經(jīng)準(zhǔn)備好寫一個(gè)鏡面反射方程了,如下所示。與之前漫反射光照計(jì)算一樣,有可能是負(fù)的,我們應(yīng)該出于與之前相同的原因把它忽略掉。此外,并非每一個(gè)物體都必須有光澤,對(duì)于啞光物體,鏡面反射項(xiàng)根本不應(yīng)該計(jì)算。我們需要在場(chǎng)景中注意這一點(diǎn),需要將它們的鏡面反射指數(shù)設(shè)置為并且進(jìn)行相應(yīng)的處理。3.5.3完整的光照方程我們可以將鏡面反射項(xiàng)添加到我們一直在開發(fā)的光照方程中,并得到一個(gè)在某一點(diǎn)的光照計(jì)算表達(dá)式,如下所示。其中,是點(diǎn)處的總光照度,是環(huán)境光的強(qiáng)度,是表面在點(diǎn)處的法線,是從點(diǎn)到相機(jī)的視線向量,是物體表面的鏡面反射指數(shù)(也被稱為光澤度指數(shù)),是光源的強(qiáng)度,是從點(diǎn)到光源的光線向量,是光源在點(diǎn)處的反射向量。3.5.4鏡面反射的渲染讓我們將鏡面反射添加到我們迄今為止一直在處理的場(chǎng)景中。首先,我們對(duì)場(chǎng)景本身做一些改變。sphere

{

center

=

(0,

-1,

3)

radius

=

1

color

=

(255,

0,

0)

#

紅色

specular

=

500

#

閃亮

}

sphere

{

center

=

(2,

0,

4)

radius

=

1

color

=

(0,

0,

255)

#

藍(lán)色

specular

=

500

#

閃亮

}

sphere

{

center

=

(-2,

0,

4)

radius

=

1

color

=

(0,

255,

0)

#

綠色

specular

=

10

#

略微閃亮

}

sphere

{

center

=

(0,

-5001,

0)

radius

=

5000

color

=

(255,

255,

0)

#

黃色

specular

=

1000

#

異常閃亮

}

這和之前的場(chǎng)景是一樣的,只是在球體定義中增加了鏡面反射指數(shù)。在代碼層面,我們需要在必要時(shí)更改ComputeLighting,從而計(jì)算鏡面反射項(xiàng),并將其添加到整體光照中。請(qǐng)注意,該函數(shù)現(xiàn)在需要V和s,如清單3-2所示。清單3-2支持漫反射和鏡面反射的ComputeLighting函數(shù)ComputeLighting(P,

N,

V,

s)

{

i

=

0.0

for

light

in

scene.Lights

{

if

light.type

==

ambient

{

i

+=

ensity

}

else

{

if

light.type

==

point

{

L

=

light.position

-

P

}

else

{

L

=

light.direction

}

//

漫反射

n_dot_l

=

dot(N,

L)

if

n_dot_l

>

0

{

i

+=

ensity

*

n_dot_l

/

(length(N)

*

length(L))

}

//

鏡面反射

①if

s

!=

-1

{

R

=

2

*

N

*

dot(N,

L)

-

L

r_dot_v

=

dot(R,

V)

②if

r_dot_v

>

0

{

i

+=

ensity

*

pow(r_dot_v

/

(length(R)

*?

length(V)),?s)

}

}

}

}

return

i

}

大部分代碼保持不變,但我們添加了一個(gè)代碼片段來(lái)處理鏡面反射。我們要確保它只適用于閃亮的物體①,并且還要確保不會(huì)添加負(fù)的光照強(qiáng)度②,就像我們對(duì)漫反射所做的一樣。最后,我們需要修改TraceRay,將新的參數(shù)傳遞給ComputeLighting。參數(shù)s很簡(jiǎn)單,它直接來(lái)自場(chǎng)景定義。但是參數(shù)V來(lái)自哪里呢?參數(shù)V表示從物體指向相機(jī)的向量。幸運(yùn)的是,在TraceRay中我們已經(jīng)有了一個(gè)表示從相機(jī)指向物體的向量的參數(shù),也就是參數(shù)D(我們正在追蹤的射線方向)!所以V就是-D。清單3-3給出了具有鏡面反射的新的TraceRay。清單3-3帶鏡面反射的TraceRay函數(shù)TraceRay(O,

D,

t_min,

t_max){

closest_t

=

inf

closest_sphere

=

NULL

for

sphere

in

scene.Spheres

{

t1,

t2

=

IntersectRaySphere(O,

D,

sphere)

if

t1

in

[t_min,

t_max]

and

t1

<

closest_t

{

closest_t

=

t1

closest_sphere

=

sphere

}

if

t2

in

[t_min,

t_max]

and

t2

<

closest_t

{

closest_t

=

t2

closest_sphere

=

sphere

}

}

if

closest_sphere

==

NULL

{

return

BACKGROUND_COLOR

}

P

=

O

+

closest_t

*

D

//

計(jì)算交點(diǎn)

N

=

P

-

closest_sphere.center

//

計(jì)算交點(diǎn)處的球面法線

N

=

N

/

length(N)

①return

closest_sphere.color

*

ComputeLighting(P,

N,

-D,

closest_sphere.specular)

}

顏色計(jì)算①比看起來(lái)要復(fù)雜一些。請(qǐng)記住,顏色值必須按照通道相乘,并且結(jié)果必須限制在通道范圍內(nèi)(在我們的示例中,通道范圍是)。盡管在上述示例場(chǎng)景中,我們可以確保所有光源的光照強(qiáng)度加起來(lái)為1.0,但是現(xiàn)在我們添加了鏡面反射項(xiàng),最終計(jì)算值可能會(huì)超出這個(gè)范圍。我們可以在圖3-16中看到所有向量經(jīng)過(guò)合理安排所產(chǎn)生的渲染效果。你可以在本書附件的/cgfs/specular-demo目錄下面找到該算法的實(shí)時(shí)實(shí)現(xiàn),雙擊Specularreflectiondemo.html文件或者用瀏覽器打開該文件即可。請(qǐng)注意,在圖3-16中,鏡面反射指數(shù)為500的紅色球體比鏡面反射指數(shù)為10的綠色球體具有更集中的亮點(diǎn),正如預(yù)期的那樣。藍(lán)色球體的鏡面反射指數(shù)也為500,但沒有可見的亮點(diǎn)。這是由圖像裁剪和光源在場(chǎng)景中的位置決定的;事實(shí)上,紅色球體的左半部分也沒有表現(xiàn)出任何鏡面反射。圖3-16使用環(huán)境光、漫反射和鏡面反射渲染的場(chǎng)景。我們不僅能感受到深度感和體積感,而且每個(gè)表面的外觀也略有不同3.6總結(jié)在本章中,我們使用了在第2章中開發(fā)的非常簡(jiǎn)單的光線追蹤渲染器,賦予它對(duì)光源進(jìn)行建模的能力,并給出了它與場(chǎng)景中的物體交互的方式。我們將光源分為3種類型:點(diǎn)光、方向光和環(huán)境光。我們探討了它們?nèi)绾未砟憧梢栽诂F(xiàn)實(shí)生活中找到的不同類型的光源,以及如何在我們的場(chǎng)景定義中描述它們。然后我們將注意力轉(zhuǎn)向場(chǎng)景中物體的表面,將它們分為兩種類型:?jiǎn)」夂烷W亮。我們討論了光線如何與它們相互作用,并開發(fā)了兩種模型——漫反射和鏡面反射——來(lái)計(jì)算它們向相機(jī)反射了多少光。最終的結(jié)果是一個(gè)更加真實(shí)的場(chǎng)景:我們現(xiàn)在看到的不僅僅是物體的輪廓,還能真正感受到深度感和體積感,以及對(duì)構(gòu)成物體的材質(zhì)的感覺。但是,我們?nèi)鄙賵?chǎng)景的一個(gè)基本方面:陰影。這是第4章的重點(diǎn)。第4章陰影和反射我們繼續(xù)以越來(lái)越逼真的方式渲染場(chǎng)景。在第3章中,我們模擬了光線與物體表面相互作用的方式。在本章中,我們將對(duì)光線與場(chǎng)景交互方式的兩個(gè)方面進(jìn)行建模:物體投射陰影和物體反射到其他物體上。4.1陰影哪里有光和物體,哪里就有陰影?,F(xiàn)在我們的場(chǎng)景中已經(jīng)有了光和物體。那么我們的陰影在哪里呢?4.1.1理解陰影讓我們從一個(gè)更基本的問(wèn)題開始。為什么會(huì)有陰影?當(dāng)光線因?yàn)槠渌矬w擋住去路而無(wú)法照射到物體時(shí),就會(huì)出現(xiàn)陰影。在第3章中,我們只關(guān)注了光源和物體表面之間非常局部的交互,而忽略了場(chǎng)景中發(fā)生的其他一切。為了產(chǎn)生陰影,我們需要更全面地考慮光源、我們想要繪制的表面和場(chǎng)景中其他物體之間的相互作用。從概念上講,我們想要做的事情相當(dāng)簡(jiǎn)單。我們想添加一點(diǎn)兒邏輯,

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論