本文介绍了opengl es2预乘与直接alpha +混合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

iphone上的Opengl es2。有些对象是由多层精灵和alphas组成的。

Opengl es2 on the iphone. Some objects are made with multiple layers of sprites with alphas.

然后我也有一些UI元素,它们也是由各种精灵合成在一起的,我淡入/淡出顶部其他一切。我通过调整着色器中的alpha来淡化。

Then I also have UI elements that are also composited together from various sprites that I fade in/out over top of everything else. I do the fading by adjusting the alpha in the shader.

我的纹理是PNG,在photoshop中制作了alpha。我没有故意为他们做好准备。我希望它们是直的alpha,但在我的应用程序中,它们表现得好像它们是预乘的,我可以看到在白色背景上绘制的白色精灵周围的黑色边缘。

My textures are PNG with alpha made in photoshop. I don't premultply them on purpose. I want them to be straight alpha, but in my app they're acting as if they're premultiplied where I can see a dark edge around a white sprite drawn over a white background.

如果我将混合模式设置为:

If I set my blend mode to:

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

元素很好地组合在一起,没有奇怪的边缘。但是当元素逐渐淡出时,它们最终会成为POP。它们将开始消退,但不会一直下​​降到alpha零。所以在淡出动画结束时,当我删除元素时,它们弹出会导致它们没有完全消失。

The elements composite nicely together, no weird edges. But when elements are fading out they POP at the end. They will start to fade but won't go all the way down to alpha zero. So at the end of the fadeout animation when I remove the elements they "pop off" cause they're not completely faded out.

如果我将混合模式切换为:

If I switch my blend mode to:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

这些元素很好地淡化和淡化。但是白色元素上的任何白色都有一个黑暗的边缘,看起来像alpha预乘。看到白框顶部绘制的白色圆圈:

The elements fade up and down nicely. But any white on white element has a dark edge around it from what looks like alpha premultiplication. See the white circle drawn over top of the white box:

但是场景中的其他混合物对我来说很好看。其他透明对象很好地融合。

But the other blends in the scene look good to me. The other transparent objects blend nicely.

另一个重要的注意事项是我的着色器处理元素和颜色元素的不透明度。对于绘制的每个东西,我乘以元素颜色,最后的alpha乘以不透明度值:

Another important note is that my shader handles opacity for elements and colorizing elements. For each thing that is drawn I multiply by an element color and the final alpha with an opacity value:

void main(void)
{
    gl_FragColor = texture2D(u_textureSampler,v_fragmentTexCoord0);
    gl_FragColor = vec4(gl_FragColor.r*u_baseColor.r,gl_FragColor.g*u_baseColor.g,gl_FragColor.b*u_baseColor.b,gl_FragColor.a*u_baseColor.a * u_opacity);
}

这允许我在我的精灵表中取一个白色物体并使其成为任何一个我想要的颜色。或者使用灰色的baseColor使对象变暗。

This allows me to take a white object in my sprite sheet and make it any color I want. Or darken objects by using a baseColor of grey.

每次我认为我理解这些混合模式时会出现这样的事情,我开始怀疑自己。

Every time I think I understand these blend modes something like this comes up and I start doubting myself.

是否有其他混合模式组合在我的精灵上有平滑的边缘并且还支持着色器中的alpha淡化/混合?

Is there some other blend mode combo that will have smooth edges on my sprites and also support alpha fading / blending in the shader?

我假设需要GL_SRC_ALPHA才能在着色器中使用alpha进行混合。

I'm assuming the GL_SRC_ALPHA is needed to blend using alpha in the shader.

或者我的问题是我需要使用除PSD以外的其他东西来保存我的精灵表?原因几乎是不可能的。

Or is my problem that I need to use something other than PSD to save my sprite sheet? Cause that would be almost impossible at this point.

更新:

我认为答案可能就是NO没有办法做我想做的事。第二种混合模式应该是正确的。但它有可能是将RGB与alpha放在一起的两倍,或者它在源文件中被预乘。我甚至尝试通过添加以下内容在上面的着色器中自我预乘alpha:

I think the answer might just be NO that there is no way to do what I want. The 2nd blend mode should be correct. But it's possible that it's double multiplying the RGB with the alpha somewhere, or that it's premultiplied in the source file. I even tried premultiplying the alpha myself in the shader above by adding:

gl_FragColor.rgb *= glFragColor.a;

但是这会让淡化看起来很糟糕,因为它们会逐渐消失。如果我自己预先设定alpha并使用上面的其他混合模式,那么事情就像我原来的一样。它们在没有弹出的情况下逐渐淡出,但你仍然可以看到光环。

But that just makes the fades look bad as things turn grey as they fade out. If I premultiply the alpha myself and use the other blend mode above, things appear about the same as in my original. They fade out without popping but you can still see the halo.

推荐答案

这是一篇关于如何避免直线条纹的好文章alpha纹理

Here's a great article on how to avoid dark fringes with straight alpha textures http://www.realtimerendering.com/blog/gpus-prefer-premultiplication/

如果您正在使用mip-maps,这可能就是您的直线Alpha纹理有深色条纹的原因 - 过滤直线Alpha图像可能会导致发生了,最好的解决方案是在创建mip-maps之前预先乘以图像。这篇文章中有一个常见的黑客修复,但是认真考虑预先乘法。

If you're using mip-maps, that might be why your straight alpha textures have dark fringes -- filtering a straight alpha image can cause that to happen, and the best solution is to pre-multiply the image before the mip-maps are created. There's a common hack fix as well described in that article, but seriously consider pre-multiplying instead.

使用直线alpha创建纹理通常是必要的,也是首选,但它是更好的做法是将它们预先乘以构建步骤的一部分,或者在纹理加载期间将它们保持为在内存中保持直接alpha。我不确定OpenGL ES,但是我知道WebGL允许你在加载期间通过使用带有gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL参数的gl.pixelStorei来实时预加倍纹理。

Using straight alpha to create the textures is often necessary and preferred, but it's still better to pre-multiply them as part of a build step, or during the texture load than to keep them as straight-alpha in memory. I'm not sure about OpenGL ES, but I know WebGL lets you pre-multiply textures on the fly during load by using gl.pixelStorei with a gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL argument.

另一种可能性是,如果您要合成许多元素,则直接Alpha混合功能不正确。为了使用直接的alpha图像做一个正确的over operator,你需要使用这个混合函数,也许这就是你要找的东西:

Another possibility is if you're compositing many elements, your straight alpha blending function is incorrect. In order to do a correct "over operator" with a straight alpha image, you need to use this blending function, maybe this is what you were looking for:

gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

您引用的常见直线Alpha混合函数(gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA) ))无法正确处理目标alpha通道,如果您打算使用over运算符合成多个图层,则在混合直线alpha图像源时必须使用单独的颜色和alpha混合函数。 (考虑一下你可能不想插入alpha通道,它应该总是比source& dest更加不透明。)并且在混合时要特别小心,因为直alpha混合的结果是一个预乘的图像!因此,如果您稍后使用结果,您仍然必须准备进行预乘混合。对于更长的解释,我在这里写到:

The common straight alpha blending function you referred to (gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)) does not correctly handle the destination alpha channel, you have to use separate blend functions for color and alpha when blending a straight alpha image source, if you intend to composite many layers using an "over operator". (Think about how you probably don't want to interpolate the alpha channel, it should always end up more opaque than both the source & dest.) And take special care when you blend, because the result of the straight-alpha blend is a premultiplied image! So if you use the result later, you still have to be prepared to do premultiplied blending. For a longer explanation, I wrote about this here: https://limnu.com/webgl-blending-youre-probably-wrong/

使用预乘图像&混合是你不必使用单独的混合功能颜色和& alpha,你自动避免了很多这些问题。你可以&应该创建直的alpha纹理,但是在加载之前或加载期间预先相乘它们并在整个代码中使用premult混合(glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA))。

The nice thing about using premultiplied images & blending is that you don't have to use separate blend funcs for color & alpha, and you automatically avoid a lot of these issues. You can & should create straight alpha textures, but then pre-multiply them before or during load and using premult blending (glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)) throughout your code.

这篇关于opengl es2预乘与直接alpha +混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 13:29