FrameBuffer幀緩衝區及其操作,測試,顏色混合抖動掩碼邏輯寫入
阿新 • • 發佈:2019-01-02
混合是源和目標畫素進行的,抖動是在混合後進行的,上面的操作資料都還是放置在臨時快取區中,寫入掩碼和邏輯操作後才是最終的將結果畫素和目標畫素進行邏輯寫入預設是GL_COPY。深度快取和模板快取的寫入也受到掩碼和操作函式控制,stencil測試公式是:stencil ref &mask op stencil value &mask,sicssor測試更快;alpha測試,深度測試,預設都是禁用的,啟用後測試結果受到自己指定的測試比較函式控制。
現代可程式設計渲染管道中,後期的硬體裁剪測試,alpha測試,模板測試,深度測試(遮擋查詢和條件渲染), 混合,抖動,寫入掩碼和寫入邏輯操作,都可以在fragment shader中設定。
透明效果,抗鋸齒效果(在多重取樣處理邊緣 alpha處理也需要),都是要依賴混合的。
累積快取的這些影象操作(單次或多次繪製物體然後組合結果(時間上的),單次對一副影象多次附近周圍取樣組合結果(空間上)效果:全景抗鋸齒被alpha和多重取樣覆蓋代替,其它操作被OGL 3.0引入的幀緩衝區物件中的浮點畫素格式很容易實現了。
顏色緩衝:
// 當前OGL是否立體渲染(3D渲染)螢幕;Intel是3.1版本; 0 AMD是4.2版本都不支援
// 立體渲染, 也就是前-左,前-右,後-左,後-右快取區; VR中應該就是這樣使用。
// 但每個OGL實現都必須支援前-左快取區。GL_FRONT_LEFT
GLint nStereoSupport;
glGetIntegerv(GL_STEREO, &nStereoSupport); // Win7 OGL 3.1不支援
// 雙快取交換鏈:前臺快取,後臺快取;還是單快取只有前臺快取;Intel是3.1版本; 0 AMD是4.2版本啟用了都支援
GLint nDoubleFrameBufferSupport;
glGetIntegerv(GL_DOUBLEBUFFER, &nDoubleFrameBufferSupport);// Win7 OGL 3.1支援
// 輔助快取;Intel是3.1版本不支援; AMD是4.2版本支援4個輔助顏色快取
// 輔助快取區,OGL並沒有指定這類快取的特定用途,因此可以用來儲存自己需要的幀快取資訊
// 例如從後臺快取區glCopyPixels到這裡,下次渲染從這裡拿到資料,避免重繪。
GLint nAluColorBuffer;
glGetIntegerv(GL_AUX_BUFFERS, &nAluColorBuffer);// Win7 OGL 3.1不支援,只有0個顏色輔助快取
深度緩衝:
儲存的是NDC座標規範化後(基於觀察座標系的距離),OGL z值在[-1,1], DX在[0,1]; 然後在視口變換期間,將該z值用預設的glDepthRange函式將z值縮放到[0,1]之間,當然也可以用glDepthRange指定需要縮放到的深度值。
OGL會將變換後的深度值快取起來,後面光柵化,FragmentShader後,經過了depth Test 可以指定比較函式,那麼該位置的深度值就會和當前的深度快取值比較,通過了則更新該位置的深度值。
累積快取也用於儲存RGBA顏色資料(不能儲存顏色索引模式下的索引值),不能直接寫入,而是從顏色快取區拷貝到累積快取區或者從累積快取區拷貝到顏色快取區(以矩形塊為單位操作的);通常用於把一系列的影象合成一副影象,經典應用是對影象進行超量取樣(多重取樣時超量取樣的特例,多重多邊緣取樣,超量是對整副影象取樣),然後對樣本求平均值,並且將結果寫入到顏色緩衝區實現場景抗鋸齒效果。也可以實現運動模糊,和模擬照片景深效果。OGL3.0以上為浮點顏色快取區實現這些效果,取消了累積緩衝區或輔助快取區的支援。
運動模糊,是將一副周圍場景影象,進行一定的比例縮放顏色成分後,再次寫入到顏色快取區,然後繪製主運動物體,得到運動模糊效果。
景深效果,用accPerspective控制主焦聚平面,模糊程度,多次從不同的角度繪製場景,累積寫入到累積快取,後面一次返回得到一個景深的影象效果。
柔和陰影,是每次用一盞燈繪製場景,多次繪製,累積組合到累積快取中,然後結果輸出到顏色快取中。
抗鋸齒微小移動,在邊緣周圍多次取樣,累積取樣組合後的效果輸出,類似高斯模糊,得到抗鋸齒效果,不需要均勻取樣,在相鄰的畫素上取樣效果更好。
累積快取的這些影象操作(單次或多次繪製物體然後組合結果(時間上的),單次對一副影象多次附近周圍取樣組合結果(空間上):全景抗鋸齒被alpha和多重取樣覆蓋代替,其它操作被OGL 3.0引入的幀緩衝區物件中的浮點畫素格式很容易實現了。
等值, 代表模板測試失敗模板緩衝區操作,模板測試成功深度測試失敗模板緩衝區操作,模板測試和深度測試都成功的模板緩衝區操作。 示例: // 清空模板快取 glClearStencil(0x0); // 啟用模板快取 glEnable(GL_STENCIL_TEST); // glDisable(GL_STENCIL_TEST); // 模板測試函式和參考值寫入到模板快取。 glClear(GL_STENCIL_BUFFER_BIT); glStencilFunc (GL_ALWAYS, 0x1, 0x1); glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); // 繪製1物體,模板測試函式,和參考值寫入到模板快取中 glStencilFunc (GL_EQUAL, 0x1, 0x1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); // 繪製2物體,模板測試函式,和參考值寫入到模板快取中 glStencilFunc (GL_NOTEQUAL, 0x1, 0x1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); (3)模板快取區的應用 繪製不規則的物體,用貼圖來實現。 奇偶跳轉的模板快取: 使用模板快取繪製填充的凹多邊形: 方法是對多邊形引入一個點該點與原來多邊形按順序的兩個點組成一個凸多邊形,繪製每個多邊形對模板快取區進行奇偶選擇寫入,例如奇數次繪製該區域則寫入,偶數將其清除,最後禁止模板快取寫入,開啟顏色快取寫入,則可以將凹多邊形繪製出來。 多個位數的模板快取: 尋找衝突區域:對重疊的三維物體的衝突檢測,重疊衝突會對畫面產生偶爾的閃爍,且繪製空間位置也出現了問題,需要檢測可以從空間角度引入一個裁剪平面來進行物體和該裁剪平面的相交檢測。也可以在模板快取區,維護多個位的模板快取,對需要檢測的一個物體在該位置有畫素那麼寫入1位,其它物體物體是否有畫素寫入1位,另外一個位可以寫入他們的並集或交集位是否為1。
一、幀緩衝區基本概念
幀快取區包括: 1.顏色緩衝區,有前後臺快取區和輔助快取區,OGL3.0以上為浮點顏色快取區,取消了累積緩衝區的支援。 2.模板緩衝區。 3.深度緩衝區。 顏色模板深度快取區畫素位置是一一對應的。各種緩衝區的成分位數:
GLint rBits, gBits, bBits, aBits; glGetIntegerv(GL_RED_BITS, &rBits);//8 glGetIntegerv(GL_GREEN_BITS, &gBits);//8 glGetIntegerv(GL_BLUE_BITS, &bBits);//8 glGetIntegerv(GL_ALPHA_BITS, &aBits);//8 GLint iBits, dBits, sBits; //顏色快取區中的顏色索引資料, Intel是3.1版本是32; AMD是4.2版本是0,顏色索引資料取消了 glGetIntegerv(GL_INDEX_BITS, &iBits); glGetIntegerv(GL_DEPTH_BITS, &dBits);//24 glGetIntegerv(GL_STENCIL_BITS, &sBits);//8 // Intel是3.1版本; 0 AMD是4.2版本OGL實現都廢棄了ACCUM累積快取 // 因為OGL 3.0引入了支援本地浮點值的顏色快取區,ACCUM快取相關的事情很容易在浮點緩衝區上實現。 GLint acRBits, acGBits, acBBits, acABits; glGetIntegerv(GL_ACCUM_RED_BITS, &acRBits);//0 glGetIntegerv(GL_ACCUM_GREEN_BITS, &acGBits);//0 glGetIntegerv(GL_ACCUM_BLUE_BITS, &acBBits);//0 glGetIntegerv(GL_ACCUM_ALPHA_BITS, &acABits);//0顏色緩衝:
// 當前OGL是否立體渲染(3D渲染)螢幕;Intel是3.1版本; 0 AMD是4.2版本都不支援
// 立體渲染, 也就是前-左,前-右,後-左,後-右快取區; VR中應該就是這樣使用。
// 但每個OGL實現都必須支援前-左快取區。GL_FRONT_LEFT
GLint nStereoSupport;
glGetIntegerv(GL_STEREO, &nStereoSupport); // Win7 OGL 3.1不支援
// 雙快取交換鏈:前臺快取,後臺快取;還是單快取只有前臺快取;Intel是3.1版本; 0 AMD是4.2版本啟用了都支援
GLint nDoubleFrameBufferSupport;
glGetIntegerv(GL_DOUBLEBUFFER, &nDoubleFrameBufferSupport);// Win7 OGL 3.1支援
// 輔助快取;Intel是3.1版本不支援; AMD是4.2版本支援4個輔助顏色快取
// 輔助快取區,OGL並沒有指定這類快取的特定用途,因此可以用來儲存自己需要的幀快取資訊
// 例如從後臺快取區glCopyPixels到這裡,下次渲染從這裡拿到資料,避免重繪。
GLint nAluColorBuffer;
glGetIntegerv(GL_AUX_BUFFERS, &nAluColorBuffer);// Win7 OGL 3.1不支援,只有0個顏色輔助快取
深度緩衝:
儲存的是NDC座標規範化後(基於觀察座標系的距離),OGL z值在[-1,1], DX在[0,1]; 然後在視口變換期間,將該z值用預設的glDepthRange函式將z值縮放到[0,1]之間,當然也可以用glDepthRange指定需要縮放到的深度值。
OGL會將變換後的深度值快取起來,後面光柵化,FragmentShader後,經過了depth Test 可以指定比較函式,那麼該位置的深度值就會和當前的深度快取值比較,通過了則更新該位置的深度值。
模板緩衝:
方便實現規則或不規則形狀的遮罩效果。 一般需要二次繪製,設定模板快取初始值和寫入策略,第一次繪製時候將指定形狀(一般是影象指定)的資料寫入模板快取對應位置,後面再次渲染場景物體時候根據設定的模板比較函式,確定是否寫入到後臺快取中,並確定是否更新模板快取。累積緩衝:
二、緩衝區的基本操作:
1.清除緩衝區
先設定緩衝區的值,然後每次清理的時候將會採用該值。 // default value is 0.0f glClearColor(0.0, 0.0, 0.0, 0.0); // default value is 1.0f glClearDepth(1.0f); // default value is 0 glClearIndex(0.0f); // default value is 0 glClearStencil(0); // 清理 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //(GLenum buffer, GLint drawBuffer, GLfloat depth, GLint stencil); glClearBufferfi(GL_DEPTH_STENCIL, 0, 1, 0);2.選擇用於讀取和寫入的顏色緩衝區
1)選擇用於寫入或清除的顏色快取區,並禁用以前設定的寫入的顏色快取區 glDrawBuffer(GL_FRONT); // 預設情況下單快取是GL_FRONT, 雙快取是GL_BACK。 OGL 3.0增加了幀緩衝區物件,當OpenGL繫結到一個使用者指定的幀緩衝區,那麼用GL_COLOR_ATTACHMENTi來指定那個顏色渲染緩衝區是繪製目標,i值在0和GL_MAX_COLOR_ATTACHMENTS之間。 GLint num = 0; glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &num); // 輸出8 GLenum buffers[] = { GL_FRONT, GL_FRONT_LEFT, GL_BACK_RIGHT } glDrawBuffers(3, buffers); #define GL_FRONT_LEFT 0x0400 #define GL_FRONT_RIGHT 0x0401 #define GL_BACK_LEFT 0x0402 #define GL_BACK_RIGHT 0x0403 #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_LEFT 0x0406 #define GL_RIGHT 0x0407 #define GL_FRONT_AND_BACK 0x0408 #define GL_AUX0 0x0409 #define GL_AUX1 0x040A #define GL_AUX2 0x040B #define GL_AUX3 0x040C 2選擇讀取的顏色快取區,用於glReadPixels(),glCopyPixels(), glCopyTexImage*(), glCopyTexSubImage*()和glCopyConvolutionFilter*()的畫素讀取來源,並禁用以前呼叫的glReadBuffer時所啟用的快取區。 glReadBuffer (GLenum mode);// 預設情況下單快取是GL_FRONT, 雙快取是GL_BACK OGL 3.0增加了幀緩衝區物件,當OpenGL繫結到一個使用者指定的幀緩衝區,那麼用GL_COLOR_ATTACHMENTi來指定那個顏色渲染緩衝區是讀取目標,i值在0和GL_MAX_COLOR_ATTACHMENTS之間。3.緩衝區的遮蔽寫入
在對啟用的幀緩衝區進行寫入之前,會對資料執行遮蔽操作,所有的掩碼都使用邏輯AND操作進行組合(非布林型別的需要要寫入的值和對應位置的掩碼值進行AND操作),以寫入對應的資料。 //mask中出現1那麼寫入,0拒絕 glIndexMask(GLuint mask); // GL_TRUE表示對應的顏色成分寫入,GL_FALSE拒絕 glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); glColorMaski(GLuint buf, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); // GL_TRUE深度緩衝可以寫入,GL_FALSE不寫入;只是決定寫入深度快取區,通過了測試才到這步 glDepthMask(GLboolean flag); // mask中出現1那麼寫入,0拒絕;只是對當前模板快取區中的值進行控制,通過了測試才到這步 glStencilMask(GLuint mask); // 控制對應的面掩碼,(GLenum face, GLuint mask); mask中出現1那麼寫入,0拒絕 glStencilMaskSeparate();三、幀快取區的測試,顏色混合抖動邏輯操作
其實現代很多的後期操作,都放到了fragment shader中設定。 但傳統的,在片段Fragment著色處理後(抗鋸齒,光照輔助顏色,霧化處理後),還需要進行進一步的操作,操作順序是:1)scissor test
預設情況下scissor測試被禁用。 // 裁剪測試可以用硬體快速執行,比Stencil快很多,但是隻能是矩形的 // 對應Unity中的Mask2D, Stencil對應Unity中的Mask可以是按照遮罩形狀來遮罩 glEnable(GL_SCISSOR_TEST);// 預設是禁用的 // 螢幕座標系下的x,y,width, height glScissor(GLint x, GLint y, GLsizei width, GLsizei height); glDisable(GL_SCISSOR_TEST); GLboolean scissor = glIsEnabled(GL_SCISSOR_TEST);// 預設不啟用 GLint box[4]; glGetIntegerv(GL_SCISSOR_BOX, box);// 預設是螢幕的大小2)alpha test
預設情況下alpha測試被禁用。 如果啟用,它就把源片斷的alpha值和一個參考值進行比較,並根據比較結果接受或拒絕這個片斷。 在預設情況下這個參考值是0,比較函式式GL_AWAYS, alpha測試被禁用。OGL3.1後alpha test被廢棄了,代替操作是在fragment shader中通過discard操作來廢棄片斷。用途是過濾一定透明度的物體。貼花可以採用alpha過濾技術。 glEnable(GL_ALPHA_TEST); glDisable(GL_ALPHA_TEST); glAlphaFunc(GL_ALWAYS, 0.5f); #define GL_NEVER 0x0200 #define GL_ACCUM_BUFFER_BIT 0x00000200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x02073)stencil test
預設情況下模板測試也是禁用的。 (1).模板測試和模板測試函式: glStencilFunc (GLenum func, GLint ref, GLuint mask); glStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask); 模板快取的測試公式是: 當前模板ref&mask op 顏色快取對應的當前模板快取value&mask, ref為左值,value為右值,mask是設定模板快取比較函式時候指定的。如果op比較函式為true那麼通過測試,false則不通過。 func值為: #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 (2)模板快取的寫入: 模板快取不能直接寫入,但是可以通過將不規則形狀寫入顏色快取draw call,然後更新模板快取中對應位置的值。 glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); // fail,zfail,zpass的值可以是: #define GL_KEEP 0x1E00 // 保持模板快取中的值 #define GL_REPLACE 0x1E01 // 用參考值替換當前模板快取中的值 #define GL_INCR 0x1E02// 增加當前模板快取中的值,超過最大值為最大值或者重置0 #define GL_DECR 0x1E03// 減少當前模板快取中的值,超過最小值為最小值或者重置0 原理:渲染了一個物體,寫入了模板快取值。渲染第二個物體,時候會用當前的模板快取值進行模板測試判斷,這樣通過第二個物體的渲染依賴於一個物體得到想要的結果,這是模板快取的核心思想。等值, 代表模板測試失敗模板緩衝區操作,模板測試成功深度測試失敗模板緩衝區操作,模板測試和深度測試都成功的模板緩衝區操作。 示例: // 清空模板快取 glClearStencil(0x0); // 啟用模板快取 glEnable(GL_STENCIL_TEST); // glDisable(GL_STENCIL_TEST); // 模板測試函式和參考值寫入到模板快取。 glClear(GL_STENCIL_BUFFER_BIT); glStencilFunc (GL_ALWAYS, 0x1, 0x1); glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE); // 繪製1物體,模板測試函式,和參考值寫入到模板快取中 glStencilFunc (GL_EQUAL, 0x1, 0x1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); // 繪製2物體,模板測試函式,和參考值寫入到模板快取中 glStencilFunc (GL_NOTEQUAL, 0x1, 0x1); glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); (3)模板快取區的應用 繪製不規則的物體,用貼圖來實現。 奇偶跳轉的模板快取: 使用模板快取繪製填充的凹多邊形: 方法是對多邊形引入一個點該點與原來多邊形按順序的兩個點組成一個凸多邊形,繪製每個多邊形對模板快取區進行奇偶選擇寫入,例如奇數次繪製該區域則寫入,偶數將其清除,最後禁止模板快取寫入,開啟顏色快取寫入,則可以將凹多邊形繪製出來。 多個位數的模板快取: 尋找衝突區域:對重疊的三維物體的衝突檢測,重疊衝突會對畫面產生偶爾的閃爍,且繪製空間位置也出現了問題,需要檢測可以從空間角度引入一個裁剪平面來進行物體和該裁剪平面的相交檢測。也可以在模板快取區,維護多個位的模板快取,對需要檢測的一個物體在該位置有畫素那麼寫入1位,其它物體物體是否有畫素寫入1位,另外一個位可以寫入他們的並集或交集位是否為1。