OpenGL視椎體 裁剪和剔除

2021-08-19 15:35:25 字數 2414 閱讀 7326

畢設做的是《基於四叉樹的lod地形渲染》,其中主要參考了潘李亮的《基於lod的大規模真實感室外場景試試渲染技術的初步研究》一文,如有有興趣做四叉樹lod的話,建議讀一讀這篇文章。但是在這篇文章的視椎體裁剪部分,說的不是很清除,而且在求解視椎體六個面的方程和判斷aabb包圍盒的與視椎體是否相交的方法上,不知道是我的理解問題還是他的實現有問題,裁剪出的結果總是有問題,查閱資料後,給出我的詳細實現。

在進行視椎體體剔除時,要求出視椎體六個面在區域性座標系中的方程才能進行判斷。求解視椎體六個面的方程這篇文章給出了非常好的說明。此處就直接以來上文中的方法來說明吧。在進行了投影變換後,視椎體從平截頭體變成了乙個正方體(ndc規範化座標),正方體的xyzzuo座標都是(-1,1)之間。

假設空間中一點p(x,y,z,1)經過這一系列變換變成p1(x1/w1,y1/w1,z1/w1,1) 並且假設projectmatrix左乘modelviewmatrix得到的第一行是(a,b,c,d),那麼有

a*x+b*y+c*z+d=x1

假設變換矩陣的最後一行(e,f,g,h),那麼有

e*x+f*y+g*z+h=w1

因為p1在ndc座標系,範圍是-1到1,那麼在視景體左面上的點都符合x1/w1=-1,式子可以變為x1+w1=0

代入之前的等式:

a*x+b*y+c*z+d+e*x+f*y+g*z+h=0

於是得到: 

(a+e)*x+(b+f)*y+(c+g)*z+(d+h)=0

一般的平面方程是:

a*x+b*y+c*z+d=0 (a,b,c)是平面的法向量

於是左側平面的方程就是

(a+e)*x+(b+f)*y+(c+g)*z+(d+h)=0 其中的x,y,z就是空間中的點座標。

以上是理論基礎,具體各個面的方程計算方法如下(假設矩陣clip=project*view*model。下面的clip[n]代表clip矩陣的第幾列,nomalize代表將向量進行歸一化,即將向量的模長變為1

):

上平面:nomalize(clip[3]-clip[1])

下平面:nomalize(clip[3]+clip[1])

左平面:nomalize(clip[3]+clip[0])

右平面:nomalize(clip[3]-clip[0])

近平面:nomalize(clip[3]+clip[2])

遠平面:nomalize(clip[3]-clip[2])

注意,以上計算的得到的結果是乙個四維向量,向量中的xyzw值分別代表乙個平面方程ax+by+cz+d=0中的a、b、c、d的值。另外需要注意的是,平面方程ax+by+cz+d=0中的(a,b,c)代表的是該平面的法向量,而且通過上式計算出的法向量(a,b,c)都是指向視椎體內部的。(指向外部也可以只需要ax+by+cz+d=0變成-ax-by-cz-d=0即可,此時法向量就是(-a,-b,-c)

)。視椎體裁剪就是將不在視椎體中的物體剔除掉不繪製,而在視椎體內部或與視椎體相交的物體繪製的方法,此舉對效能的提公升有著巨大 的幫助。通常,物體是不規則的,為了方便,我們通常製作乙個包圍體,判斷包圍體與視椎體的關係。包圍體一般有球體和長方體兩種。球包圍體的判斷非常簡單,只需要判斷球心到視椎體每個面的距離與半徑的關係,此處不予討論。主要說明長方體的判斷,這也正是我認為潘李亮大神**中有錯誤的地方。

首先說明,如何判斷乙個點在平面的某一側的方法:已知平面方程為ax+by+cz+d=0,將乙個點p(x,1y1,z1)的座標帶入平面方程得r=ax1+by1+cz1+d,如果計算結果r>0,,則表示p在法向量(a,b,c)指向的一側,同理,r<0,表示在法向量的另一側。潘李亮大神的判斷正是基於此,將長方體包圍盒的頂點帶入視椎體六個面的方程,如果計算得到的六個值都大於0,則表示該點在視椎體內。通過這種方法,只要長方體包圍盒的8個頂點有乙個頂點在視椎體內,就說明實際物體模型能看得見,就需要繪製。但是這個方法有乙個致命的缺陷,就是有些長方體的8個頂點全在視椎體外,但長形體仍然與視椎體有交集,不能被剔除,如下圖所示,黃色長方體不應該剔除,但是用上述方法就會被錯誤剔除。另一種情況是,長方體包圍盒很大,視椎體在長方體內部,也會被錯誤剔除,我用這種方法就是有一些地形塊被錯誤剔除渲染不出來。

下面說查閱到的正確方法:判斷時,只有當長方體所有的頂點位於同一平面的外側時,才認為這個長方體包圍盒在視椎體外面。這樣會將一些在視椎體外面的包圍盒錯誤的判斷成在與視椎體有交集,但是數量很少,可以接受。下面給出程式實現:

bool isvisable()

if (!in)

return false;

else

return true;

}}

這樣,視椎體裁剪就完成了,如有錯誤,歡迎批評指正。

畢設快做完了,其中遇到了挺多問題,等答辯結束了將整個四叉樹lod的構造過程寫乙個系列部落格吧。

OpenGL概念辨析 視窗,視口,裁剪區域

1.視窗 這就不用解釋了吧 2.視口 就是視窗中用來顯示圖形的一塊矩形區域,它可以和視窗等大,也可以比視窗大或者小。只有繪製在視口區域中的圖形才能被顯示,如果圖形有一部分超出了視口區域,那麼那一部分是看不到的。通過glviewport 函式設定。如下圖所示 圖1.不同大小的視口 3.裁剪區域 平行投...

裁剪區域和視口區域(2)

解釋 1 void glutreshapefunc void func int width,int height glut定義了當視窗大小改變時glutreshapefunc 函式應該被呼叫。此外,這個函式還會在視窗初次被建立時呼叫,保證初始化視窗不是正方形的時候渲染也不會變形出錯。2 自定義函式c...

OpenGL學習筆記之背面剔除和深度測試

glfrontface gl cw glcullface gl back glenable gl cull face 開啟背面剔除 gldisable gl cull face 關閉背面剔除.glutinitdisplaymode glut double glut rgba glut depth 設...