作者:位元組流動
來源:
https://blog.csdn.net/Kennethdroid/article/details/102630858OpenGL ES 混合
OpenGL ES 混合本質上是将 2 個片元的顔色進行調和,産生一個新的顔色。OpenGL ES 混合發生在片元通過各項測試之後,準備進入幀緩沖區的片元和原有的片元按照特定比例權重計算出最終片元的顔色值,不再是新(源)片元直接覆寫緩沖區中的(目标)片元。
OpenGLES 混合方程:

啟用 OpenGL ES 混合使用
glEnable(GL_BLEND);
。
然後通過
void glBlendFunc(GLenum sfactor, GLenum dfactor);
設定混合的方式,其中 sfactor 表示源因子,dfactor 表示目标因子。
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// GL_SRC_ALPHA 表示源因子取值為源顔色的 alpha
// GL_ONE_MINUS_SRC_ALPHA 表示目标因子取值為 1- alpha(源顔色的 alpha)
// 操作符預設為 GL_FUNC_ADD ,即權重相加。
// 混合公式變成了 源顔色向量 × alpha + 目标顔色向量 × (1- alpha)
GL_SRC_ALPHA
表示源因子取值為源顔色 alpha (透明度)通道值,
GL_ONE_MINUS_SRC_ALPHA
表示目标因子取值為 1- alpha(源顔色的 alpha),由于操作符預設為
GL_FUNC_ADD
,即元素相加,是以混合公式變成了
源顔色向量 × alpha + 目标顔色向量 × (1- alpha)
混合因子表:
混合因子 | 值 |
GL_ZERO | |
GL_ONE | 1 |
GL_SRC_COLOR | 源顔色向量C s o u r c e C_{source}Csource |
GL_ONE_MINUS_SRC_COLOR | 1−C s o u r c e C_{source}Csource |
GL_DST_COLOR | 目标顔色向量C d e s t i n a t i o n C_{destination}Cdestination |
GL_ONE_MINUS_DST_COLOR | 1−C d e s t i n a t i o n C_{destination}Cdestination |
GL_SRC_ALPHA | C s o u r c e C_{source}Csource的alpha值 |
GL_ONE_MINUS_SRC_ALPHA | 1− C s o u r c e C_{source}Csource的alpha值 |
GL_DST_ALPHA | C d e s t i n a t i o n C_{destination}Cdestination的alpha值 |
GL_ONE_MINUS_DST_ALPHA | 1− C d e s t i n a t i o n C_{destination}Cdestination的alpha值 |
GL_CONSTANT_COLOR | 常顔色向量C c o n s t a n t C_{constant}Cconstant |
GL_ONE_MINUS_CONSTANT_COLOR | 1−C c o n s t a n t C_{constant}Cconstant |
GL_CONSTANT_ALPHA | C c o n s t a n t C_{constant}Cconstant的alpha值 |
GL_ONE_MINUS_CONSTANT_ALPHA | 1− C c o n s t a n t C_{constant}Cconstant的alpha值 |
我們也可以通過
void glBlendEquation(GLenum mode)
自定義操作符:
我們可以為 RGB 和 alpha 通道各自設定不同的混合因子,使用
glBlendFuncSeperate
:
//對 RGB 和 Alpha 分别設定 BLEND 函數
//void glBlendFuncSeparate(GLenum srcRGB,GLenum dstRGB,GLenum srcAlpha,GLenum dstAlpha);
glBlendFuncSeperate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ONE, GL_ZERO);
代碼對應的混合公式為:
混合結果顔色 RGB 向量 = 源顔色 RGB 向量 × alpha + 目标顔色 RGB 向量 × (1- alpha);
混合結果顔色 alpha = 源顔色 alpha × 1 + 目标顔色 alpha × 0;
當然我們也可以為 RGB 和 alpha 通道各自設定不同操作符:
void glBlendEquationSeparate(GLenum modeRGB,GLenum modeAlpha);
另外需要格外注意的是,開啟混合和深度測試繪制透明物體時,需要遵循物體距觀察者(Camera)的距離,由遠到近開始繪制,這樣可以避免由于深度測試開啟後(在透明物體後面)丢棄片元造成的奇怪現象。
未按照順序繪制
由遠到近順序繪制
可以看出未按由遠到近順序繪制的結果,出現了透明物體遮擋了其他物體的奇怪現象,這是由深度測試造成的。
上述場景主要實作邏輯:
float ratio = (float)screenW / screenH;
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
//啟動混合,設定混合因子
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(m_ProgramObj);
//繪制箱子(不透明)
glBindVertexArray(m_VaoIds[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureIds[0]);
glUniform1i(m_SamplerLoc, 0);
UpdateMatrix(m_MVPMatrix, 0, 0, 1.0, glm::vec3(-1.0f, 0.0f, -1.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
UpdateMatrix(m_MVPMatrix, 0, 0, 1.0, glm::vec3(2.0f, 0.0f, 0.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
//繪制地闆(不透明)
glBindVertexArray(m_VaoIds[1]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureIds[1]);
glUniform1i(m_SamplerLoc, 0);
UpdateMatrix(m_MVPMatrix, 0, 0, 1.0, glm::vec3(0.0f, 0.0f, 0.0f), ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
//繪制窗戶(透明)
glBindVertexArray(0);
glBindVertexArray(m_VaoIds[2]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureIds[2]);
glUniform1i(m_SamplerLoc, 0);
//容器 sorted 根據窗戶距觀察者的距離進行排序
for (auto it = sorted.rbegin(); it != sorted.rend(); ++it)
{
//遵循物體距觀察者(Camera)的距離,由遠到近開始繪制
UpdateMatrix(m_MVPMatrix, 0, 0 , 1.0, it->second, ratio);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glBindVertexArray(0);
聯系與交流
技術交流/擷取源碼可以添加我的微信:Byte-Flow
視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。