EDIT
Blend Brush -> Layer -> Background
Well, what happens glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
works to mix brush strokes into the brush texture, but the alpha values obtained in the texture are incorrect. Each added fragment should 1. add alpha to the final alpha value - it should remove exactly so much light for interaction and 2. scale the previous alpha with the rest - the previous surfaces reduce the light by the previous value, but since a new surface is added to reduce them. I'm not sure if that made sense, but it leads to this ...
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Now the color channel of the brush texture contains the overall color that should be mixed with the background (previously multiplied by alpha), and the alpha channel gives the weight (or the amount that the color obscures the background). Since the color is pre-multiplied by alpha, the default blend RenderTexture defaults to GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
again scales with alpha and therefore darkens the overall color. Now you need to blend the brush texture with the background using the following function that I am going to install in Cocos2D:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Hope this is possible. I did not think about how to control the ability to create a brush texture so that it combines with GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
, but decomposition / normalization of alpha may require a floating-point texture and / or an additional passage that sounds painful.
Alternatively, select the background in your rendering texture before drawing and save the place there without mixing the layers.
This worked for me:
glDisable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); fbo.bind(); glClear(GL_COLOR_BUFFER_BIT); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); drawTexture(brush1); drawTexture(brush2); fbo.unbind(); drawTexture(grassTex);
![small test in GL](https://fooobar.com/undefined)
Brush opacity
Using GL_ONE, GL_ONE_MINUS_SRC_ALPHA
causes problems with the implementation of the opacity library in blending layers, since it assumes that the color is multiplied by alpha. By decreasing the opacity
, the alpha of the brush layer decreases during blending. GL_ONE_MINUS_SRC_ALPHA
then increases the amount of background color, however GL_ONE
adds up 100% of the brush layer and oversaturated the image.
The simplest imo solution is to find a way to scale the color using the opacity of the global layer and continue to use GL_ONE, GL_ONE_MINUS_SRC_ALPHA
.
- In fact, using
GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHA
might be the answer if the library supports it, but apparently it is not. - You can use fixed pipelined rendering to scale the color:
glColor4f(opacity, opacity, opacity, opacity)
, but for this you will need a second rendering goal and manual combination, similar to the code above, where you draw a full-screen square once for the background and again for brush layer. - If you do the combination manually, it would be more reliable to use the fragment shader instead of the
glColor
method. This will significantly increase control if you ever wanted to play with more complex blending functions, especially when it comes to units and time series outside the 0: 1 range: gl_FragColour = texture(brushTexture, coord) * layerOpacity;
End edit
Standard alpha blend glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
, not really GL "start" / default function.
Summing alpha values, as in glBlendFuncSeparate, will oversaturate alpha, and the bottom color will be completely replaced. A saturation overlay can produce decent results: glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE)
. It might be worth experimenting with glBlendEquationSeparate and MAX blending, if supported. The advantage of playing with MAX will be to reduce overlapping artifacts (hard triangular bits) from your line drawing code — for example, replacing a color, but only until you reach the general alpha value of X. EDIT: Both cases will require mixing and cleaning after each hit.
I can only assume that overlaying the render texture on the background actually works. (not for current level values)
On a side note and largely unrelated to it is also “Under Blending”, where you save the transmittance value instead of alpha / opacity (from here ):
glBlendEquation(GL_FUNC_ADD); glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);