Transparency on ofFbo

I try to draw a windowlet (with ofFbo) on the screen with this pseudo code:

//screen background
ofSetColor(255, 255, 255, 255);
image1.draw(0, 0, ofGetWidth(), ofGetHeight());

//fbo windowlet
ofFbo.begin();
    //windowlet background
    ofSetColor(255, 255, 255, 255);
    image2.draw(0, 0, fbowidth, fboheight);

    //windowlet drawing
    ofSetColor(0, 0, 0, 128); //Att to transparency here
    ofDrawRect(0, 0, fbowidth/2, fboheight/2); //That draws a semi-transparent rectangle on the windowlet.
ofFbo.end();
ofFbo.draw();

Semi-transparent rectangle should show the windowlet’s background image(image2) under itself. But it shows the screen’s background image(image1) instead. The image2’s respective part becomes also semi-transparent. What I need to do to change this wrong behaviour?

Have you tried ofEnableAlphaBlending() ?

ofEnableAlphaBlending() is the ever first line of the app :slightly_smiling:

Not sure, but for the “The image2’s respective part becomes also semi-transparent” issue, set ofSetColor(255); just before the ofFbo.draw() to draw the fbo image itself without transparency.

Thanks nice try! But unfortunately nothing changed.

Might be missing `ofClear(0)’ inside ofFbo::begin - end?

@chuckleplant Thanks, but nothing happens.

Please see the image below. Opaque Image1 is drawn on the screen. Opaque Image2 and semi-transparent rectangle are drawn on the ofFbo. Semi-transparent rectangle should show only image2 under herself but image1 is also shown.

Hi,
I can make mistakes, but here’s how I understand your problem:
ofEnableAlphaBlending() call glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
(I’m not sure this is true for android)
So, when you draw the rectangle to the fbo, the alpha value for each pixel is computed like this:
As * As + Ad * ( 1 - As)
where As is the alpha value for the source pixels (the rectangle, as defined by ofSetColor) and Ad the alpha value for the destination pixels (the previous fbo content, image2 in your case). As and Ad are expressed here in the 0…1 range (not the 0…255 range).
This means that in your case, for the rectangle pixels, As=0.5 (128) and Ad=1 (255). The final alpha value is
0.5 * 0.5 + 1 * ( 1 - 0.5 ) = 0.75
This is why the fbo pixels are not opaque where you draw the rectangle.

Because your image2 is opaque, I think an easy fix could be to use an opaque fbo
ofFbo.allocate( width, height, GL_RGB )

Another way to fix the problem could be to not use ofEnableAlphaBlending() but glBlendFuncSeparate just for drawing the rectangle. Perhaps
glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE )

I don’t understand why it is so hard to compose transparent objects with openGL to obtain results similar those we can have with drawing applications like Gimp or Photoshop…

2 Likes

@lilive Thanks for the explanation.

I tried ofFbo.allocate( width, height, GL_RGB ) but it made the rectangle full opaque.

I didn’t try glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE ). Because I am writing an addon. I may use a transparent image for image2 as well.

ofFbo.allocate( width, height, GL_RGB ) works for me (windows 7):

void ofApp::setup(){
    image1.load("image1.jpg");
    image2.load("image2.jpg");
    fbo.allocate(400,400, GL_RGB);
}

void ofApp::draw(){

    // Draw into the FBO
    fbo.begin();
    ofClear(0);
    // image2
    ofSetColor(255);
    image2.draw(0,0);
    // Then a semi-transparent black rectangle.
    ofSetColor(0,0,0,128);
    ofDrawRectangle(0,0,400,150);
    fbo.end();

    // Draw on screen
    // image1
    ofSetColor(255);
    image1.draw(0,0);
    // The FBO
    ofSetColor(255);
    fbo.draw(100,100);
}

test1.zip (106.6 KB)

But this not allows to use a transparent image2.

Some months ago, I ended up writing a shader to compose images within an fbo, with transparency. You can have a look. This seems quite dirty to me, because I pass to the shader the texture in which it draws. I need to do this to use the compositing formulas I found online.

#version 150

uniform sampler2DRect dstTex;
uniform vec4 globalColor;

out vec4 outputColor;

void main (void)
{
    vec4 dst = texture( dstTex, gl_FragCoord.xy );
    float a = globalColor.a + dst.a * ( 1 - globalColor.a );
    if( a == 0 )
    {
        outputColor = vec4( 0 );
    }
    else
    {
        outputColor = vec4( ( globalColor.rgb * globalColor.a + dst.rgb * dst.a * ( 1 - globalColor.a ) ) / a, a );
    }
}

test2.zip (118.5 KB)

But I don’t know if all of this will work on android.

2 Likes

@lilive Thanks for the script. I am planning to port the game from OpenGL ES 1.1CM to 2.0 (or 3.0) next season. I will benefit from it for sure.

As I wrote in my previous post, on OpenGL ES 1.1CM, GL_RGB doesn’t allow to use transparency with the rectangle neither.

Drawing a transparent image on a full opaque background image shouldn’t produce a transparency in the final ofFbo drawing. But I couldn’t find how to solve the issue yet.

Well, I don’t understand this difference between openGL and openGL ES 1.1CM.

I know nothing about android and openGL ES 1.1CM. I don’t even know if you can use custom shaders. Sorry that I can’t contribute further :wink:

I solved my issue by drawing the semi-transparent rectangle onto a 2nd ofFbo.