OpenGL ES 2.0 - проблема смешивания с текстом (iOS) - PullRequest
0 голосов
/ 21 ноября 2018

У меня серые тени вокруг текстов, когда я смешиваю их с 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 голосов
/ 22 ноября 2018

Ты почти у цели.Вам нужно использовать предварительно умноженную альфу, если вы хотите избежать ореолов от текстуры (поскольку смешивание GL обычно является пост умноженным альфа, что вызывает цветное кровотечение по каналам).

Обычно GL_ONE работает, потому чтоправильная альфа была предварительно запечена в цветовые каналы RGB текстуры перед загрузкой текстуры.Если вы начнете добавлять пользовательское затухание поверх этого в шейдере, то вы получите десинхронизацию между альфа-каналом, который вы используете для смешивания в шейдере, и альфа-каналом, который использовался для предварительного умножения.

...поэтому вам нужно добавить корректировку к фрагментному шейдеру на основе нового альфа-значения, чтобы вернуться к стабильному значению предварительного умножения.Что-то вроде:

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 текстуры белым).

...