OpenGL alpha混合

5

我在alpha混合方面找到了5349574673页的资料,但仍然无法获得所需的结果。

我正在尝试使用OpenGL使gif/png文件正确地显示(带有透明度/半透明度)。

以下是我的初始化代码:

glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); //I've seen this on most tutorials
glDisable(GL_DEPTH_TEST); //it's a 2D game
//...loading matrices and so on

我确信这些图片有透明度并且已被正确加载。
glBlendFunc(GL_ONE, GL_ONE); 能够工作,但我不能确定它是否在alpha通道上有所作为,因为渲染出来是黑色的 => 混合效果有效。
glColor4f(1f,1f,1f,0.3f); 工作正常,我可以绘制透明的物体。

P.S. 我正在使用 http://lwjgl.org/wiki/index.php?title=Space_Invaders_Example_Game 这个例子进行学习。

编辑 我使用了使用GIMP编码的其他纹理和其他纹理加载器,现在它能够正常工作。


发布图片。初始化代码看起来不错。 - Jim Buck
2个回答

6
您的混合设置是正确的。但是,为了使混合工作,纹理必须包含一个alpha通道,当然需要适当赋值。然后,alpha通道数据必须由图像加载过程保留。可以让我们看到图像加载和纹理生成代码吗?

1
alpha混合公式的主要问题在于源/目标/结果颜色的存储方式。我们有两种情况:alpha预乘(r、g、b通道乘以alpha通道);非alpha预乘(r、g、b未乘)。您必须确保使用正确的混合公式来使用哪些格式。
当渲染屏幕时,通常使用alpha预乘,它允许使用更简单和更快速的混合公式。
我总结了所有基本情况,但首先提供一些信息:
  • 什么是源/目标:如果你按照“Photoshop”的方式思考,你可以将目标视为底层,源视为顶层。
  • 混合函数:它是着色器线性插值函数(也称为lerp)。从OpenGL参考文献中可以看到:mix使用A来加权X和Y之间的线性插值:mix(x, y, a) = x * (1 - a) + y * a。从我的经验来看,当在GPU片段着色器中使用时,mix版本比标准公式稍快一些。
  • 所有公式都适用于浮点颜色值(从0.0到1.0)
  • 如果您想要对源颜色使用不透明度,只需将src.a乘以不透明度即可:src.a *= opacity
  • 在可能出现除以0的公式中,您可能需要添加一个“if”条件,如下所示:
result.a = <formula for alpha>;
if (result.a == 0.0) {
    result.rgb = dest.rgb;
} else {
    result.rgb = <formula for rgb>;
}

所以这里是公式:

1. 源、目标和结果都未经过预乘处理

result.a = dest.a * (1.0 - src.a) + src.a;
result.rgb = (dest.rgb * dest.a * (1.0 - src.a) + src.rgb * src.a) / result.a;  // division by 0

或者使用混合函数:

result.a = mix(dest.rgb, 1.0, src.a);
result.rgb = mix(dest.rgb * dest.a, src.rgb, src.a) / result.a;  // division by 0!!!!

OpenGL混合函数:

not possible

2. 源、目标和结果都是预乘的

result.a = dest.a * (1.0 - src.a) + src.a;
result.rgb = dest.rgb * (1.0 - src.a) + src.rgb;

混合版本:

result.a = mix(dest.rgb, 1.0, src.a);
result.rgb = dest.rgb * (1.0 - src.a) + src.rgb; // "mix" version not available

OpenGL混合功能:

glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);

3. 目标,结果预乘,源未预乘

result.a = dest.a * (1.0 - src.a) + src.a;
result.rgb = dest.rgb * (1.0 - src.a) + src.rgb * src.a;

混合版本:

result.a = mix(dest.rgb, 1.0, src.a);
result.rgb = mix(dest.rgb, src.rgb, src.a);

OpenGL混合函数:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);

4. 目标是不透明的(dest.a = 1.0),所以结果也是不透明的,源图像非预乘

result.rgb = dest.rgb * (1.0 - src.a) + src.rgb * src.a;
result.a = 1.0;

混合版本:

result.rgb = mix(dest.rgb, src.rgb, src.a);
result.a = 1.0;

OpenGL混合函数:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接