Alpha Channel Manipulation in OpenGL and Advice

Ed's icon

I'm looking into converting a project from using Jitter matrices to shaders and was hoping for some guidance. The patch I'm converting creates a black matrix with alpha 255 as a frame and writes a number of small videos to select locations on it using dstdimstart and dstdimend. This is alphablended over top a large HD video. The small videos also have an oval alpha mask applied so they appear round in the composite video.

How do I apply an oval alpha mask in OpenGL Jitter to the small videos? More generally, what is the best overall approach? Do I create a texture and use the td.resample.jxs shader to add the small videos then use an alphablend shader? I tried using the td.resample.jxs shader directly to the large HD video but the results are small oval videos that constantly disappear.

Thanks for any suggestions!

-Ed

Zachrkn's icon

I've found the best way is to make an open gl object into the shape that you want the mask, then apply the video as a texture onto the shape. The texture wrapping method is important, depending on what you want to do. Pasted below is a fairly simple example, with a little documentation included to explain what it does.

Let me know if I'm not correctly understanding your goal.

Max Patch
Copy patch and select New From Clipboard in Max.

Ed's icon

THANK YOU for the quick reply! Your example was very clear and the notes were VERY helpful. I spent some time playing around with your example and found that using 'tex_map 1' gets me very, very close to what I want. One thing that's throwing me off a bit, though, is having to set the s and t texture coordinates according to the radius of the circle (or ellipse). My destination video sizes aren't uniform. I don't suppose there's an autoscaling option I missed?

One thing I didn't mention in my original description was that I applied blurring to the oval alpha mask in order to soften and feather the edges of the small videos. I suppose I can still use an alpha mask to do this.

Thanks again for taking the time to answer. You've been very helpful.

-Ed

Zachrkn's icon

Rereading your above post, it seems like what you're wanting to do is have the whole video appear in the circle with just the corners rounded off? Is that right? With non-uniform destination sizes, that makes things trickier. I honestly don't understand the math of the texture mappings well enough to figure out how to convert the radius into the appropriate number for the tex_plane parameters. I'll keep playing with it and come back to it if I get it figured out.

The feathering is actually quite tricky if you use my above-suggested method with open gl objects. As you might see from my other recent post today, feathering is something I've been spending a good bit of time with recently. From what I've learned, there is no way to actually feather the edges of an open-gl object (if you feather the texture, you just end up with black around the edges of your object). That might be incorrect, but I'm pretty sure it's true. In other words, if you need to feather, you'll have to completely scrap what I posted above and start over.

There are a few ways to work around this. However, from your original post it sounds like you have the basic idea. Fundamentally, you need to come up with a feathered alphamask, then use alphaglue to get your video onto the mask, and alphablend to combine that with the background material.

The most processor friendly way I've found to create the alphamask is to use jit.gl.sketch to make a plane, capture than plane to a texture, pass that texture through a fader (edgeblend for a rectangle/square, or Andrew Benson's spotmask for a circle), pop that texture onto a videoplane, and capture the output of the videoplane to yet another texture. From there, my method has been to convert the texture to a CPU readable matrix, use dstdim to position the resultant alphamask, use alphaglue to get your video into your alphamask, and finally alphablend to get your background behind it.

The worst part about that method (besides its odiousness), is having to convert the texture to a CPU-readable matrix in order to use dstdim, which can take a dig into your framerate if you're making multiple circles. This is the biggest flaw I can see in my method, so let me know if you find a better way to position the alphamask.

Basically what I’m trying to say is that this will work to do what you’re asking, but boy is it a silly way to have to do it.

Pasted below is another example patch demonstrating this method. If anyone can post a more efficient way of doing this, I also would be very grateful!

Let me know how it works for ya, Ed.

(note, for below patch to work, you must have andrew benson's spotmask shader from his Jitter Recipes Book #3)

Max Patch
Copy patch and select New From Clipboard in Max.

Ed's icon

"Rereading your above post, it seems like what you're wanting to do is have the whole video appear in the circle with just the corners rounded off? Is that right?"

Yes, exactly.

You know, I tried using alphaglue with a mask at one point but it spit out tons of errors for some reason.

I'll check out your patch tomorrow but it does sound awfully convoluted. I'll also check out your other thread.

Thanks again!

-Ed

Zachrkn's icon

Having slept on the problem, I've made another adjustment. I got rid of the jit.matrix objects which were used for usedstdim and instead used a td.rota.jxs shader for sizing and positioning the mask. This is a far more efficient method, as the matrix never has to be converted back to the CPU.

This is most likely the best way to accomplish your goal.

See below for the patch.

Max Patch
Copy patch and select New From Clipboard in Max.

Ed's icon

Thanks for the code! There's something deifnitely screwy with alphaglue. I took your example from last night and got rid of the black borders by using jit.op in place of alphaglue and setting the alpha mask to only one plane. This is exactly how my matrix based Jitter patcher creates round feathered borders.

By the way, you're trying to do this with arbitrary shapes, right? Have you tried extracting the luma channel, setting a threshold so points are either 100% black or 100% white, using the erode shader then adding a gaussian blur to create a feathered alpha mask?

----------------------------------------------------------
[MOD - removed uncompressed patch]

Zachrkn's icon

First of all, when copying patches into the forum, using Copy Compressed instead of just copy saves a huge amount of space. In fact, the patch you pasted in got cropped off by the forum, so I can't see it. If you could repost it with copy compressed that would be great!

Second, what exactly is happening for you with alphaglue? It's working perfectly on my computer (windows 7 here, although I doubt it makes a difference). You said before it spits out a lot of errors? If anyone else is trolling this thread, could you chime it to let us know how these patches working for you?

That's a good idea with luma and erode. I've posted below a version of what I think you mean (still using alphaglue since it works for me, though you can switch in jit.op in its place). Extrapolating that idea, I bet that the way to accomplish the feathering of any shape (as I posted about in another thread) would be to create that shape in jit.gl.sketch, then pass it through the erode and gaussian blur shaders like you said. I'll give that a shot and post with what I come up with.

Here's the code for what I think you suggested above.

Max Patch
Copy patch and select New From Clipboard in Max.

Ed's icon

Sorry about that. The compressed version of the code that makes the black edges go away is below.

Alphaglue spits out the following error message for EVERY frame on my Vista machine:

Max Patch
Copy patch and select New From Clipboard in Max.

0(9) : warning C7531: global type sampler2DRect requires "#extension GL_ARB_texture_rectangle : enable" before use
0(25) : error C1011: cannot index a non-array value
-- END GLSL INFO LOG: C:/Program Files (x86)/Cycling '74/Max 5.0/Cycling '74/jitter-shaders/color/cc.alphaglue.jxs --
-- START GLSL INFO LOG: C:/Program Files (x86)/Cycling '74/Max 5.0/Cycling '74/jitter-shaders/color/cc.alphaglue.jxs --
Fragment info

Ed's icon

"Extrapolating that idea, I bet that the way to accomplish the feathering of any shape .... would be to create that shape in jit.gl.sketch, then pass it through the erode and gaussian blur shaders..."

Max Patch
Copy patch and select New From Clipboard in Max.

Yes, the code you included was essentially what I meant. I added a contrast shader to set a threshold and also to invert the results. I also added a planemap shader to copy the red channel to the alpha channel in the mask before using alphaglue.

Zachrkn's icon

Well, here's Andrew Benson's response to someone with the same problem with alphaglue as you're experiencing:
https://cycling74.com/forums/cc-alphaglue-jxs-error
So it sounds like a videocard compatibility issue. He has a few suggestions for possible fixes in that thread.

With your above patch, the feathering seems pixelated (I can see lines/squares in the feathered portion) whereas with alphaglue the feather seems much more smooth. It must have something to do with the way jit.op works vs the way the alphaglue shader works. If you can make one of Andrew's fixes work for you, I'd highly recommend it, since alphaglue works like a charm when it works.

By the way, I'm really glad for this continued correspondence. I've definitely learned from this back-and-forth discussion we're having. There doesn't seem to be nearly as much of it on these forums as there used to be. Hope it continues!

Zachrkn's icon

Here's the way someone else has accomplished what you're looking for
https://cycling74.com/forums/how-to-mask-then-reveal-a-background-video
Look at the patch in Luke Woodbury's post.

It uses a series of 6 gaussian blur slabs for feathering, then the co.multiply.jxs shader in place of alphaglue.

Ed's icon

"Well, here's Andrew Benson's response to someone with the same problem with alphaglue as you're experiencing...."

Thanks. I forgot that I had swapped in a cheapo Dell workstation card for my nice one sometime back after experiencing bootup problems. I verified that alphaglue works fine on a gaming laptop. It sort of works on my workstation with all the errors but I just found it works differently so the code I sent with erode will need to be adjusted. (BTW, without the erode part, the patch is essentially the same as lumakey.)

"With your above patch, the feathering seems pixelated (I can see lines/squares in the feathered portion) whereas with alphaglue the feather seems much more smooth."

It probably has something to do with the way textures are processed.

"Here's the way someone else has accomplished what you're looking for...."

Actually, that multiply shader trick won't work for me. I need to compress up to eight videos into small ovals. What I would like to find is a way to build a composite texture made of all the small oval videos. Rota looks like an interesting way to do it but I still don't quite have a handle on how to build the composite texture except for doing something like a bunch of co.additive shaders connected together. Ugly. Hmmmm, UNLESS I can write the result of each co.additive shader composite operation BACK into the original source texture! Hmmm, I wonder.... :)

"By the way, I'm really glad for this continued correspondence. I've definitely learned from this back-and-forth discussion we're having."

I'm definitely learning a lot too. (Thanks. Plus its fun.) I recently had to write a video mixer/effects/interactive patcher and decided it was time to finally learn something about shaders. (I loved the water effect I was able to construct with shaders!) And that started me on rewriting an old patcher. And here I am. I'm pretty happy to have some interesting code to play around with. Now I just need a new video card. :(

-Ed

Zachrkn's icon

"but I still don't quite have a handle on how to build the composite texture except for doing something like a bunch of co.additive shaders connected together. Ugly. Hmmmm, UNLESS I can write the result of each co.additive shader composite operation BACK into the original source texture!"

That's an interesting idea, but as far as my brain works I'm not sure it's even feasible. If I understand correctly, you're talking about using @capture to bring all the composited ovals into a single texture. In order to do that, they'd have to be applied to an object, which would bring us back to square one, because even though the texture would be feathered the object would not. Also, from what I've read in other threads, capturing multiple objects to a single texture is tricky. Joshua Kit Clayton explains here:
https://cycling74.com/forums/jit-gl-sketch-controlling-question

Ed's icon

Ah, that's an interesting approach. My experiments with capture were all unsuccessful - only one capture would display at a time - but this looks like it could potentially solve that. I'll give that a try. Thanks!

Zachrkn's icon

I'm curious if you've found a good way of finishing this idea up by getting eight separate videos into eight feathered ovals over a background. I remain hung up on solving this final portion of the puzzle we engaged in.

Andrew Benson's icon
Max Patch
Copy patch and select New From Clipboard in Max.

You can render multiple GL objects to a single texture by using a jit.gl.sketch object with "drawobject" messages and setting the @capture of the jit.gl.sketch object. Here's a really basic example of that:

Zachrkn's icon

Ah, there's a good solution. Thanks Andrew!

Ed's icon

"I'm curious if you've found a good way of finishing this idea up by getting eight separate videos into eight feathered ovals over a background."

I was able to do so using an oval mask blurred with jit.gl.slab.gauss6x and alphaglue'd to the videos. Then I used a series of td.resample.jxs and co.additive.jxs shaders to position and combine each of the video ovals into a single texture. The resulting texture was combined with a background video using alphablend.

This works but seems to eat up RAM and texture memory. My converted app ran 50-100% faster compared to the Jitter matrix version but I expected a bit better.

May go back and try the above suggestion at some point but I need to start a new Kinect project.

I'll post the code tomorrow as I seem to have left my USB key at work.

Ed's icon

Hey, check this thread out: https://cycling74.com/forums/jit-gl-videoplane-blend_mode-alpha-mask-simple-problem
He's using multiple videoplanes with alpha masks.

Max Patch
Copy patch and select New From Clipboard in Max.

Here's Pedro Santos' example code from the thread with an alphamask added:

Zachrkn's icon

An elegant solution that gets past all that stupid alphablend stuff. Basically combines what I was suggesting in my very first response (putting each shape onto its own object), with the feathering techniques we hammered out.

Why didn't we think of that? *face-hands*

Thanks for the heads-up, Dambik.

Ed's icon

"Why didn't we think of that?"

Seriously! I never imagined you could do such a thing with jit.gl.videoplane. So simple.

Ed's icon
Max Patch
Copy patch and select New From Clipboard in Max.

For comparison, here's my alphablend method:

Ed's icon

I tried the videoplane method in my patch today and it works VERY well. Framerates were 3 times faster than when using Jitter matrices and I had no problems with running out of texture memory like I did when compositing textures and using alphablend. Plus it really simplifies the code.

Christopher Dobrian's icon
Max Patch
Copy patch and select New From Clipboard in Max.

FWIW, here's a formula I use for creating oval-shaped alpha masks with variable edge blur. You just compute the mask one time, then put the resulting matrix into the alpha plane of a video (very cheap to do), then send it on to wherever you want to use it (such as a jit.gl.videoplane object).

Zachrkn's icon

Dambik - agreed. That definitely seems to be the optimal method.

Christopher - thanks for sharing that! Makes a very nice smooth feather.

Ed's icon

"The worst part about that method (besides its odiousness), is having to convert the texture to a CPU-readable matrix in order to use dstdim, which can take a dig into your framerate if you're making multiple circles."

Which method are you referring to?

My ugly code that builds a composite texture with co.additive.jxs shaders positions the circles using td.resample.jxs shaders with a dstdim parameter applied.

With the method of writing textures to the videoplane, the circles can be positioned using the videoplane position and scale attributes. The drawback with this is that you appear to have to keep the window's aspect ratio constant otherwise the positions of the circles relative to the background will change.

Or are you referring to positioning the alphamask on the image/video which want to make appear circular?

Zachrkn's icon

Dambik, "ross88online" is a bot that copies portions of other people's posts within the thread to make the post seem legit, then puts a URL advert at the end. He copied something I posted from previously in this thread before we had things figured out. He did the same thing on several other threads as well.

Ed's icon

Oh, a spambot. Doh!