Afternoon
I have a quick question, is it possible in openFrameworks to render to a texture?
Can I use standard openGL pBuffers?
has anyone done this before?
thanks & best regards
Dave Green
Afternoon
I have a quick question, is it possible in openFrameworks to render to a texture?
Can I use standard openGL pBuffers?
has anyone done this before?
thanks & best regards
Dave Green
Well ofTexture has the loadScreenData command which can grab a portion of the screen.
http://openframeworks.cc/documentation#-…-ScreenData
This requires you to draw somewhere offscreen first capture it into the texture and the display it. You can see this working in the ofTextureScreengrabExample.
You could also do all your drawing that you want to go the the texture, capture to texture and then call glFlush(); to clear the screen and then do the drawing you want people to see.
Hope that is clear
Theo
Hello Gents,
I have a similar challenge. I would like to draw to a texture which is larger than my screen resolution, and then sample from this texture and draw to the screen.
At the moment I am drawing to the screen, and trying to draw offscreen, and then sampling from the screen using a texture and loadScreenData calls. I then redraw this texture on screen several times.
When I sample an area partially offscreen, my texture can only “grab” from onscreen areas.
One way I can see around this is do all my drawing into a texture, and then sample from that to draw onscreen. How do I draw to a texture?
Do I want to use glBindTexture? All my rendering code is pure openGL, rather than using the OF bindings. I will also need to be able to set the renderer to render to the screen afterwards.
JGL
I’m working on a class that will handle drawing to an offscreen FBO buffer, and then draw that to the screen if you want.
This is a lot faster than drawing to the screen and using grabscreen.
Hopefully it’ll be done pretty soon
If you guys have graphics card’s that support FBO’s It might be what you’re looking for
here’s the FBO class:
http://www.stfj.net/misc/ofFBOTexture.zip
It extends ofTexture, so everything should be cool cross platform and all.
It’s pretty easy to use, just
allocate(width, height, bool autoClear) // autoClear decides if it will clear every frame or if it wont (for accumulating data), if you want to manually clear it just call clear().
then, to draw to it you just call swapIn() and draw like you normally would to the screen.
and when you’re done drawing to it you call swapOut().
since it extends ofTexture, to draw it to the screen, you just call draw(x,y)
let me know how this works for you guys
if you
glPushAttrib(GL_VIEWPORT_BIT);
in your swapIn() method and pop it in swapOut(), you can return the viewport back to the proper dimensions. Also, I’d imagine you’d want to set the viewport to the dimensions of the attached texture as well. Otherwise, looks very close to what I did for FBO support
wes
Yeah, i was trying that at first, but it was completely messing up the dimensions of the image, so I quit trying.
This one seems to work properly without it though
something else. It’s also standard practice to check for FBO completeness after attaching textures and render buffers to the FBO. Here’s the method I use to do this.
void FBO :: checkStatus()
{
GLenum status;
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch(status)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
printf("framebuffer GL_FRAMEBUFFER_UNSUPPORTED_EXT\n");
/* you gotta choose different formats */
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
printf("framebuffer INCOMPLETE_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
printf("framebuffer FRAMEBUFFER_MISSING_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
printf("framebuffer FRAMEBUFFER_DIMENSIONS\n");
break;
case 0x8CD8: //GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
printf("framebuffer INCOMPLETE_DUPLICATE_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
printf("framebuffer INCOMPLETE_FORMATS\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
printf("framebuffer INCOMPLETE_DRAW_BUFFER\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
printf("framebuffer INCOMPLETE_READ_BUFFER\n");
break;
case GL_FRAMEBUFFER_BINDING_EXT:
printf("framebuffer BINDING_EXT\n");
break;
case 0x8CDE: // GL_FRAMEBUFFER_STATUS_ERROR_EXT:
printf("framebuffer STATUS_ERROR\n");
break;
default:
/* programming error; will fail on all hardware */
//exit(0);
break;
}
}
cool. yeah i do have a check to make sure that the fbo completes, but it’s not as comprehensive as this one, so I’ll add this code. thanks!
I can see how setting the viewport would be useful, but every time i change it it completely destroys the scale of the buffer…
did you extend ofTexture when you made your FBO? if not how did you make sure it would render correctly?
I guess ill keep tinkering
Ah, now I see where you were checking. I completely overlooked those lines.
As far as viewport corruption is concerned, I’ve never had any issues, so I can’t really say what’s going on. I’m only using OF for the video camera and video file playback. I have my own Texture, Matrix, and misc. other OpenGL classes pulled together in what I call libmuro. Below is a link to the Texture and FBO classes, which you can take apart and see what works for you. There are some dependencies that I didn’t include, but they should be pretty trivial to remove.
http://www.mat.ucsb.edu/~whsmith/FBO-Texture.zip
HTH,
wes
Oh awesome, thanks! I’ll take a look at those.
It makes sense that you didn’t encounter any problems if you weren’t using OF to actually draw.
Since openframeworks does a lot of messing with the camera to setup the screen initially (0,0 is in the upper left, for example), it ends up creating a lot of strange things, like textures that automatically flip themselves so that they display properly.
Initially when I was creating my fbo class I tried to just create a texture that wasn’t connected with openframeworks explicitly, but it caused a ton of scaling problems due to using OF draw methods which were meant for the of viewport setup.
Now that I’m extending ofTexture, everything works fine as long as I dont try changing the viewport
I’ll probably consult with zach in a few days and see if he can think of anything
Right, the pixel-based opengl coordinates of OF can be tricky to deal with in this situation. I can see the reasoning behind doing this (following processing and perhaps easing the burden of learning OpenGL although I would say teach people this stuff up front instead of hiding it), but IMHO, pixel-based coordinates are not good for doing opengl work unless you’re working strictly in an ortho 2D world and even then, it’s way easier to use normalized [-1, 1] coordinates. Any time that your rendering scale depends on window size is not good.
Still, I don’t see how this should affect FBO RTT sections as you should be able to simply push the viewport attribut to save state and pop it back when donebehind your back unless OF is doing some viewport resetting behind your back, which would be odd.
following processing and perhaps easing the burden of learning OpenGL although I would say teach people this stuff up front instead of hiding it
since it’s opengl, people can setup the world however they want, but in the end, I’ve been teaching opengl for a while and *alot* of people get:
– confused by coordinate systems that are very small (normalized -1,1)
– tremendous trouble working at non-pixel scale for 2d graphics
– have trouble w. lower left = 0,0
– frustrated plugging in different opengl examples compiled for different scales.
I honestly think that 0,0 in the top left is the best of all worlds – for 2d folks, you can go ahead and draw and everything makes sense. For 3d folks, it will work too and your scalings will make sense because you know your screen size (and you can easily scale normalized stuff up). And, if you feel like how you feel, just rest everything yourself. We don’t do anything in the drawing that is based on screen size or viewport, so you can override our setup and do what you want.
in OF it’s explicitly not hidden - just poke around the setup in ofGraphics and change it however you want. This is why we release apps with the source code to the library uncompiled. If you fee like that, **just change it **!
you can then even post about it so that other -1,1 folks can give it a try. if you poke around the forum, you’ll see that this is what this is about. We are definitely not hiding anything - but just trying to simplify things, so it’s easier to get started and that a beginner doesn’t have to learn too many things to get up and running.
the stuff we are doing is so minimal, it’s all in ofGraphics setup()… there’s nothing else there…
hope that helps!
take care,
zach
Hi zach_gage, thanks for the ofFBO Class looks great, but I’m having some trouble with it… basically I get a black screen (not even the stuff drawn directly to the screen is visible).
These are some of the tests I’ve tried:
So it seems I have two problems:
I had a look at your class as well otherside, but it was a bit over my head and I couldn’t figure out what I would need to carry across. Been reading loads on gpgpu.org but its all a bit too much to take in at once!
Any ideas appreciated!
*EDIT*: I’m running on a Mac Pro with ATI X1900XT
my code is as follows:
void testApp::setup(){
ofBackground(0, 0, 0);
bikeIcon.loadImage("bike_icon.png");
glslPlasma.loadShader("plasma.frag", "basic.vert");
fboPlasma.allocate(256, 256, false);
glDepthMask(false);
glDisable(GL_DEPTH_TEST);
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
}
void testApp::draw(){
fboPlasma.swapIn();
glPushMatrix();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glslPlasma.setShaderActive(true);
glslPlasma.setUniformVariable("t", 0.0009f * ofGetElapsedTimeMillis());
glslPlasma.setUniformVariable("scaleX", 1.0f);
glslPlasma.setUniformVariable("scaleY", 1.0f);
glslPlasma.setUniformVariable("base", 0.5f);
bikeIcon.draw(0, 0);
/* glBegin( GL_QUADS );
glTexCoord2f(0, 0); glVertex3i(0, 0, 0);
glTexCoord2f(1, 0); glVertex3i(100, 0, 0);
glTexCoord2f(1, 1); glVertex3i(100, 100, 0);
glTexCoord2f(0, 1); glVertex3i(0, 100, 0);
glEnd();
*/ glPopMatrix();
glslPlasma.setShaderActive(false);
fboPlasma.swapOut();
fboPlasma.draw(100, 0);
bikeIcon.draw(600, 400);
}
// plasma.frag:
uniform float t; // time, increment this a bit every frame
uniform float scaleX; // how many cycle on the x axis
uniform float scaleY; // how mnay cycles on the y axis
uniform float base; // the base intensity
void main() {
vec3 pos = vec3(gl_TexCoord[0].x * scaleX, gl_TexCoord[0].y * scaleY, t);
gl_FragColor = vec4(noise3(pos) + base, 1.0);
}
// basic.vert:
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}
[/code]
memo, I just posted some updated FBO texture code.
the old code was kind of buggy and would have problems with FBOs that werent the same size as the window (i know, kind of useless right?). sorry!
this code should work better
let me know if it works for you
http://www.stfj.net/misc/ofFBOTexture2.zip
-zach
Hi Zach, thanks for that… its getting closer now. If I don’t have any shaders active, the fbo rendering works fine. I draw the bike to (0, 0) when the fbo is active, and then draw the fbo to 100, 0 and thats where the bike appears. So all is good there! As soon as I activate the shader though, I still see nothing… not even the normal bike drawn after the swapOut! The shader works by itself though when the fbo is not active… dunno if this is anything to do with the fbo, or something else :S
thanks for you help
hmmm/// i dont know too much about shaders, but if you zip up your program and email (zachstfj@gmail.com) it to me i’ll take a crack at correcting the fbo stuff so it works…
It looks like you’re applying your shader to the fbo? is that what you mean to be doing?
does the shader work if you try drawing other textures to the window? e.g. try using an ofImage to copy the screen into a texture and then telling that texture to draw… you might have to un-protect the ofImage’s texture to do that
Thanks zach, zip in the post…
I want to render a quad into the FBO using a fragment shader, so then I can feed it into other shaders, and also read back to the CPU so effectively the GPU will have done some calculations for me - eventually I won’t be using an ofImage for this, just a normal GL_QUAD, but just using an image now for testing.
My code is below. If the 3rd block in the draw() function (render with shader to FBO) is on, then I don’t even see the results of the previous draws. But if the 3rd block is commented out, then everything else works fine (I can see the normally drawn pic and plasma, as well as the fbo pic).
void testApp::setup(){
ofBackground(0, 0, 0);
image.loadImage("pic.jpg");
glslPlasma.loadShader("plasma.frag", "basic.vert");
fbo1.allocate(200, 200, true);
fbo2.allocate(200, 200, true);
glDepthMask(false);
glDisable(GL_DEPTH_TEST);
glEnable( GL_BLEND );
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
}
void testApp::draw(){
image.draw(0, 0); // draw image normally
drawPicWithShader(200, 0); // draw with plasma shader
fbo1.swapIn();
image.draw(0, 0); // draw to fbo
fbo1.swapOut();
fbo1.draw(0, 200); // draw fbo (should be normal pic)
fbo2.swapIn();
drawPicWithShader(0, 0); // draw with shader to fbo
fbo2.swapOut();
fbo2.draw(200, 200); // draw fbo (should be plasma)
}
void testApp::drawPicWithShader(int x, int y) {
glslPlasma.setShaderActive(true);
image.draw(x, y);
glslPlasma.setUniformVariable("t", 0.0009f * ofGetElapsedTimeMillis());
glslPlasma.setUniformVariable("scaleX", 0.01f);
glslPlasma.setUniformVariable("scaleY", 0.01f);
glslPlasma.setUniformVariable("base", 0.5f);
glslPlasma.setShaderActive(false);
}
so from looking around the internet, it looks like FBOs need to be set up specifically to handle shaders… it seems like you need multiple texture layers (?) but im not sure exactly. My opengl abilities are kind of limited. I have a book that Ill look into but i was wondering if anyone else has had any experience in using shaders within fbos (in openframeworks or otherwise)
otherside, do you have any ideas on how to do this?
Hi FBOs do not need to be specifically setup with shaders to work. When you bind an FBO, everything works just like normal drawing except the pixels flow into the FBO’s texture instead of to the screen. So, the same method for using shaders when drawing to screen applies to when using FBOs.
Here’s a link to a really bare-bones GLUT app showing how to use shaders and FBOs. I did this quickly so there may be a few odd things going on, but it is still a very good and pared down example of how to use shaders and fbos. I did it to test out multiple render targets, so it does a bit more than you probably need.