i have read a lot of thread about this but i can’t make it to work !
i would like to stack 2 images and apply a mask to the top level one to see the bottom layer through it :
load 2 images
load a Grayscale image as a mask
apply mask to image1
draw image2
draw image1 to see image2 through the mask of image1
Hi! It seems like the mask must be partially transparent. If it’s black it’s not transparent I think we were thinking too much like photoshop or gimp. Try using a PNG with transparent background.
ofFbo mask;
ofImage img;
void ofApp::setup() {
img.load("1.jpg");
mask.allocate(img.getWidth(), img.getHeight(), GL_RGBA); // <-- it can have transparency
img.getTexture().setAlphaMask(mask.getTexture());
}
void ofApp::draw() {
mask.begin();
ofClear(0, 0, 0, 0); // <-- note the 0 alpha value
ofSetColor(255);
ofDrawCircle(150 + 50 * sin(ofGetElapsedTimef()), 150 + 50 * cos(ofGetElapsedTimef()), 50);
mask.end();
img.draw(0, 0);
}
I have already tried a custom PNG with alpha as a mask and it works.
But i thought the purpose of setAlphaMask() was actually to use the colors of a texture as a mask and not the alpha, but maybe i am wrong. @arturo is this the expected behavior ?
If i am wrong, then how to manually add alpha (make black part of the mask transparent) after loading the mask image ?
There I only copy the red channel to the alpha channel, but ideally you would also wipe the RGB channels with white to avoid visual glitches on the mask edges.
I see there’s a bunch of examples dealing with masks and shaders. I didn’t look at them, but with a shader it would be very fast to do this in real time (copying an RGB channel to the alpha one).
The comparison with 0 may work, but the mask edges may be rough, because it’s a threshold: either transparent or opaque.
@arturo In my tests black did not become transparent. As in @Gallo 's “what I have” image above, the white part of the mask shows the textures, but the black does not become transparent, but replaces the image texture with black.
oh yeah sorry you are right the mask works for color form rgb and for alpha from alpha. you can remap the channels using:
mask.setSwizzle(GL_TEXTURE_SWIZZLE_A, GL_RED);
which will map the red channel to act as alpha so you will see white as alpha 1 and black as alpha 0. you’ll need a texture allocated with alpha in the first place for this to work
setSwizzle() takes 5 microseconds on my system, while the two for loops take around 20500 microseconds. Just in case you need to be fast.
If your mask is not pure black and white, but has gray values, it might look like this:
Which you can solve like this using your approach:
for(int y = 0; y < mask.getHeight(); y++) {
for(int x = 0; x < mask.getWidth(); x++) {
mask.getPixels().setColor(x, y, ofColor(255, 255, 255, mask.getPixels().getColor(x, y).getBrightness()));
}
}
Or at least I would not compare to 0 (jpg may have introduced artifacts, as you can see on the right side of the pentagon). Using .getBrightness() < 128 would be better, I think.
I expected: white regions of the mask are showing the video, grey regions are partially transparent, black regions are fully transparent.
But it leads to: white regions of the mask are showing the video, some grey regions are in fact partially transparent, but black regions of the mask are non-transparent black.
Same outcome on Ubuntu 16.04 and OS X 10.9.5, both OF 0.9.8
I have in fact the same result when trying the same with a custom shader like: