日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 消費電子 > 消費電子
[導讀]介紹這篇文章將介紹光線追蹤技術。在計算機圖形領域中,這種技術被普遍應用于生成高質(zhì)量的照片級圖像。在為一個場景計算光照的時候,通過固定圖形渲染管線可以計算phong光照模型,由于該模型的特征,使得渲染的物體看

介紹

這篇文章將介紹光線追蹤技術。在計算機圖形領域中,這種技術被普遍應用于生成高質(zhì)量的照片級圖像。在為一個場景計算光照的時候,通過固定圖形渲染管線可以計算phong光照模型,由于該模型的特征,使得渲染的物體看起來有塑料的質(zhì)感。如果要渲染一個有金屬質(zhì)感且能反射周圍環(huán)境的物體,phong模型就無能為力了。和固定渲染管線相比,可編程圖形渲染管線的力能要強的多,雖然可以實現(xiàn)很多逼真的光照效果,比如利用環(huán)境貼圖來現(xiàn)實物體對環(huán)境的反射效果。但是這種環(huán)境反射只能反射出已經(jīng)保存在Cube Map中的圖像。在真實世界中,如果一個能反射周圍環(huán)境的物體周圍還有很多其他物體,它們就會相互反射。一般的環(huán)境貼圖技術達不到這樣的效果,于是在渲染照片級畫面的時候,就要用到光線追蹤的技術。文本還將利用c++面向?qū)ο?/strong>的方法來實現(xiàn)光線追蹤。

原理

在介紹原理之前,先考慮一個問題:我們是怎樣看到真實世界中的物體的?我們能看到物體,是因為該物體上有反射光線到達我們的眼睛。沒有任何光線傳入眼睛,我們就看不到任何東西。我們還經(jīng)??吹揭粋€物體表面能反射另一個物體。這也是因為被反射物體表面的反射光線到達該物體表面后,該物體繼續(xù)將光線反射到我們的眼睛里,于是我們看到了該物體表面反射其他物體的效果?,F(xiàn)在,我們將從物體表面出發(fā)最后到達眼睛的光線的方向反向。先來看看下面的Fig1,在Fig1中是一個虛擬的場景,場景中有2個球和1個圓錐,白色的點代表光源,中間四邊形就是虛擬屏幕,屏幕上一個一個的小方格就代表像素,相機的位置代表觀察者眼睛的位置。

(a)

(b)

Fig1 光線追蹤場景

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

(a)

(b)

Fig2 光線和空間物體相交

在Fig2中可以看到,從相機出發(fā)的射線依次穿過每一個像素,圖中顯示出其中的三條。這些射線都與物體有交點,不同物體的交點計算方法也不一樣。射線與平面的交點計算方法和射線與球的交點計算方法是截然不同的。為了計算方便,這里就只以球為例。如果一個物體可以反射周圍的環(huán)境,那么當一條射線與該物體相交后,射線還會在該點產(chǎn)生反射和折射等。例如在Fig2中,當射線和藍色球相交后,光線會反射,反射的光線又可能和橙色圓錐和綠色球相交,所以我們能在藍色球的表面看到橙色的圓錐和綠色球。整個光線追蹤的原理就是這么簡單,但是實際操作起來又有很多要注意的地方。

實踐

用面向?qū)ο蟮姆椒▉韺崿F(xiàn)光線追蹤比使用面向結構要來的容易一些。因為在光線追蹤的整個過程中,比較容易抽象出對象的共同特征,比如我們可以抽象出射線,物體,光源,材質(zhì)等等。當然,最最基本的一個類就是向量類,在計算光照的時候向量很重要。在這里我們假設已經(jīng)實現(xiàn)了一個三維向量類GVector3,該類提供所有有關向量的操作。

除了向量,我們最先能想到一個關于射線的類,叫CRay。

對于一條射線最基本的就是它的出發(fā)點和方向,所以在CRay的類圖中,能看到兩個私有成員變量m_Origin和m_Direction,它們都是GVector3類型。由于類的設計原則要滿足數(shù)據(jù)的封裝性,既然射線的出發(fā)點和方向都是私有的,那么就要提供公共的成員方法來訪問它們,于是我們還需要set和get方法。最后,getPoint(double)方法是通過向射線的參數(shù)方程傳入?yún)?shù)t而獲得在射線上的點。實現(xiàn)了射線CRay類后,那么在使用光線追蹤計算每個像素顏色的時候,對于每一個像素都要創(chuàng)建一個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循環(huán)用于掃描每一個像素,然后在循環(huán)里計算出每個像素的位置。如果我們假設Fig1中,四邊形屏幕處于xy平面,長和寬分別是40和30,且左上頂點坐標和右下頂點坐標分別為(-20,15,0)和(20,-15,0)。為了將該屏幕映射到實際分辨率為800*600的窗口上,就要求出虛擬屏幕上每個像素的坐標pixel_x和pixel_y。然后對每一個像素都用一條射線穿過它,射線的方向自然就是像素的位置和相機位置的差向量的方向。要注意一點,實際窗口的分辨率比例要和虛擬屏幕長寬比例保持一致,這樣渲染出來的畫面看起來長寬比例才正確。

現(xiàn)在我們來考慮在場景中的物體。一個物體可能有很多可以描述它的特征,比如形狀,大小,顏色,材質(zhì)等等。使用面向?qū)ο蟮姆椒?,就需要將這些物體的共同特征抽象出來。下面是一個抽象出來的物體類GCObject。

CGObject類成員變量有五個,分別表示物體表面環(huán)境光反射系數(shù)(m_Ka),漫反射系數(shù)(m_Kd),鏡面反射系數(shù)(m_Ks),鏡面反射強度(m_Shininess)和環(huán)境反射強度(m_Reflectivity)。前四個變量是計算光照所需要的最基本量,而環(huán)境反射強度表示該物體能反射環(huán)境的能力。這些成員變量都的類型都是protected,因為我們要把CGObject最為物體的基類,這些protected成員變量可以被該類的子類所繼承。該類的所有get方法和set方法都能被子類繼承,而且所有繼承了該類的子類的方法都相同。該類還有兩個虛成員函數(shù),分別是getNormal()和isIntersected()。getNormal()函數(shù)的作用是獲取物體表面一點的法線,它接受一個GVector3類型的參數(shù)_Point,并返回物體表面點_Point處的法線。當然不同物體表面獲得法線的方法是不一樣的。比如,對于平面來說,平面上所有點的法線都是一樣的。而對于球來說,球面上每一個的法線是球面上的該交點p和球心的c的差向量。

NSphere = p - c

所以將getNormal()設置為虛成員函數(shù)就可以實現(xiàn)類的多態(tài)性,凡是繼承了該方法的子類,都可以實現(xiàn)自己的getNormal()方法。同樣的道理,函數(shù)isInserted也是虛成員函數(shù),該方法接受參數(shù)射線CRay

和距離Distance,CRay是輸入?yún)?shù),用于判斷射線和該物體的交點,Distance是輸出參數(shù),如果物體和射線相交,則返回相機到該交點的距離。Distance還應該有個很大初始值,表示在無限遠處物體和射線相交,這種情況用于判斷物體和射線沒有交點。函數(shù)isIntersected()還返回一個枚舉類型INTERSECTION_TYPE,定義如下:

enum INTERSECTION_TYPE {INTERSECTED_IN = -1, MISS = 0, INTERSECTED = 1};

其中INTERSECTED_IN表示射線從物體內(nèi)部出發(fā)并和物體有交點,MISS射線和物體沒有交點,INTERSECTED表示射線從物體外部出發(fā)并且和物體有交點。射線和不同物體交點的計算方法不同,于是該函數(shù)為虛函數(shù),繼承該函數(shù)的子類可以實現(xiàn)自己的isIntersected()方法。下面的代碼就可以判斷一條射線和場景中所有物體的是否有交點,并且返回離相機最近的一個。

double distance = 1000000; // 初始化無限大距離

GVector3 Intersection; // 交點

for(int i = 0; i

{

CGObject *obj = objects_list[i];

if( obj->isIntersected(ray, distance) != MISS) // 判斷是否有交點

{

Intersection = ray.getPoint(distance); //如果相交,求出交點保存到Intersection

}

}

為了計算方便,這里就以球為例,創(chuàng)建一個CSphere的類,該類繼承于CGObject。

作為球,只需要提供球心Center和半徑Radius就可以決定它的幾何性質(zhì)。所以CSphere類只有兩個私有成員變量。在所有成員函數(shù)中,我們重點來看看isIntersected()方法。

INTERSECTION_TYPE CSphere::isIntersected(CRay _ray, double& _dist)

{

GVector3 v = _ray.getOrigin() - m_Center;

double b = -(v * _ray.getDirection());

double det = (b * b) - v*v + m_Radius;

INTERSECTION_TYPE retval = MISS;

if (det > 0){

det = sqrt(det);

double t1 = b - det;

double t2 = b + det;

if (t2 > 0){

if (t1 < 0) {

if (t2 < _dist) {

_dist = t2;

retval = INTERSECTED_IN;

}

}

else{

if (t1 < _dist){

_dist = t1;

retval = INTERSECTED;

}

}

}

}

return retval;

}

如果射線和球有交點,那么交點肯定在球面上。球面上的點P都滿足下面的關系,

| P – C | = R

很明顯球面上的點和球心的差向量的大小等于球的半徑。然后將射線的參數(shù)方程帶入上面的公式,再利用求根公式判斷解的情況。具體的方法這里就不詳述了,有興趣的同學可以參考另一篇文章“利用OpenGL實現(xiàn)RayPicking”,這篇文章詳細講解了射線和球交點的計算過程。

現(xiàn)在我們實現(xiàn)了射線CRay,球體CSphere,還差一個重要的角色——光源。光源也是物體的一種,完全可以從我們的基類CGObject類繼承。這里做一點區(qū)別,我們單獨創(chuàng)建一個所有光源的基類CLightSource,然后從它在派生出不同的光源種類,比如平行光源DirectionalLight,點光源CPointLight和聚光源CSpotLight。本文中只詳細講解平行光源的情況,其他兩種光源有興趣的同學可以自己實現(xiàn)。

類CLightSource的成員變量有四個,分別表示光源的位置,光源的環(huán)境光成分,漫反射成分和鏡面反射成分。同樣地,所有的set和get方法都為該類的子類提供相同的功能。最后也有三個虛成員函數(shù),EvalAmbient(),EvalDiffuse()和EvalSpecular(),它們名字分別說明它們的功能,并且都返回GVector3類型的值——顏色。由于對于不同種類的光源,計算方法可能不同,于是將它們設置為虛函數(shù)為以后的擴展做準備。筆者這里將光照計算放在了光源類里面,當然你也可以放在物體類CGObject里,也可以單獨寫一個方法,將光源和物體作為參數(shù)傳入,計算出顏色后最為返回值返回。具體使用哪一種好還是要根據(jù)具體情況具體分析。

上面的平行光源類CDirectionalLight是CLightSource的子類,它繼承了父類三個虛函數(shù)方法。下面來看看這三個函數(shù)的具體實現(xiàn)。

環(huán)境光的計算是最簡單的,將物體材質(zhì)環(huán)境反射系數(shù)和光源的環(huán)境光成分相乘即可。

ambient = Ia•Ka

計算環(huán)境光的代碼如下

GVector3 CDirectionalLight::EvalAmbient(const GVector3& _material_Ka)

{

return GVector3(m_Ka[0]*_material_Ka[0],

m_Ka[1]*_material_Ka[1],

m_Ka[2]*_material_Ka[2]);

}

漫反射的計算稍微比環(huán)境光復雜,漫反射的計算公式為

diffuse = Id•Kd• (N•L)

其中,Id是光源的漫反射成分,Kd是物體的漫反射系數(shù),N是法線,L是入射光向量。

GVector3 CDirectionalLight::EvalDiffuse(const GVector3& _N, const GVector3& _L, constGVector3& _material_Kd)

{

GVector3 IdKd = GVector3( m_Kd[0]*_material_Kd[0],

m_Kd[1]*_material_Kd[1],

m_Kd[2]*_material_Kd[2]);

double NdotL = MAX(_N*_L, 0.0);

return IdKd*NdotL;

}

鏡面反射的計算又比環(huán)境光要復雜,鏡面反射的計算公式為

specular = Is•Ks• (V·R)n

其中

R = 2(L•N) •N-L

Is是光源鏡面反射成分,Ks是物體的鏡面反射系數(shù),V是相機方向向量,R是反射向量,­n­就反射強度Shininess。為了提高計算效率,也可以利用HalfVector H來計算鏡面反射。

specular = Is•Ks• (N•H)n

其中

H=(L+V)/2

計算H要比計算反射向量R要快得多。

GVector3 CDirectionalLight::EvalSpecluar(const GVector3& _N, const GVector3& _L, constGVector3& _V,

const GVector3& _material_Ks,const double& _shininess)

{

GVector3 IsKs = GVector3( m_Ks[0]*_material_Ks[0],

m_Ks[1]*_material_Ks[1],

m_Ks[2]*_material_Ks[2]);

GVector3 H = (_L+_V).Normalize();

double NdotL = MAX(_N*_L, 0.0);

double NdotH = pow(MAX(_N*H, 0.0), _shininess);

if(NdotL<=0.0)

NdotH = 0.0;

return IsKs*NdotH;

}

分別計算出射線和物體交點處的環(huán)境光,漫反射和鏡面反射后,那么該射線對應像素的顏色c為

C = ambient + diffuse + specular

于是,我們可以在代碼中添加一個方法叫Tracer(),該方法就是遍歷場景中的每個物體,判斷射線和物體的交點,然后計算交點的顏色。

GVector3 Tracer(CRay R)

{

GVector3 color;

for(/*遍歷每一個物體*/)

{

if(/*如果有交點*/)

{

GVector3 p = R.getPoint(dist);

GVector3 N = m_pObj[k]->getNormal(p);

N.Normalize();

for(/*遍歷每一個光源*/)

{

GVector3 ambient = m_pLight[m]->EvalAmbient(m_pObj[k]->getKa());

GVector3 L = m_pLight[m]->getPosition()-p;

L.Normalize();

GVector3 diffuse = m_pLight[m]->EvalDiffuse(N, L, m_pObj[k]->getKd());

GVector3 V = m_CameraPosition - p;

V.Normalize();

GVector3 specular = m_pLight[m]->EvalSpecluar(N, L, V, m_pObj[k]->getKs(), m_pObj[k]->getShininess());

color = ambient + diffuse + specular;

}

}

}

}

如果要渲染可以反射周圍環(huán)境的物體,就需要稍微修改上面的Tracer()方法,因為反射是一個遞歸的過程,一但一條射線被物體反射,那么同樣的Tracer()方法就要被執(zhí)行一次來計算被反射光線和其他物體是否還有交點。于是,在Tracer()方法中再傳入一個代表遞歸迭代深度的參數(shù)depth,它表示射線與物體相交后反射的次數(shù),如果為1,說明射線與物體相交后不反射,為2表示射線反射一次,以此類推。

Tracer(CRay R, int depth)

{

GVector3 color;

// 計算C = ambient + diffuse + specular

if(TotalTraceDepth == depth)

return color;

else

{

//計算射線和物體交點處的反射射線 Reflect;

GVector3 c = Tracer(Reflect, ++depth);

color += GVector3(color[0]*c[0],color[1]*c[1],color[2]*c[2]);

return color;

}

}

創(chuàng)建一個場景,然后執(zhí)行代碼,可以看到下面的效果。

Fig3 光線追蹤渲染的場景1

如果設置Tracer的遞歸深度大于2的話,就可以看到兩個球相互反射的情況。雖然這個光線追蹤可以正常的執(zhí)行,但是畫面看起來總覺得缺少點什么。仔細觀察你會發(fā)現(xiàn)畫面雖然有光源,但是物體沒有陰影,陰影可以增加場景的真實性。要計算陰影,我們應該從光源的出發(fā),從光源出發(fā)的射線和物體如果有交點,而且這條射線與多個物體相交,那么除第一個交點外的后面所有交點都處于陰影中,這點很容易理解。于是,我們需要修改部分代碼。

GVector3 Tracer(CRay R, int depth)

{

GVector3 color;

double shade = 1.0

for(/*遍歷每一個物體*/)

{

for(/*遍歷每一個光源*/)

{

GVector3 L = pObj[k]->getCenter() - Intersection;

double dist = norm(L);

L *= (1.0f / dist);

CRay r = CRay( Intersection,L );

for ( /*遍歷每一個物體*/ )

{

CGObject* pr = pObj[s];

if (pr->isIntersected(r, dist)!=MISS)

{

shade = 0;

break;

}

}

}

}

if(shade>0)

{

// 計算C = ambient + diffuse + specular

// 遞歸計算反射

}

return color*shade;

}

增加了陰影計算后,再運行程序,就能看到下面的效果。

Fig4 光線追蹤渲染的場景2

最后我們也可以讓地面反射物體,然后再墻上添加很多小球,讓畫面變得復雜一些,如下圖。

Fig5 光線追蹤渲染的場景3

總結

這篇文章通過利用面向?qū)ο蟮姆椒▉韺崿F(xiàn)了光線追蹤渲染場景。利用面向?qū)ο蟮姆椒▉韺崿F(xiàn)光線追蹤使程序的擴展性得到增強,渲染復雜的場景或者復雜的幾何物體的時候,或者有很多光源和復雜光照計算的時候,只需要從基類繼承,然后利用多態(tài)性來實現(xiàn)不同物體的不同渲染方法。

從上面的類圖可以看到,利用面向?qū)ο?/strong>的方式可以很容易擴展程序。而且,由于光線追蹤的這種結構,不論添加多少物體在場景中,不論物體多么復雜,這種結構總能很好地渲染出正確的畫面。

 

但是,對光線追蹤來說,越復雜的場景需要的渲染時間越長。有的時候渲染一幀的畫面甚至需要幾天的時間。所以好的算法和程序結構對于光線追蹤來說是很重要的,可以通過場景管理、使用GPU或CUDA等等技術來提高渲染效率。

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

視頻占全球互聯(lián)網(wǎng)數(shù)據(jù)流量的 69% ,遠超社交媒體( 13% )和游戲( 10% ) 到 2031 年, XR 設備的 出貨 量將翻兩番,達到 8,300 萬臺 現(xiàn)有網(wǎng)絡的局限性已經(jīng)顯而易見, 4...

關鍵字: DIGITAL INTER 無線網(wǎng)絡 6G

慕尼黑 2025年5月13日 /美通社/ -- 2025年5月7日,思格新能源亮相德國慕尼黑太陽能光伏儲能展(Intersolar Europe 2025)。此次展覽思格不僅帶來了覆蓋從家庭到工商業(yè)的全場景光儲解決方案...

關鍵字: SOLAR INTER RS AI

特拉華州威爾明頓2025年4月8日 /美通社/ -- InterDigital, Inc.(納斯達克代碼:IDCC),一家專注于移動通信、視頻和人工智能技術的研發(fā)公司,于2025年4月7日宣布已與惠普簽署了一項新的多年期...

關鍵字: DIGITAL 惠普 INTER 許可協(xié)議

InterDigital將展示其在無線通信、視頻和AI領域的創(chuàng)新成果、與是德科技(Keysight)的研究合作,以及在6G和沉浸式通信未來方面的專業(yè)實力。 特拉華州威爾明頓2025年2月19日 /美通社/ -- Int...

關鍵字: DIGITAL INTER 無線 網(wǎng)絡

兩家公司將展示高精度的基于AI的傳感技術,可適應動態(tài)環(huán)境,應用于沉浸式體驗、入侵檢測、電子健康監(jiān)測等領域 特拉華州威爾明頓2025年2月19日 /美通社/ -- InterDigital, Inc.(納斯達克代碼:ID...

關鍵字: DIGITAL INTER 是德科技 傳感技術

深圳2024年12月16日 /美通社/ -- 在現(xiàn)代工業(yè)快速發(fā)展的進程中,光固化技術正以其獨特的優(yōu)勢重塑著眾多制造工藝。然而,工業(yè)紫外線(UV)的潛在危害也如影隨形,如何有效防范成為了行業(yè)焦點。Dymax作為光固化領域的...

關鍵字: 紫外線 防護 紫外光 反射

特拉華州威爾明頓2024年10月29日 /美通社/ -- InterDigital, Inc.(納斯達克代碼:IDCC),一家專注于移動通信、視頻和人工智能技術的研發(fā)公司,今...

關鍵字: DIGITAL OPPO INTER 許可協(xié)議

特拉華州威爾明頓2024年10月8日 /美通社/ -- InterDigital, Inc.(納斯達克代碼:IDCC)9,一家專注于移動通信、視頻和人工智能技術的研發(fā)公司,今日宣布已與TPV (冠捷)簽署了新的許可協(xié)議,...

關鍵字: DIGITAL INTER 許可協(xié)議 納斯達克

在編程語言的廣闊世界里,C語言以其高效、靈活和接近硬件的特性著稱,但它本身并不直接支持面向?qū)ο缶幊蹋∣OP)的特性,如類、繼承、封裝和多態(tài)等。然而,通過一些巧妙的設計和編程技巧,我們?nèi)匀豢梢栽贑語言中模擬出面向?qū)ο蟮木幊?..

關鍵字: C語言 面向?qū)ο?/a>
關閉