光線追蹤技術的理論和實踐(面向對象)
介紹
本文引用地址:http://www.104case.com/article/164673.htm這篇文章將介紹光線追蹤技術。在計算機圖形領域中,這種技術被普遍應用于生成高質量的照片級圖像。在為一個場景計算光照的時候,通過固定圖形渲染管線可以計算phong光照模型,由于該模型的特征,使得渲染的物體看起來有塑料的質感。如果要渲染一個有金屬質感且能反射周圍環境的物體,phong模型就無能為力了。和固定渲染管線相比,可編程圖形渲染管線的力能要強的多,雖然可以實現很多逼真的光照效果,比如利用環境貼圖來現實物體對環境的反射效果。但是這種環境反射只能反射出已經保存在Cube Map中的圖像。在真實世界中,如果一個能反射周圍環境的物體周圍還有很多其他物體,它們就會相互反射。一般的環境貼圖技術達不到這樣的效果,于是在渲染照片級畫面的時候,就要用到光線追蹤的技術。文本還將利用c++面向對象的方法來實現光線追蹤。
原理
在介紹原理之前,先考慮一個問題:我們是怎樣看到真實世界中的物體的?我們能看到物體,是因為該物體上有反射光線到達我們的眼睛。沒有任何光線傳入眼睛,我們就看不到任何東西。我們還經常看到一個物體表面能反射另一個物體。這也是因為被反射物體表面的反射光線到達該物體表面后,該物體繼續將光線反射到我們的眼睛里,于是我們看到了該物體表面反射其他物體的效果。現在,我們將從物體表面出發最后到達眼睛的光線的方向反向。先來看看下面的Fig1,在Fig1中是一個虛擬的場景,場景中有2個球和1個圓錐,白色的點代表光源,中間四邊形就是虛擬屏幕,屏幕上一個一個的小方格就代表像素,相機的位置代表觀察者眼睛的位置。

(a)

(b)
Fig1 光線追蹤場景
光線追蹤的原理就是從相機的位置發出一條條通過每一個像素的射線,如果該射線和場景中的物體相交,那么就可以計算出該交點的顏色,這個顏色就是對應的像素的顏色。當然,計算像素顏色的時候首先要計算出交點處所有與光照計算相關量,比如法線,入射光線和反射光線等等。

(a)

(b)
Fig2 光線和空間物體相交
在Fig2中可以看到,從相機出發的射線依次穿過每一個像素,圖中顯示出其中的三條。這些射線都與物體有交點,不同物體的交點計算方法也不一樣。射線與平面的交點計算方法和射線與球的交點計算方法是截然不同的。為了計算方便,這里就只以球為例。如果一個物體可以反射周圍的環境,那么當一條射線與該物體相交后,射線還會在該點產生反射和折射等。例如在Fig2中,當射線和藍色球相交后,光線會反射,反射的光線又可能和橙色圓錐和綠色球相交,所以我們能在藍色球的表面看到橙色的圓錐和綠色球。整個光線追蹤的原理就是這么簡單,但是實際操作起來又有很多要注意的地方。
用面向對象的方法來實現光線追蹤比使用面向結構要來的容易一些。因為在光線追蹤的整個過程中,比較容易抽象出對象的共同特征,比如我們可以抽象出射線,物體,光源,材質等等。當然,最最基本的一個類就是向量類,在計算光照的時候向量很重要。在這里我們假設已經實現了一個三維向量類GVector3,該類提供所有有關向量的操作。
除了向量,我們最先能想到一個關于射線的類,叫CRay。

對于一條射線最基本的就是它的出發點和方向,所以在CRay的類圖中,能看到兩個私有成員變量m_Origin和m_Direction,它們都是GVector3類型。由于類的設計原則要滿足數據的封裝性,既然射線的出發點和方向都是私有的,那么就要提供公共的成員方法來訪問它們,于是我們還需要set和get方法。最后,getPoint(double)方法是通過向射線的參數方程傳入參數t而獲得在射線上的點。實現了射線CRay類后,那么在使用光線追蹤計算每個像素顏色的時候,對于每一個像素都要創建一個CRay的實例。
for(int y=0; y=ImageHeight; y++)
{
for(int x=0; x=ImageWidth; x++)
{
double pixel_x = -20.0 +40.0/ImageWidth*x;
double pixel_y = -15.0 +30.0/ImageHeight*y;
GVector3 direction = GVector3(pixel_x, pixel_y,0)-CameraPosition;
CRay ray(CameraPosition, direction);
// call RayTracer function
}
}
從上面的代碼可以看到,兩個for循環用于掃描每一個像素,然后在循環里計算出每個像素的位置。如果我們假設Fig1中,四邊形屏幕處于xy平面,長和寬分別是40和30,且左上頂點坐標和右下頂點坐標分別為(-20,15,0)和(20,-15,0)。為了將該屏幕映射到實際分辨率為800*600的窗口上,就要求出虛擬屏幕上每個像素的坐標pixel_x和pixel_y。然后對每一個像素都用一條射線穿過它,射線的方向自然就是像素的位置和相機位置的差向量的方向。要注意一點,實際窗口的分辨率比例要和虛擬屏幕長寬比例保持一致,這樣渲染出來的畫面看起來長寬比例才正確。
現在我們來考慮在場景中的物體。一個物體可能有很多可以描述它的特征,比如形狀,大小,顏色,材質等等。使用面向對象的方法,就需要將這些物體的共同特征抽象出來。下面是一個抽象出來的物體類GCObject。

c++相關文章:c++教程
評論