本文正在参加「金石方案」

OpenGL混合根底

OpenGL中的混合简略了解便是两个色彩的中和色,比如常见的通明色,咱们有一块玻璃,玻璃后面有个物体,那么要显示一种通明的作用,就需求运用到混合的概念。

通明物体可所以彻底通明(它使色彩彻底穿透)或者半通明的(它使色彩穿透的同时也显示本身色彩)。一个物体的通明度,被定义为它的色彩的alpha值,alpha色彩值运用色彩向量的第四个元素

【安卓OpenGLES】 开发入门(七):渲染半透明纹理之混合

混合方程

OpenGL中有两种混合方法:

  • 第一种:能够简略的给定一个通明度alpha的阈值,关于低于阈值alpha的片段进行丢掉,高于阈值的片段进行保存,能够得到一个混合后的作用。可是这种混合方法会使得部分区域彻底保存,部分区域彻底丢掉,不适合通明下的场景。
  • 第二种:采用一个混合公式对片段色彩进行混合。

OpenGL以下面的方程进行混合:

【安卓OpenGLES】 开发入门(七):渲染半透明纹理之混合

这里简略阐明下源向量和方针向量的概念:

源向量:便是将要运用的掩盖方针向量的色彩。

方针向量:将要被源向量掩盖的色彩向量。

经过定义也能够看出,咱们在制作的时候需求先制作方针向量,再制作源向量

如果次序搞反了,先制作了源向量,再制作了方针向量,那么在制作源向量的过程中,由于方针向量还不存在,就会呈现方针向量被彻底掩盖的状况(假定敞开了深度测试)。

混合API详解

  • 敞开混合

    glEnable(GL_BLEND);
    

    GL_BLEND用来启用混合(Blending) 功用。

  • 混合函数因子设置:

    void glBlendFunc(GLenum sfactor, GLenum dfactor)
    

    glBlendFunc接纳两个参数:用来设置源和方针因子

    OpenGL为咱们定义了许多选项,咱们把最常用的列在下面:

    选项
    GL_ZERO 00
    GL_ONE 11
    GL_SRC_COLOR 源色彩向量C_source
    GL_ONE_MINUS_SRC_COLOR 1−C_source
    GL_DST_COLOR 方针色彩向量C_destination
    GL_ONE_MINUS_DST_COLOR 1−C_destination
    GL_SRC_ALPHA C_source alpha值
    GL_ONE_MINUS_SRC_ALPHA 1−C_source alpha值
    GL_DST_ALPHA C_destination的alpha值
    GL_ONE_MINUS_DST_ALPHA 1−C_destination的alpha值
    GL_CONSTANT_COLOR 常色彩向量C_constant
    GL_ONE_MINUS_CONSTANT_COLOR 1−C_constant
    GL_CONSTANT_ALPHA C_constant的alpha值
    GL_ONE_MINUS_CONSTANT_ALPHA 1−C_constant的alpha值

    注意,色彩常数向量能够用glBlendColor函数分开来设置。

    为了将两个色彩按alpha通明度进行混合,咱们需求把源色彩的alpha给源因子,1−alpha给方针因子,如下设置:

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    

    当然你也能够运用glBlendFuncSeparate函数来分别对RGBalpha因子设置:

    glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
    
  • 设置混合形式是相加还是相减

    void glBlendEquation(GLenum mode)
    

    三种形式可选:

    • GL_FUNC_ADD:默许的,互相元素相加:result = Src+Dst;
    • GL_FUNC_SUBTRACT:互相元素相减:result = Src−Dst;
    • GL_FUNC_REVERSE_SUBTRACT:互相元素相减,但次序相反:result = Dst−Src;

一般咱们运用默许的GL_FUNC_ADD即可,如果需求完成一些其他作用,能够选择其他形式、

了解了以上api之后,下面咱们来写个demo

混合操作实践

下面咱们在之前代码根底上,给模型加上一个通明窗户的作用:渲染半通明纹路

【安卓OpenGLES】 开发入门(七):渲染半透明纹理之混合

代码如下

  • 极点着色器代码:
"#version 300 es \n"
"layout(location = 0) in vec3 vPosition;\n"
"layout(location = 1) in vec2 texCords;\n"
"out vec2 TexCords;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"void main()"
"{ \n"
"  gl_Position = projection*view*model*vec4(vPosition,1.0f); \n"
"  TexCords = texCords; \n"
"} \n";
  • 片段着色器代码:
"#version 300 es \n"
"precision mediump float;\n"
"uniform sampler2D cubeTexture;"
"in vec2 TexCords;"
"out vec4 outColor;\n"
"void main()"
"{ \n"
"  vec3 _texture = vec3(texture(cubeTexture,TexCords));\n"
"  outColor = vec4(_texture, 0.6f); \n"
"} \n";
  • 制作代码:
void MyGLRenderContext::OnDrawFrame() {
   isDrawing = true;
   beforeDraw();
   if(programObj == 0){
     return;
   }
   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   //清除buffer
   glEnable(GL_DEPTH_TEST);
   glEnable(GL_STENCIL_TEST);
   glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
   glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
​
   //part1:制作立方体
   {
     //总是写入模板缓冲区,并让模板缓冲区可写
     glStencilFunc(GL_ALWAYS,1,0xff);
     glStencilMask(0xff);
     //运用立方体程序着色器目标
     useProgram(programObj);
     //绑定VAO
     glBindVertexArray(VAO);
     //观察者位置
     setCordder(model);
     //绑定纹路
     setUniformTexture("textureColor",textureID);
     //开端制作
     glDrawArrays(GL_TRIANGLES,0,36);
     //解绑VAO
     glBindVertexArray(GL_NONE);
   }
   //part2:制作物体概括
   {
     //制作模板缓冲区中不等于1的部分,并让模板缓冲区不可写,且屏蔽深度测试
     glStencilFunc(GL_NOTEQUAL,1,0xff);
     glStencilMask(0x00);
     glDisable(GL_DEPTH_TEST);
​
     //运用物体概括制作的着色器目标
     useProgram(singleColorShader);
     glBindVertexArray(VAO);
     GLfloat scale = 1.1f;
     //第一次制作时缩放到1.1倍
     if(isFirstDraw){
       modelScale = glm::scale(modelScale, glm::vec3(scale, scale, scale));
       isFirstDraw = false;
     }
     //设置坐标系的变换矩阵
     setCordder(modelScale);
     //开端制作
     glDrawArrays(GL_TRIANGLES,0,36);
     //重置模板缓冲区参数并敞开深度测试,开释资源
     glStencilMask(0xFF);
     glStencilFunc(GL_ALWAYS, 0, 0xFF);
     glEnable(GL_DEPTH_TEST);
     glBindVertexArray(GL_NONE);
     //解绑程序着色器目标
     glUseProgram(GL_NONE);
   }
   //part3:制作窗户
   {
     //运用一个新的着色器目标
     useProgram(cubeProObj);
     //绑定窗户极点数据
     glBindVertexArray(cubeVAO);
     //设置坐标系
     setCordder(modelCube);
     //设置纹路坐标:窗户
     setUniformTexture("cubeTexture",cubeTextureID);
     //制作正方形
     glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);
     isDrawing = false;
     glBindVertexArray(GL_NONE);
     //解绑程序着色器目标
     useProgram(GL_NONE);
   }
}
  • 最后作用:

【安卓OpenGLES】 开发入门(七):渲染半透明纹理之混合

最后:完整代码现已贴到github上了,我们能够自行下载查看。我是小余,咱们下期见》》》