天天看點

NDK OpenGL ES 3.0 開發(十一):模闆測試OpenGL ES 模闆測試聯系與交流

作者:位元組流動

來源:

https://blog.csdn.net/Kennethdroid/article/details/102533260

OpenGL ES 模闆測試

NDK OpenGL ES 3.0 開發(十一):模闆測試OpenGL ES 模闆測試聯系與交流

模闆測試與深度測試類似,主要作用是利用模闆緩沖區(Stencil Buffer)所儲存的模闆值決定目前片段是否被丢棄,且發生于深度測試之前。

圖檔來源:

https://learnopengl.com/Advanced-OpenGL/Stencil-testing

模闆測試一般步驟:

  • 啟用模闆測試,開啟模闆緩沖寫入

    glStencilMask(0xFF)

  • 執行渲染操作,更新模闆緩沖區;
  • 關閉模闆緩沖寫入

    glStencilMask(0x00)

  • 執行渲染操作,利用模闆緩沖區所儲存的模闆值确定是否丢棄特定片段。

啟用模闆測試

glEnable(GL_STENCIL_TEST);

, 清空模闆緩沖區

glClear( GL_STENCIL_BUFFER_BIT);

控制模闆緩沖區是否可以進行寫入:

// 0xFF == 0b11111111
// 模闆值與它進行按位與運算結果是模闆值,模闆緩沖可寫
glStencilMask(0xFF); 

// 0x00 == 0b00000000 == 0
// 模闆值與它進行按位與運算結果是0,模闆緩沖不可寫
glStencilMask(0x00); 
      

模闆測試的配置函數

glStencilFunc

glStencilOp

void glStencilFunc(GLenum func, GLint ref, GLuint mask);      
  • func:設定模闆測試操作。這個測試操作應用到已經儲存的模闆值和

    glStencilFunc

    的 ref 值上,可用的選項是:

    GL_NEVER、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL、GL_ALWAYS ;

  • ref:指定模闆測試的引用值。模闆緩沖區中的模闆值會與這個值對比;
  • mask:指定一個遮罩,在模闆測試對比引用值和儲存的模闆值前,對它們進行按位與(and)操作,初始設定為 1 。
glStencilFunc(GL_EQUAL, 1, 0xFF);
// 表示當一個片段模闆值等于(GL_EQUAL)引用值1,片段就能通過測試被繪制了,否則就會被丢棄。

glStencilFunc(GL_ALWAYS, 1, 0xFF);
// 表示所有片段模闆測試總是通過。

      

glStencilOp

主要用于控制更新模闆緩沖區的方式。

void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);      
  • sfail: 如果模闆測試失敗将如何更新模闆值;
  • dpfail: 如果模闆測試通過,但是深度測試失敗時将如何更新模闆值;
  • dppass: 如果深度測試和模闆測試都通過,将如何更新模闆值。

參數可選操作:

操作 描述
GL_KEEP 保持現有的模闆值
GL_ZERO 将模闆值置為 0
GL_REPLACE 将模闆值設定為用 glStencilFunc 函數設定的ref值
GL_INCR 如果模闆值不是最大值就将模闆值 +1
GL_INCR_WRAP 與 GL_INCR 一樣将模闆值 +1 ,如果模闆值已經是最大值則設為 0
GL_DECR 如果模闆值不是最小值就将模闆值 -1
GL_DECR_WRAP 與 GL_DECR 一樣将模闆值 -1 ,如果模闆值已經是最小值則設為最大值
GL_INVERT 按位反轉目前模闆緩沖區的值

繪制物體輪廓是模闆測試的常見應用,其步驟一般如下:

  • 啟動深度測試和模闆測試,清空模闆緩沖和深度緩沖;
  • 在繪制物體前,設定

    glStencilFunc(GL_ALWAYS, 1, 0xFF);

    ,用 1 更新物體将被渲染的片段對應的模闆值;
  • 渲染物體,寫入模闆緩沖區;
  • 關閉模闆寫入和深度測試;
  • 将物體放大一定比例;
  • 使用一個不同的片段着色器用來輸出一個純顔色(物體輪廓顔色);
  • 再次繪制物體,設定

    glStencilFunc(GL_NOTEQUAL, 1, 0xFF)

    當片段的模闆值不為 1 時,片段通過測試進行渲染;
  • 開啟模闆寫入和深度測試。

關鍵實作的代碼片段:

//啟動深度測試和模闆測試,清空模闆和深度緩沖
glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);

glStencilFunc(GL_ALWAYS, 1, 0xFF); //所有片段都要寫入模闆緩沖
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);//若模闆測試和深度測試都通過了,将片段對應的模闆值替換為1
glStencilMask(0xFF);

//繪制物體
glBindVertexArray(m_VaoId);
glUseProgram(m_ProgramObj);
glUniform3f(m_ViewPosLoc, 0.0f, 0.0f, 3.0f);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glUniform1i(m_SamplerLoc, 0);
UpdateMatrix(m_MVPMatrix, m_ModelMatrix, m_AngleX, m_AngleY , 1.0, glm::vec3(0.0f,  0.0f,  0.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glUniformMatrix4fv(m_ModelMatrixLoc, 1, GL_FALSE, &m_ModelMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);

glStencilFunc(GL_NOTEQUAL, 1, 0xFF);//當片段的模闆值不為 1 時,片段通過測試進行渲染

//禁用模闆寫入和深度測試
glStencilMask(0x00);
glDisable(GL_DEPTH_TEST);

//繪制物體輪廓
glBindVertexArray(m_VaoId);
glUseProgram(m_OutlineProgramObj);
//放大 1.05 倍
UpdateMatrix(m_MVPMatrix, m_ModelMatrix, m_AngleX, m_AngleY, 1.05, glm::vec3(0.0f,  0.0f,  0.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glUniformMatrix4fv(m_ModelMatrixLoc, 1, GL_FALSE, &m_ModelMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);

//開啟模闆寫入和深度測試
glStencilMask(0xFF);
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
      

另外需要注意,在使用 GLSurfaceView 時,新的 API 預設沒有配置模闆緩沖區,需要使用

setEGLConfigChooser

配置模闆緩沖區。

public MyGLSurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.setEGLContextClientVersion(2);
    mGLRender = new MyGLRender();
    /*If no setEGLConfigChooser method is called,
    then by default the view will choose an RGB_888 surface with a depth buffer depth of at least 16 bits.*/
    setEGLConfigChooser(8, 8, 8, 8, 16, 16);//最後 2 個參數表示分别配置 16 位的深度緩沖區和模闆緩沖區
    setRenderer(mGLRender);
    setRenderMode(RENDERMODE_WHEN_DIRTY);

}      
利用模闆測試繪制物體輪廓效果圖

聯系與交流

技術交流/擷取源碼可以添加我的微信:Byte-Flow

視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。
NDK OpenGL ES 3.0 開發(十一):模闆測試OpenGL ES 模闆測試聯系與交流

繼續閱讀