How does the blend mode work exactly?

say i have two ofImage of the type OF_IMAGE_COLOR_ALPHA. img1 is a red image with RGBA values [255,0,0,255], img2 is a green image with RGBA values [0,255,0,255]. in the draw() function i wrote:

void testApp::draw(){
	ofSetColor(255,255,255);
	ofEnableBlendMode(OF_BLENDMODE_ADD);
	img1.draw(0,0);//red image
    img2.draw(0,0);//green image
	ofDisableBlendMode();
}

according to my understanding, red+green should be yellow with OF_BLENDMODE_ADD. but finally it just shows a white image. could anybody explain the principle of blend mode for things like OF_BLENDMODE_ADD, OF_BLENDMODE_MULTIPLY, OF_BLENDMODE_SUBTRACT, OF_BLENDMODE_SCREEN?

Hey,

try this:

void ofApp::setup(){
	
	int w	= 200;
	int h	= 200;

	ofPixels red, green;
	red.allocate(w, h, OF_IMAGE_COLOR_ALPHA);
	red.setColor(ofColor::red);
	
	green.allocate(w, h, OF_IMAGE_COLOR_ALPHA);
	green.setColor(ofColor::green);

	img1.setFromPixels(red);
	img2.setFromPixels(green);
}

void ofApp::draw(){

		ofBackground(0); // this matters

		ofEnableBlendMode(OF_BLENDMODE_ADD);
		img1.draw(0,0);//red image
		img2.draw(100,100);//green image
}

You can check out what is each blend mode in OF source. But it should be same as GL blend modes:
http://www.andersriggelsen.dk/glblendfunc.php

1 Like

thanks man. yes, the most important thing is to set background to 0.

Yes… it would be nice to have an easy way to keep the background out of the blending so that it does not influence the color of those images… it is doable but the code is very ugly… basically you have to paint things twice:

	ofBackground(230); // this matters
img1.draw(0,0);//red image
img2.draw(100,100);//green image

	ofEnableBlendMode(OF_BLENDMODE_ADD);
	img1.draw(0,0);//red image
	img2.draw(100,100);//green image
ofDisableAlphaBlending();

Maybe there is a fancy, clean solution to it… I haven’t looked at it too much.

@yangyangcv

Alternatively, you could do:

img1.draw(0,0); // Draw red image without blend mode - i.e. overrides the background pixels
ofEnableBlendMode(OF_BLENDMODE_ADD);  // this only applies to img2
img2.draw(0,0); // Draw green image with a blend mode - i.e. using add, blend it into img1
ofDisableBlendMode();  // Switch back to not using a blend mode

You don’t need the background to be drawn as long as your first image isn’t set to use OF_BLENDMODE_ADD.

The way you are doing it (setting of OF_BLENDMODE_ADD before you draw the first image), you are telling openGL to blend img1 into openFramework’s default background color (a light gray). Then, img2 is blended into the result.

I think the principle you are asking about in your initial post is that ofEnableBlendMode(...) will apply to any draw commands that are called after setting the blend mode.

(@Jordi, love that visual blending link you posted)

Hey @mikewesthad,

Thank you for pointing that out.
I just wanted to say that in case the images are not in the same position, the second will still be blended with the bg:

ofBackground(230); // this matters
img1.draw(0,0); // Draw red image without blend mode - i.e. overrides the background pixels
ofEnableBlendMode(OF_BLENDMODE_ADD);  // this only applies to img2
img2.draw(100,100); // Draw green image with a blend mode - i.e. using add, blend it into img1
ofDisableBlendMode();  // Switch back to not using a blend mode

I would like to have a better way of blending without having to care about the bg… but i guess the best way is just to care about it :smiley:

1 Like

@Jordi, great point. If you are still looking for a way to “ignore” the background, you could use an ofFbo:

ofFbo fbo;

void testApp::setup(){
    int w	= 200;
	int h	= 200;

	ofPixels red;
	ofPixels green;
	red.allocate(w, h, OF_IMAGE_COLOR_ALPHA);
	red.setColor(ofColor::red);

	green.allocate(w, h, OF_IMAGE_COLOR_ALPHA);
	green.setColor(ofColor::green);

    ofImage img1;
    ofImage img2;
	img1.setFromPixels(red);
	img2.setFromPixels(green);
    
    // Create an fbo to hold the two images
	fbo.allocate(300, 300, GL_RGBA);
	
	// Draw the images to the fbo
	fbo.begin(); // Tell oF to start sending draw commands to the fbo
	
        // Clear the screen with a completely transparent color
        ofClear(0, 0, 0, 0);
        
        // Draw the images
        img1.draw(0, 0);
        ofEnableBlendMode(OF_BLENDMODE_ADD);
        img2.draw(100, 100);
        
    fbo.end(); // Tell oF to stop sending draw commands to the fbo
}

void testApp::draw(){
    
    // This will make sure that the fbo isn't blended with the background of the screen:
    ofDisableBlendMode();
    
    // Draw the fbo to the screen
    fbo.draw(0, 0);
}

Since you can fill the fbo with transparent pixels, you effectively get the sort of blank canvas you want. Then when you go to draw the fbo to the screen, you end can turn off blending so that the fbo will override the default background.

1 Like

Good point! thanks!

I tried the method outlined in this thread but to no avail. My fbos don’t stack for some reason. There is a black box with no alpha at the ends of my video, such that I can’t see both of my animations simultaneously-- any ideas?

void ofApp::setup(){
    
    vidContent.load("content.mp4");
    vidMask.load("mask.mp4");
    
    
    vidContent.play();
    vidMask.play();
    
    // Create an fbo to hold the two images
    fbo.allocate(960, 540, GL_RGBA);
    
    ofEnableAlphaBlending();
    
}

//--------------------------------------------------------------
void ofApp::update(){
    vidMask.update();
    vidContent.update();
    
    // Draw the images to the fbo
    fbo.begin(); // Tell oF to start sending draw commands to the fbo
    
    // Clear the screen with a completely transparent color
    ofClear(0, 0, 0, 0);
    
    // Draw the images
    vidMask.draw(0, 0);
    
    ofEnableBlendMode(OF_BLENDMODE_MULTIPLY);
    
    vidContent.draw(0, 0);
    
    fbo.end(); // Tell oF to stop sending draw commands to the fbo
}

//--------------------------------------------------------------
void ofApp::draw(){
    
    //ofDisableBlendMode();
    
    fbo.draw(0,0);
    fbo.draw(100,0);
    
}

i guess it’s because you used OF_BLENDMODE_MULTIPLY. with (0,0,0,0) background, everything is 0 because you just multiply 0

I recreated this (using a vidgrabber as one movie because I didn’t have two handy) and it seems to work fine. The only thing I would question is why you are drawing two of the fbo when drawing one will show you whether it is working or not. You should be able to see the movies overlaying each other within the single FBO.

UNLESS you are expecting the second movie to act as a mask for the first movie? (i.e., the first movie is playing within the cutout of a dancing person, and everything outside the cutout is transparent). If that is the case, this solution may not be what you are looking for.