OpenGL超级宝典笔记——遮挡查询 [转]
目錄[-]
- 遮擋查詢之前
- 包圍體
- 遮擋查詢
在一個場景中,如果有有些物體被其他物體遮住了不可見。那么我們就不需要繪制它。在復(fù)雜的場景中,這可以減少大量的頂點(diǎn)和像素的處理,大幅度的提高幀率。遮擋查詢就是允許我們判斷一組圖形在進(jìn)行了深度測試之后是否可見。
遮擋查詢之前
為了顯示遮擋查詢對性能的提升,我們需要一個對照組(不使用遮擋查詢來渲染場景)。
首先我們先繪制“主遮擋物”。這個主遮擋物不需要太多的細(xì)節(jié),一般是墻,天花板,地板之類的物體。在下面的例子中我們,使用6面墻來組成這個主遮擋物。
void?DrawOccluder() {glColor3f(0.5f,?0.25f,?0.0f);glPushMatrix();glScalef(30.0f,?30.0f,?1.0f);glTranslatef(0.0f,?0.0f,?50.0f);glutSolidCube(10.0f);glTranslatef(0.0f,?0.0f,?-100.0f);glutSolidCube(10.0f);glPopMatrix();glPushMatrix();glScalef(1.0f,?30.0f,?30.0f);glTranslatef(50.0f,?0.0f,?0.0f);glutSolidCube(10.0f);glTranslatef(-100.0f,?0.0f,?0.0f);glutSolidCube(10.0f);glPopMatrix();glPushMatrix();glScalef(30.0f,?1.0f,?30.0f);glTranslatef(0.0f,?50.0f,?0.0f);glutSolidCube(10.0f);glTranslatef(0.0f,?-100.0f,?0.0f);glutSolidCube(10.0f);glPopMatrix(); }現(xiàn)在我們在每一個單元格中,放置一個高度分挌化的紋理球體。這些球體可能是被遮擋物,也可能是遮擋物。
void?DrawSphere(GLint?sphereNum)? {?...glutSolidSphere(50.0f,?200,?200);? ...}void?DrawModels(void)? {?//開啟紋理?自動生成紋理坐標(biāo)glEnable(GL_TEXTURE_2D);?glEnable(GL_TEXTURE_GEN_S);?glEnable(GL_TEXTURE_GEN_T);?//繪制27個不同顏色的球體for?(r?=?0;?r?<?3;?r++)?{?for?(g?=?0;?g?<?3;?g++)?{?for?(b?=?0;?b?<?3;?b++)?{?glColor3f(r?*?0.5f,?g?*?0.5f,?b?*?0.5f);?glPushMatrix();?glTranslatef(100.0f?*?r?-?100.0f,??100.0f?*?g?-?100.0f,??100.0f?*?b?-?100.0f);?DrawSphere((r*9)+(g*3)+b);?glPopMatrix();?}?}?}?glDisable(GL_TEXTURE_2D);?glDisable(GL_TEXTURE_GEN_S);?glDisable(GL_TEXTURE_GEN_T);?}在我的機(jī)器上沒有遮擋查詢下渲染的幀率是20左右。
包圍體
在遮擋查詢中,如果一個物體的邊界都是不可見的,那么就代表這個物體不可見。所以我們只需檢測物體外圍的包圍體可見,就可以判斷物體是否被遮擋。物 體外圍的包圍體包含著整個物體,這也就意味著包圍體的體積是大于等于物體的體積的。對于一個球體來說,包圍體可以有很多種,最常見的就是立方盒子,四面體 等。
為什么要選擇包圍體去判斷遮擋,而不是直接用球體的。因為球體太過于復(fù)雜,包含的頂點(diǎn)也多,渲染較耗時。遮擋之所以能夠提升性能,就是我們可以在無 光照,無紋理等其他效果的下,并且不需要改變緩沖區(qū)的值,先渲染簡單的包圍體。通過這些包圍體進(jìn)行深度測試,我們就能判斷出哪些物體被遮擋,那些被遮擋的 物體就可以不需要被渲染(不需要調(diào)用任何渲染該物體的命令),如果這個物體擁有非常多的頂點(diǎn),那么遮擋在這個時候就能大幅度的提高性能。
遮擋查詢
遮擋查詢的步驟:
首先為這些物體生成查詢對象ID 調(diào)用glGenQueries
調(diào)用glBeginQuery開始遮擋查詢
渲染包圍體
調(diào)用glEndQuery 結(jié)束遮擋查詢
調(diào)用glGetQueryObject[u]iv,根據(jù)ID提取遮擋查詢的結(jié)果,并根據(jù)結(jié)果進(jìn)行相應(yīng)的操作
glDeleteQueries 刪除ID,回收資源
查詢對象的標(biāo)識符(ID/名稱)是一個無符號整數(shù),我們可以通過glGenQueries函數(shù)生成,也可以自己定義。一般用OpenGL提供的glGenQueries會比較方便。
void glGenQueries(GLsizei n, GLuint *ids);
第一個參數(shù)是生成ID的個數(shù),第二個參數(shù)是來存放這些ID的數(shù)組。0是保留的ID,不會被產(chǎn)生。我們還可以通過glIsQuery來判斷一個ID是否是一個遮擋查詢對象的ID。
void glIsQuery(GLuint id);
如果是返回GL_TRUE,不是則返回GL_FALSE。
有了遮擋查詢對象的ID后,可以開始遮擋查詢了。例如
glBeginQuery(GL_SAMPLES_PASSED,?1); glBegin(GL_TRIANGLES);glVertex3f(1.0f,?1.0f,?0.0f);glVertex3f(-1.0f,?5.0f,?0.0f);glVertex3f(6.0f,?20.0f,?0.0f); glEnd(); glEndQuery(GL_SAMPLES_PASSED);void glBeginQuery(GLenum target, GLuint id);
其中target必須是GL_SAMPLES_PASSED. id是用來標(biāo)識這次遮擋查詢的ID。
void glEndQuery(GLenum target);結(jié)束這次遮擋查詢,其中target必須是GL_SAMPLES_PASSED。
在完成對需要遮擋查詢的物體渲染之后,我們需要提取遮擋查詢的結(jié)果,可以通過glGetQueryObject[u]iv來提取結(jié)果,函數(shù)將返回片段或采樣的數(shù)量。
void glGetQueryObjectiv(GLenum id, GLenum pname, GLint *param);
void glGetQueryObjectuiv(GLenum id, GLenum pname, GLuint *param);
id是這個遮擋查詢對象的id,pname如果是GL_QUERY_RESULT, param將包含了通過深度測試的片段或樣本(如果啟用了多重采樣)的數(shù)量,如果數(shù)量為0,則表示這個物體完全被遮擋。
在完成遮擋查詢操作時,可能會有延遲。我們可以通過設(shè)置pname為GL_QUERY_RESULT_AVAILABLE來檢查是否完成了。如果遮擋查詢有效地完成了,則param將為GL_TRUE,否則為GL_FALSE.
例:
int?count?=?1000;?//等待1000次循環(huán) GLuint?queryReady?=?GL_FALSE; while?(!queryReady?&&?count--) {glGetQueryObjectuiv(1,?GL_QUERY_RESULT_AVAILABLE,?&queryReady); }GLuint?samples;glGetQueryObjectuiv(1,?GL_QUERY_RESULT,?&samples); if(samples?>?0)DrawSomething();使用完遮擋查詢對象之后,調(diào)用glDeleteQueries回收資源。
void glDeleteQueries(GLsizei n, const GLuint *ids);
修改前面的例子,我們可以先渲染27個球體的包圍體,進(jìn)行遮擋查詢,如果有哪個包圍體被完全遮擋,我們就不需要繪制這個球體了。代碼片段如下:
void?DrawModels(void)? {?GLint?r,?g,?b;?//繪制主遮擋物DrawOccluder();?//在繪制包圍體時,越簡單越好。關(guān)掉紋理,光照等等。//不需要往緩沖區(qū)中寫值。glShadeModel(GL_FLAT);?glDisable(GL_LIGHTING);?glDisable(GL_COLOR_MATERIAL);?glDisable(GL_NORMALIZE);?glDepthMask(GL_FALSE);?glColorMask(0,?0,?0,?0);?//?畫27個立方體for?(r?=?0;?r?<?3;?r++)?{?for?(g?=?0;?g?<?3;?g++)?{?for?(b?=?0;?b?<?3;?b++)?{?if?(showBoundingVolume)?glColor3f(r?*?0.5f,?g?*?0.5f,?b?*?0.5f);?glPushMatrix();?glTranslatef(100.0f?*?r?-?100.0f,??100.0f?*?g?-?100.0f,??100.0f?*?b?-?100.0f);?//開始遮擋查詢glBeginQuery(GL_SAMPLES_PASSED,?queryIDs[(r*9)+(g*3)+b]);?//繪制包圍體glutSolidCube(100.0f);?//結(jié)束遮擋查詢glEndQuery(GL_SAMPLES_PASSED);?glPopMatrix();?}?}?}//恢復(fù)正常的渲染狀態(tài)glDisable(GL_POLYGON_STIPPLE);?glShadeModel(GL_SMOOTH);?glEnable(GL_LIGHTING);?glEnable(GL_COLOR_MATERIAL);?glEnable(GL_NORMALIZE);?glColorMask(1,?1,?1,?1);?glDepthMask(GL_TRUE);?//開啟紋理?自動生成紋理坐標(biāo)glEnable(GL_TEXTURE_2D);?glEnable(GL_TEXTURE_GEN_S);?glEnable(GL_TEXTURE_GEN_T);?//繪制27個不同顏色的球體for?(r?=?0;?r?<?3;?r++)?{?for?(g?=?0;?g?<?3;?g++)?{?for?(b?=?0;?b?<?3;?b++)?{?glColor3f(r?*?0.5f,?g?*?0.5f,?b?*?0.5f);?glPushMatrix();?glTranslatef(100.0f?*?r?-?100.0f,??100.0f?*?g?-?100.0f,??100.0f?*?b?-?100.0f);?//函數(shù)中根據(jù),遮擋查詢的結(jié)果來判斷是否要繪制這個球體DrawSphere((r*9)+(g*3)+b);?glPopMatrix();?}?}?}?glDisable(GL_TEXTURE_2D);?glDisable(GL_TEXTURE_GEN_S);?glDisable(GL_TEXTURE_GEN_T);? } void?DrawSphere(GLint?sphereNum)? {?GLboolean?occluded?=?GL_FALSE;?if?(occlusionDetection)?{?GLint?passingSamples;?//檢查物體是否被完全遮擋glGetQueryObjectiv(queryIDs[sphereNum],?GL_QUERY_RESULT,??&passingSamples);?if?(passingSamples?==?0)?occluded?=?GL_TRUE;?}?//沒有被遮擋則繪制if?(!occluded)?{?glutSolidSphere(50.0f,?200,?200);?}? }有了遮擋查詢后,幀率達(dá)到了32左右,當(dāng)然還要看觀察場景的角度。如果從某個角度看大部分球體都被遮擋了,性能的提升更大。
?
在osg中 example_osgocclusionquery
一)演示了osg::OcclusionQueryNode的使用。
轉(zhuǎn)載于:https://www.cnblogs.com/mazhenyu/p/5083026.html
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的OpenGL超级宝典笔记——遮挡查询 [转]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大二第一学期期末课程设计 2015.12
- 下一篇: Android HttpURLConne