openglalphablendingraylib

Raylib alpha blending not working properly?


I'm using ralib (which uses OpenGL) to make a 2D game. I have sprites for menubutton objects and I want to draw a white "mask" sprite over the button, but give it a transparency. (Only the mask will have a transparency.) That will produce a hilighted button.

Instead what I get is this:

enter image description here

The exit button actually got darker, which should never happen. If you composite a perfectly white sprite over anything else, it should become lighter (unless the alpha is exactly 0, in which case the original sprite does not change/blend with anything).

Some code in MenuBut.hpp:

int hi; // timer for highlight
const int hi_max = 20;
const float hi_alph = 0.333f;

Drawing code in MenuBut.cpp

// this draws the regular MenuButton graphic
DrawTexturePro(GCN::TG->tex_grid_menubuts, (Rectangle){0, 32.0f*t, 320, 32}, (Rectangle){(float)x, (float)y, (float)320, (float)32}, (Vector2){0, 0}, 0.0f, (Color){255, 255, 255, 255);

if (hi > 0)
{
    BeginBlendMode(BLEND_ALPHA);
    // this draws a white mask sprite over the actual MenuButton graphic
    DrawTexturePro(GCN::TG->tex_grid_menubuts, (Rectangle){320, 32.0f*t, 320, 32}, (Rectangle){(float)x, (float)y, (float)320, (float)32}, (Vector2){0, 0}, 0.0f, (Color){255, 255, 255, (unsigned char)round( 1.0f*(hi_alph*hi/hi_max)*255 )});
    EndBlendMode();
}

// draw text for "Exit"
DrawTextEx(GCN::TG->fnt_AL, disp_text.c_str(), (Vector2){(float)(x + w/2 - MeasureTextEx(GCN::TG->fnt_AL, disp_text.c_str(), 24.0f, 1.0f).x/2), (float)(y+6)}, 24.0f, 1.0f, (Color){0, 0, 0, 255});

Note, if i change hi_alph to something much higher like 0.750f, it does appear lighter, but the transition is very weird, like it starts getting darker then suddenly surges to whiter. That transition is kinda painful on the eyes.

I'm pretty sure something is blending the rgb values improperly because the button appears to become grayish too quickly in both cases.

I have tried all the other blend modes available (other than custom): BLEND_ADDITIVE, BLEND_MULTIPLIED, BLEND_ADD_COLORS, BLEND_SUBTRACT_COLORS, BLEND_ALPHA_PREMULTIPLY. Some of them produce the same results, others produce much weirder results that are not what I want.

I have hunted for alpha problems and found a few posts. This SO topic was the most helpful so far explaining how pre-multiplied alpha works, and I think I understand it. Another talks about alpha troubles although it is deeper into OpenGL which I don't understand.

I don't actually know OpenGL. I really hope there is a solution in raylib without having to write my own shader.


Solution

  • I figured it out. First of all you have to #include "rlgl.h" to get access to the rlSetBlendFactorsSeparate function, and ofc start using blend mode BLEND_CUSTOM_SEPARATE.

    However the real key was to start searching on how OpenGL works with alpha blending. Not Raylib help. Raylib has very little official documentation, it's only a pdf cheat sheet and FAQ. The real documentation is the source code itself and its comments, but you won't understand it unless you know something about OpenGL and its functions too.

    Anyway the solution is

    rlSetBlendFactorsSeparate(0x0302, 0x0303, 1, 0x0303, 0x8006, 0x8006);
    BeginBlendMode(BLEND_CUSTOM_SEPARATE);
    // do the draw here
    EndBlendMode();
    

    I even got those values from a help thread and a related thread, but those special values exist in a lookup table in rlgl.h so you can understand exactly what they are.

    (BTW, apparently this blend problem only exists when you draw to a different render target (draw to a texture not the screen).)