Pergunta

I'm writing an PyOpenGL-based UI for manually aligning images. I display my two images as textured quads, the moving image on top of the static reference. The moving image is shown in red with varying alpha, i.e. glColor4f(1.,0.,0.,overlay_opacity), and the static image is shown in cyan with constant opacity equal to one, i.e. glColor4f(0.,1.,1.,1.). The user can then vary overlay_opacity by mouse scrolling in order to fade between the moving and reference images.

At the moment I am using glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA). Whilst this does allow me to fade smoothly between the cyan and red images, it also means that when overlay_opacity is equal to 0.5 I get only half the maximum intensity of the red and cyan images, so the result looks dim and muddy. If I use glBlendFunc(GL_SRC_ALPHA,GL_ONE) I always get the max intensity for my cyan image, so I can't fade it out. What I really want is some sort of nonlinear blending that looks like the third graph below:

enter image description here

I guess I could perhaps do this in a fragment shader, but it seems like there ought to be a much simpler way to achieve the same result using just glBlendFunc(). I've also tried GL_SRC_ALPHA_SATURATE, which doesn't seem to work in my implementation.

Foi útil?

Solução

Quick answer: no, this isn't possible using just OpenGL calls. GL_SRC_ALPHA_SATURATE shouldn't do what you want either, its RGB factor would be min(Asrc, (1-Adest)), in your case that would probably always end up being equal to Asrc, as I assume your destination alpha is always 0.

Long Answer: Your best and only option is to write said fragment shader. In order to achieve what you want you'll have to use some trickery. I recommend pre-multiplying your overlay color with an alpha factor and output another alpha value to blend the destination color. An equation similar to this should suffice:

// Note I cap off the alpha values in both cases to achieve the desired non-linear ramp
float alpha = overlay_opacity * 2.0f;
out = vec4(color.rgb * min(1.0f, alpha), min(1.0f, 2.0f - alpha));

Then use the following blend functions to make sure the destination color blends as well:

glBlendFunc(GL_ONE, GL_SRC_ALPHA);

One further optimization, you notice I multiply the overlay opacity by two to cap it off for both alpha values. Instead of that you can pre multiply it by two before passing it to the shader, this will shave off some multiplications for each pixel.

Hopefully this will solve your problem, good luck!

Outras dicas

Since you're blending only images you can do it with a trick: First render image A, modulating its colors. Then you draw the second image on top of it using glBlendFunc(GL_ONE, GL_ONE) to make it additive and modulate the color again. By making the modulation colors for back and front layer follow your desired blending curve you get what you want.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top