OpenGL Child Component with Transparent Background


#1

Hi! I am very new to OpenGL but I need to draw some 3-dimensional looking lines so I’m learning. I have a child component that needs to draw some Axis ticks and some 3D junk over the parent. The problem is that I can’t seem to get the child to draw with a transparent background to just overlay it’s GL graphics on top of the parent’s graphics JUCE paint()-based graphics. With this code, I still get a black background on the child component

[code]void MyChildComponent::renderOpenGL(){
OpenGLHelpers::clear (Colour (Colours::black.withAlpha(0.0f)));
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

OpenGLHelpers::prepareFor2D (getContextWidth(), getContextHeight());
OpenGLHelpers::setPerspective (45.0, getContextWidth() / (double) getContextHeight(), 0.1, 100.0);
glTranslatef (0.0f, 0.0f, -3.0f);

//…draw a bunch of junk

glDisable(GL_BLEND);
}
[/code]
All I can think to do is set the Alpha of the “clear” colour in the first line of the renderer or try to find some OpenGL flag to allow for a transparent background. I am pretty new to all this so I hope I’m not overlooking something obvious. Thoughts oh-great-JUCE-community-of-geniusness?


#2

3D over 2D? not tried that, but here’s some ideas:

stop the child 3D component drawing 2D (does by default), glctx.setComponentPaintingEnabled(false).

set child to be opaque setOpaque(true)' then definepaint’ to do nothing.

?


#3

Thanks for the reply! I have tried stopping 2D rendering (context.setComponentPaintingEnabled(false)) and setting the child component to Opaque and neither made any difference. For reference, here’s a censored version of the GUI so you can see what I’m trying to do:

[attachment=0]GUI_public.png[/attachment]

The polar pattern (in the big black box) is rendered in 3D to give the perspective of pointing into the screen relative to the smaller pink rectangle in the middle. I need to make the background of my child component transparent so that the graphics of the parent can be seen through the axis tick marks and the polar pattern while maintaining the 3D perspective. Is this more helpful? I really hope this is doable because it’s going to cause substantial problems with my architecture if I have to add the polar pattern graphics directly to the parent component.


#4

The juce demo has an example of rendering 3D into a texture. Maybe this can be a 2D Image that you can then paint as you wish. Ok, so it’s a bit long-winded; render 3D into a 2D image then you have to drawImageAt in your (now 2D) child component.

Of course, there might be a really simple way as it is now.

Anyone?


#5

If your component is using a GL rendering engine, then you can actually make whatever 3D GL calls you need to in its paint() method (after all, the 2D rendering is just making GL calls at that point)… However, you’d have to make sure that you reset the GL context to exactly the same state it was in when you began drawing, otherwise subsequent 2D drawing will go wrong.


#6

I can help with that bit. here’s what you need to reset.

void _resetGLTests() { // disable 3d drawing tests to allow 2D drawing. glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE); glDisable( GL_DITHER); }


#7

Actually, thinking about it, this won’t work 100% correctly, because the 2D renderer class has state that would need to be flushed before it’s safe to call your own drawing code.

To make it work, I think we’d need to add some methods to the 2D renderer which would flush its internal state, and then to tell it that the current GL context has been modified and that it needs to re-initialise any state before drawing again.


#8

I appreciate the help, however, I haven’t been able to get anything working yet. I tried adding glDisable for the state variables hugh mentioned (CULL_FACE and DITHER) as well as setting up the state variables exactly as is done in the OpenGLDemo. Neither made a difference for the background. Jules, I tried moving all my openGL calls to the (previously empty) paint() function. Now nothing draws.

It sounds like yall are suggesting that the state variables need to be set correctly before I can expect it to draw correctly in either the renderOpenGL() or paint() functions. Since I’m new to GL, I have no idea how to look at these variables to see what is set before / after my drawing. I’m been trying to use gDebugger but I’m not learning much from it yet.

Hugh, how did you determine the glDisable calls you suggested?

Jules, is this 2D internal state rendering / reinitializing something that I have a realistic chance of accomplishing on my own? Any other suggestions for how I can debug and fix the OpenGL bits that aren’t set correctly?

I thought managing the background would be way easier than all the drawing and junk :smiley:


#9

So, here’s the skinny. OpenGL views go on top of other views - they are windows, essentially, and don’t support transparency, AFAICT.

The way around is to do all the drawing you need to in the OpenGL view itself. A few approaches:

  • Manually ‘copy’ the view underneath the OpenGL view and use that as a background in your OpenGL view. It works, but if there’s a lot of changes I can see it failing.

  • Do any 2D stuff in a Paint function of the 3D view. That, obviously gets awkward if there’s overlap, so you need to start expanding your 3D view until it covers all the stuff you need and draw it in the 3D view instead. You should be able to use Components etc. still, but they’ll in ‘in’ the 3D view.

  • The best option is that Jules acts on his plans to extend the OpenGLRenderer to allow OpenGL views to render ‘in it’. Then your OpenGL Component on top will use the renderer’s context, and will be another render operation on top of the other rendered items.

Option 3 is the best, by far, but I think it may still be on the drawing board (Jules?). So you’ll have to go for option 2. Look at the OpenGL portion of the JuceDemo and expand and ‘lower’ your OpenGL Component as needed.

Bruce


#10

Oh my…

Thanks Bruce and Jules! That really helps me understand how things are organized. I can conceptually dig the “rendering down” approach to try to set the 3D child’s background to include the stuff underneath. However, I am trying to use multiple polar-pattern children (currently each their own OpenGL renderers) that are movable, can overlap each other, and currently have all the mouse-based interactions (among other things) nicely encapsulated. Therefore, it looks like taking the parent background graphics up into the children isn’t going to work. example picture below.

Am I correct in assuming that I am going to have to make the parent the OpenGLRenderer and find a way of getting the child OpenGL data (framebuffer?) into the ‘parental renderer?’ Is there some way to just call the drawing functions of the child in the parent’s RenderOpenGL() function? Or, can I just pass the parent a pointer to each child’s drawing data, like passing a pointer to an audio buffer between components? I really hope OpenGL works like that (fingers crossed).

[attachment=0]GUI_public2.png[/attachment]


#11

Oh, yuck. You have the worst case.

Well, you can share OpenGL contexts, but that will break your need for transparent overlap. So you’ll have to make an OpenGLContext that fills the entire area your windows might go, and then manage some OpenGL rendering yourself (as opposed to one OpenGLComponent per shape/view).

You could just draw each/every shape you want, changing the viewport as needed, or you could draw each shape into it’s own FBO and then composite them all?

Bruce

PS - an FBO allows you to use a texture as a render target. You bind to the FBO, then unbind and use the resulting texture in a screen aligned quad in your main render. Jules does similar things with the 2D/3D drawing mix.


#12

[quote]
Hugh, how did you determine the glDisable calls you suggested?[/quote]

I’m doing the opposite to you. I draw a 3D scene, but i sometimes want to overlay a 2D UI with transparency. For example, the 2D allows you to change the lighting of the 3D scene, so you can see it change underneath.

I render 3D in renderOpenGL' and the 2D inpaint’. However, because i change the OGL state in my 3D render, i have to reset it back before paint.

For your problem, is there some way you can render the 3D into a frame buffer then access the frame buffer as a 2D juce image?


#13

Thanks for all the suggestions! I was able to fix this by making the parent the OpenGLRenderer and calling the (renamed) renderOpenGL functions of the children directly in the actual RenderOpenGL function of the parent. This made the children draw to the size of the parent, but the components still knew the size they were supposed to be. So, it wasn’t that hard to have the child set it’s own size:

void MyChild::renderOpenGLWhenCalledByParent(){ glPushMatrix(); Rectangle<int> r = this->getBounds(); glViewport(r.getX(), r.getY(), getWidth(), getHeight()); //...draw all the stuffs glPopMatrix(); }

This may be obvious to all of you more experienced in OpenGL, but for anyone that (like me) tried to treat OpenGL rendering like the JUCE Paint() rendering, this is how you can move from one to the other. Yall rock!!!
[attachment=0]GUI_public3.png[/attachment]


#14

In case it's useful to anyone, here an implementation of the first option you mentioned: http://www.juce.com/forum/topic/transparent-opengl-component