美文网首页
OpenGL学习17——混合

OpenGL学习17——混合

作者: 蓬篙人 | 来源:发表于2021-07-05 13:07 被阅读0次

混合(Blending)

  • 混合(Blending) 在OpenGL中一般作为实现物体透明度的技术。一个物体的透明度由它颜色中的alpha值定义。

1. 丢弃片元

  • 在一些渲染场景中我们可能并不关心部分透明度,而是根据纹理的颜色决定显示或完全不显示。如下面的青草纹理,我们只想显示绿色的青草,而背景部分则完全丢弃。(图片取自书中
    青草纹理图像
  • 要加载含alpha值的纹理,我们需要告诉OpenGL我们的纹理包含alpha通道。
glTexImage2D(GL_TEXTURE_2D, 0, FL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
  • 对于存在透明度的颜色,我们在片元着色器中需要使用颜色的四个分量进行计算。
void main()
{
    FragColor = texture(texture1, TexCoords);
}

下面我们使用深度测试的例子,添加一些青草纹理来展示混合的效果。

  • 首先,创建一个位置矢量数组来代表青春在场景中的位置。
std::vector<glm::vec3> vegation;
vegation.push_back(glm::vec3(-1.5f, 0.0f, -0.48f))
vegation.push_back(glm::vec3( 1.5f, 0.0f,  0.51f))
vegation.push_back(glm::vec3( 0.0f, 0.0f,  0.7f));
vegation.push_back(glm::vec3(-0.3f, 0.0f, -2.3f));
vegation.push_back(glm::vec3( 0.5f, 0.0f, -0.6f));
  • 这里为了简单,我们直接将青草的纹理贴到四方形上。顶点数据可以参考立方体某个面的顶点数据。下面我们给出青草的渲染代码。
// grass
glBindVertexArray(grassVAO);
glBindTexture(GL_TEXTURE_2D, grassTexture);
model = glm::mat4(1.0f);
for (int i = 0; i < vegation.size(); i++)
{
    model = glm::mat4(1.0f);
    model = glm::translate(model, vegation[i]);
    shader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 6);
}
  • 渲染效果。


    青春纹理渲染效果
  • 在片元着色器中,我们根据alpha通道的值,使用内置指令discard来丢片片元。
void main()
{   
    //FragColor = texture(texture1, TexCoords);
    vec4 texColor = texture(texture1, TexCoords);
    if(texColor.a < 0.1)
        discard;
    FragColor = texColor;
}
  • 渲染效果。


    青草透明渲染效果

2. 混合

  • 直接根据alpha值丢弃片元无法让我们渲染半透明图像,要渲染不同透明度的图像,我们首先需要启用混合。
glEnable(GL_BLEND);
  • OpenGL中的混合采用下述公式:
    \overline{C}_{result}=\overline{\color{green}{C}}_{source} * \color{green}{F}_{source}+\overline{\color{red}{C}}_{destination} * \color{red}{F}_{destination}
    • \overline{\color{green}{C}}_{source}:源颜色矢量,片元着色器输出的颜色。
    • \overline{\color{red}{C}}_{destination}:目标颜色矢量,当前存储在颜色缓冲区的颜色矢量值。
    • \color{green}{F}_{source}:源因子值,源颜色矢量的alpha值的影响因子。
    • \color{red}{F}_{destination}:目标因子值,目标颜色矢量的alpha值的影响因子。
  • 当片元着色器运行后,且所有测试通过了,混合公式将作用于片元着色器的颜色输出和当前颜色缓冲区中的值。
  • 下面,我们用一个红色四方形和绿色四方形的混合来简单作简单展示。(图片取自书中
    混合的四方形
  • 假设我们使用60%的绿色和40%红色进行混合,对应上面的公式,我们的计算应该是这样:
    \overline{C}_{result}= \left( \begin{matrix} \color{red}{0.0} \\ \color{green}{1.0} \\ \color{blue}{0.0} \\ \color{purple}{0.6} \end{matrix} \right) * \color{green}{0.6} + \left( \begin{matrix} \color{red}{1.0} \\ \color{green}{0.0} \\ \color{blue}{0.0} \\ \color{purple}{1.0} \end{matrix} \right) * (\color{red}{1} - \color{red}{0.6})
  • 混合效果如下。(图片取自书中
    四方形混合
  • 在OpenGL中,我们可以使用函数glBlendFunc设置源和目标颜色矢量的影响因子。
glBlendFunc(GLenum sfactor, GLenum dfactor);
  • 常用的影响因子如下表所示:
选项
GL_ZERO 影响因子为0
GL_ONE 影响因子为1
GL_SRC_COLOR 影响因子等于源颜色矢量\overline{\color{green}{C}}_{source}
GL_ONE_MINUS_SRC_COLOR 影响因子等于1减去源颜色矢量1-\overline{\color{green}{C}}_{source}
GL_DST_COLOR 影响因子等于目标颜色矢量\overline{\color{red}{C}}_{destination}
GL_ONE_MINUS_DST_COLOR 影响因子等于1减去目标颜色矢量1-\overline{\color{red}{C}}_{destination}
GL_SRC_ALPHA 影响因子等于源颜色矢量\overline{\color{green}{C}}_{source}的alpha分量值
GL_ONE_MINUS_SRC_ALPHA 影响因子等于1减去源颜色矢量\overline{\color{green}{C}}_{source}的alpha分量值
GL_DST_ALPHA 影响因子等于目标颜色矢量\overline{\color{red}{C}}_{destination}的alpha分量值
GL_ONE_MINUS_DST_ALPHA 影响因子等于1减去目标颜色矢量\overline{\color{red}{C}}_{destination}的alpha分量值
GL_CONSTANT_COLOR 影响因子等于常量颜色矢量\overline{\color{blue}{C}}_{constant}
GL_ONE_MINUS_CONSTANT_COLOR 影响因子等于1减去常量颜色矢量\overline{\color{blue}{C}}_{constant}
GL_CONSTANT_ALPHA 影响因子等于常量颜色矢量\overline{\color{blue}{C}}_{constant}的alpha分量
GL_ONE_MINUS_CONSTANT_ALPHA 影响因子等于1减去常量颜色矢量\overline{\color{blue}{C}}_{constant}的alpha分量
  • 对于表格上的颜色矢量常量,我们可以使用glBlendColor函数设置。
  • OpenGL允许我们使用glBlendFuncSeparate函数分别设置RGB和alpha通道的颜色值。
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
  • OpenGL甚至还允许我们使用函数glBlendEquation函数修改公式中源和目标部分的操作符。
    • GL_FUNC_ADD:默认,两个颜色矢量进行加操作,\overline{C}_{result}=\color{green}{Src}+\color{red}{Dst}
    • GL_FUNC_SUBTRACT:两个颜色矢量进行减操作,\overline{C}_{result}=\color{green}{Src}-\color{red}{Dst}
    • GL_FUNC_REVERSE_SUBTRACT:两个颜色矢量转换顺序进行减操作,\overline{C}_{result}=\color{red}{Dst}-\color{green}{Src}
    • GL_MIN:按颜色矢量的分量取最小值,\overline{C}_{result}=min(\color{red}{Dst},\color{green}{Src})
    • GL_MAX:按颜色矢量的分量取最大值,\overline{C}_{result}=max(\color{red}{Dst},\color{green}{Src})
glBlendEquation(GLenum mode);

3. 渲染半透明纹理

  • 下面我使用前面的例子,将青草纹理替换为一张窗体纹理来渲染混合的场景。首先,我们启用混合并设置混合公式参数。
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  • 其次,因为我们使用混合计算颜色值,因此片元着色器中无需根据alpha值进行片元丢弃。
void main()
{   
    FragColor = texture(texture1, TexCoords);
}
  • 渲染效果。


    半透明渲染1
  • 问题:上面的渲染场景,我们可以看到前面的窗体遮挡了部分后面的窗体。这是因为当写入深度缓冲区时,深度测试并不关心片元是否有透明度,因此透明部分的深度值也写入深度缓冲区。这导致后面的窗体也进行深度测试,并丢弃了片元。要解决这个问题,我们需要将窗体按最远到最近进行排序和绘制。
  • 对于包含透明物体的场景,我们一般的绘制顺序如下:
      1. 绘制所有非透明物体对象。
      1. 对所有透明物体对象进行排序。
      1. 按排序顺序绘制透明物体对象。
  • 针对上述场景,我们简单采用物体位置矢量与相机位置矢量之间的距离排序,并将距离和相应的位置矢量存储到STL类库中的map数据结构中。
std::map<float, glm::vec3> sorted;
for (unsigned int i = 0; i < vegation.size(); i++)
{
    float distance = glm::length(camera.Position - vegation[i]);
    sorted[distance] = vegation[i];
}
  • 渲染时我们将map进行反转,按最远到最近的顺序进行绘制。
for (std::map<float, glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
{
    model = glm::mat4(1.0f);
    model = glm::translate(model, it->second);
    shader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 6);
}
  • 渲染效果。


    半透明渲染2

相关文章

  • OpenGL学习17——混合

    混合(Blending) 混合(Blending) 在OpenGL中一般作为实现物体透明度的技术。一个物体的透明度...

  • opengl学习-混合

    不使用混合如何实现透明度 通过在片源着色器中添加if (texColor.a < 0.1) discard;来根据...

  • Opengl混合算法探究

    在我们的实际应用中使用OpenGL进行混合常见的问题有以下三种: 使用Opengl自带的混合算法 自定义混合算法 ...

  • OpenGL 混合

    开启深度测试后,如果重叠的图层中,上层的图层是半透明的情况下我们不能采用直接覆盖的方式,而需要用到混合,在图层重叠...

  • OpenGL 混合

    原因 颜色缓冲区存储着像素点的颜色信息,当深度缓冲区开启时,当该像素点深度小于原来的深度时的颜色信息就会被替换为新...

  • NDK OpenGL ES 3.0 开发(十二):混合

    该原创文章首发于微信公众号:字节流动 OpenGL ES 混合 OpenGL ES 混合本质上是将 2 个片元的颜...

  • OpenGL中图层混合公式的一点探讨

    OpenGL中图层混合公式的一点探讨 一、问题的提出 OpenGL混合的时候,常常会用到如下一个公式: 其中Cf表...

  • OpenGL-颜色混合浅析

    基础理论 在OpenGL中,物体透明技术通常被叫做混合(Blending)。 OpenGL渲染时会把颜色值存在颜色...

  • 高级OpenGL-03.混合(Blending)

    混合 在OpenGL中,物体透明技术通常被叫做混合(Blending)。透明的物体(或物体的一部分)非纯色而是混合...

  • 混合、面剔除

    混合 在OpenGL中,物体透明技术通常被叫做混合(Blending)。透明是物体(或物体的一部分)非纯色而是混合...

网友评论

      本文标题:OpenGL学习17——混合

      本文链接:https://www.haomeiwen.com/subject/yanbultx.html