OpenGL ReadPixels(屏幕截图)Alpha

OpenGL ReadPixels(屏幕截图)Alpha,opengl,rendering,screenshot,alpha,Opengl,Rendering,Screenshot,Alpha,我正在使用平铺渲染(使用glReadPixels)设置来拍摄场景的屏幕截图。我的输出看起来正确: 但观察alpha通道,即使透明纹理在不透明纹理上渲染,像素仍然是透明的 尤其是在我们看到天花板的地方,汽车的“内部”应该是完全不透明的,但在穿过后窗时,部分是透明的 是否有一种方法可以在像素处测试每个纹理的alpha分量,而不仅仅是最近的一个 是否有一种方法可以在像素处测试每个纹理的alpha分量,而不仅仅是最近的一个 否。OpenGL为每个像素存储一个RGBA值;无法获取以前的值(因为这需要大

我正在使用平铺渲染(使用glReadPixels)设置来拍摄场景的屏幕截图。我的输出看起来正确:

但观察alpha通道,即使透明纹理在不透明纹理上渲染,像素仍然是透明的

尤其是在我们看到天花板的地方,汽车的“内部”应该是完全不透明的,但在穿过后窗时,部分是透明的

是否有一种方法可以在像素处测试每个纹理的alpha分量,而不仅仅是最近的一个

是否有一种方法可以在像素处测试每个纹理的alpha分量,而不仅仅是最近的一个

否。OpenGL为每个像素存储一个RGBA值;无法获取以前的值(因为这需要大量RAM)


写入帧缓冲区的alpha值取决于alpha混合方程,您可以使用
glBlendFunc
glBlendFuncSeparate
进行设置。有关更多信息,请参见OpenGL wiki上的,并让您查看各种混合模式的效果。

我认为您从评论和其他答案中获得了一些有用的指导,但没有获得完整的详细解决方案。与其只是给出结果,不如让我来看看,这样你就知道下一次你自己怎么弄清楚了

我假设您使用
GL_SRC_ALPHA,GL_ONE_减去
blend函数将半透明对象向后绘制。你没有直接提到这一点,但它相当标准,并且与你所看到的一致。正确的解决方案还需要帧缓冲区中的alpha组件,但您已经有了,否则在读取alpha时将一无所获

为了说明整个过程,我将在此过程中使用两个示例。我只列出颜色的
(R,A)
组件,
G
B
的行为就像
R

  • 绘制一个带有颜色
    (R1,1.0)
    的图层,然后在其顶部绘制一个带有
    (R2,0.4)
    的图层
  • 绘制一个带有颜色
    (R1,0.5)
    的图层,然后在上面绘制一个带有
    (R2,0.4)
    的图层
  • 背景色是
    (Rb,0.0)
    ,对于这种混合,您总是希望使用0.0的alpha值进行清除

    首先,让我们计算我们想要实现的颜色结果:

    • 对于情况1,绘制第一层完全覆盖背景,因为它的alpha=1.0。然后我们在上面混合第二层。因为它的alpha=0.4,所以我们保留了第一层的60%,并添加了第二层的40%。所以我们想要的颜色是

      0.6*R1+0.4*R2

    • 对于案例1,绘制第一层保留50%的背景,因为它的alpha=0.5。那么目前为止的颜色是

      0.5*Rb+0.5*R1

      然后我们在上面混合第二层。同样,我们保留了前一层颜色的60%,并添加了第二层颜色的40%。所以我们想要的颜色是

      0.6*(0.5*Rb+0.5*R1)+0.4*R2
      =0.3*Rb+0.3*R1+0.4*R2

    现在,让我们来计算alpha的结果:

    • 对于案例1,我们的第一层是完全不透明的。观察不透明度的一种方法是测量物体吸收的光的比例。一旦我们有了一个吸收所有光线的层,我们渲染的任何其他东西都不会改变这一点。我们的总阿尔法应该是

      1.0

    • 对于案例2,我们有一层吸收50%的光,另一层吸收40%的剩余光。由于50%中的40%是20%,因此总共有70%被吸收。我们的总阿尔法应该是

      0.7

    使用
    GL_SRC_ALPHA,GL_ONE_减去_SRC_ALPHA
    进行混合可以获得所需的颜色效果。但正如你所注意到的,不是阿尔法。对示例执行计算:

    • 案例1:绘图层1,
      SRC_ALPHA
      为1.0,源值为
      S=(R1,1.0)
      ,目标值为
      D=(Rb,0.0)
      。因此,blend函数的计算结果为

      SRC_ALPHA*S+1_减去SRC_ALPHA*D
      =1.0*(R1,1.0)+0.0*(Rb,0.0)
      =(R1,1.0)

      这将写入帧缓冲区,并成为图形图层2的目标值。第2层的源代码是
      (R2,0.4)
      。对于
      SRC_ALPHA

      SRC_ALPHA*S+1_减去SRC_ALPHA*D
      =0.4*(R2,0.4)+0.6*(R1,1.0)
      =(0.4*R2+0.6*R1,0.76)

    • 案例2:绘图层1,
      SRC_ALPHA
      为0.5,源值为
      S=(R1,0.5)
      ,目标值为
      D=(Rb,0.0)
      。因此,blend函数的计算结果为

      SRC_ALPHA*S+1_减去SRC_ALPHA*D
      =0.5*(R1,0.5)+0.5*(Rb,0.0)
      =(0.5*R1+0.5*Rb,0.25)

      这将写入帧缓冲区,并成为图形图层2的目标值。第2层的源代码是
      (R2,0.4)
      。对于
      SRC_ALPHA

      SRC_ALPHA*S+1_减去SRC_ALPHA*D
      =0.4*(R2,0.4)+0.6*(0.5*R1+0.5*Rb,0.25)
      =(0.4*R2+0.3*R1+0.3*Rb,0.31)

    所以我们确认了你们已经知道的:我们得到了想要的颜色,但字母是错误的。我们如何解决这个问题?我们需要一个不同的alpha混合函数。幸运的是,OpenGL拥有
    glBlendFuncSeparate()
    ,这使我们能够做到这一点。我们需要弄清楚的是alpha使用什么混合函数。以下是思考过程:

    假设我们已经渲染了一些半透明对象,其总alpha值为
    A1
    ,存储在帧缓冲区中。到目前为止,我们渲染的内容吸收了总光的一部分
    A1
    ,并让一部分
    1.0-A1
    通过。我们用alpha
    A2渲染另一层glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                        GL_ONE_MINUS_DST_ALPHA, GL_ONE);