模版測試——實現物體輪廓線效果
模版測試用途
模版測試是圖形渲染管線中位於片元著色器之後深度測試之前的一個階段,其主要用途為實現一些效果:物體輪廓、在一個後視鏡中繪製紋理、使用陰影體積(Shadow Volume)的模版緩衝技術渲染實時陰影。
物體輪廓
而許多RTS遊戲中常見到的物體被框選的效果,也是通過模版測試來實現的。例如下圖中,綠色的線條表現了物體的輪廓。
基本思路
模版測試的工作機制為將頂點著色器得到的顏色緩衝(Color Buffer)與一個與其尺寸相同的模版緩衝(Stencil Buffer)進行特定的操作,例如下圖中,只有當模版值為1的時候,顏色緩衝中的片段才會被渲染。
有了模版測試這樣的工具,若我們將物體片段所在位置的模版緩衝值置為1,再使用輪廓顏色繪製一個放大過後的物體並只在模版緩衝值不為1的時候繪製,即可得到輪廓效果。
具體實現
1:啟用模版測試
我們首先啟用模板測試,並設定測試通過或失敗時的行為:
glEnable(GL_DEPTH_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
2:正常繪製物體,並將物體片段所在區域的模版緩衝值設為1
// 1st. render pass, draw objects as normal, writing to the stencil buffer // -------------------------------------------------------------------- glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilMask(0xFF); normalShader.use(); DrawTwoContainers(); ... ...
使用normalShader繪製一遍物體,其中,glStencilFunc(GLenum func, GLint ref, GLuint mask)函式控制OpenGL應該對模版緩衝內容做什麼,或者說顏色緩衝會怎樣受到模版緩衝的影響,例如:
glStencilFunc(GL_EQUAL, 1, 0xFF)
表示只要片段的模版值等於(GL_EQUAL)參考值1,片段將會通過測試並被繪製,否則會被丟棄。
而glStencilMask函式是模版值即將寫入模版緩衝前的一個操作,其起到的作用大多數為啟用和禁用模版緩衝寫入,在這裡我們傳入的引數是0xFF,其代表有物體片段的地方模版值都將設為1。
3:繪製放大後的物體,並當模版值不為1的時候才通過模版測試
// 2nd. render pass: now draw slightly scaled versions of the objects, this time disabling stencil writing.
// -----------------------------------------------------------------------------------------------------------------------------
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00);
glDisable(GL_DEPTH_TEST);
shaderSingleColor.use();
...
glStencilMask(0xFF);
使用shaderSingleColor這個 shader再次繪製物體時,模版緩衝中已經有了前一個normalShader繪製時寫入的模版值了,故
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
將使得模版值不等於1的片段通過模版測試,隨後
glStencilMask(0x00);
防止此時的模版緩衝被更新和寫入。
參考
LearnOpenGL:https://learnopengl-cn.github.io/04 Advanced OpenGL/02 Stencil testing/