OpenGL ES 2.0-文本混合问题(iOS)

时间:2018-11-21 18:27:29

标签: ios opengl-es opengl-es-2.0 blending

当我将它们与OpenGL混合时,文本周围会有灰色阴影。

enter image description here

当前,这是我的混合功能:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

如果我将其更改为:

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

它起作用了,我用Gimp获得了相同的结果:

enter image description here

但是,但是使用GL_ONE时,文本不能再淡入背景。就像透明度0或1。

同样使用GL_ONE,两张图片之间的淡入淡出将以某种方式使结果图像超亮:

enter image description here

使用GL_SRC_ALPHA看起来很正常:

enter image description here

因此,这两种解决方案都各有利弊。我不需要灰色阴影,但我想保持交叉淡入淡出效果。任何建议都将不胜感激。

这是我的片段着色器:

gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate));

以下是纹理(文本和图像)的加载方式(最后预乘):

+ (GLuint)getGLTextureFromCGIImage:(CGImageRef)cgiImage {
    size_t width = CGImageGetWidth(cgiImage);
    size_t height = CGImageGetHeight(cgiImage);

    GLubyte *spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    CGContextRef spriteContext = CGBitmapContextCreate(spriteData,
                                                       width,
                                                       height,
                                                       bitsPerComponent,
                                                       bytesPerRow,
                                                       colorSpace,
                                                       kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), cgiImage);
    CGContextRelease(spriteContext);

    return [GLMediaUtils getGLTextureFromPixelsInFormat:GL_RGBA
                                                  width:(int)width
                                                 height:(int)height
                                                 pixels:spriteData];
}

+ (GLuint)getGLTextureFromPixelsInFormat:(GLenum)format
                                   width:(int)width
                                  height:(int)height
                                  pixels:(void *)pixels {

    glActiveTexture(GL_TEXTURE0);

    GLuint texture;
    glGenTextures(1, &texture);


    glBindTexture(GL_TEXTURE_2D, texture);


    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


    GLenum type = GL_UNSIGNED_BYTE;
    if(format == GL_RGB) // RGB565
        type = GL_UNSIGNED_SHORT_5_6_5;

    glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, pixels);

    free(pixels);
    glFlush();

    return texture;
} 

1 个答案:

答案 0 :(得分:1)

您快到了。如果要避免从纹理重影,则需要使用预乘Alpha(因为GL混合通常是后乘Alpha,这会导致通道中的颜色泛滥)。

通常GL_ONE起作用是因为在纹理上传之前,正确的alpha已被预先烘焙到RGB颜色通道中。如果您开始在着色器中添加自定义淡入淡出,那么最终会导致在着色器中用于混合的Alpha与用于预乘的Alpha之间不同步。

...因此您需要根据新的alpha值向片段着色器添加调整,以返回到稳定的预乘值。像这样:

vec4 texColor = texture2D(u_Texture, v_TexCoordinate);
// Scale the texture RGB by the vertex color
texColor.rgb *= v_color.rgb;
// Scale the texture RGBA by the vertex alpha to reinstate premultiplication
gl_FragColor = texColor * v_color.a;

另一种方法是将字体仅存储为亮度纹理。您会得到灰色阴影,因为颜色通道在字体之外为黑色,并且纹理过滤将白色和黑色混合在一起。如果您知道字体颜色是白色,则根本不需要在纹理中存储RGB值...(或者,如果您很懒,只需保留现有纹理并用白色填充整个纹理RGB通道即可。 )。