Main Menu

FBO Question

Started by Schmidget, May 02, 2009, 05:14:06

Previous topic - Next topic

Schmidget

I've been working on a simple game engine for fun just to get some practice and experience working with openGL and Java.  I wanted to use FBOs in a sort of Render To Texture class where you could draw text, lines, sprites, etc. one time to a texture offscreen, then render that texture to a quad.  It's been basically working. I have the basic idea down and it was surprisingly easy to do.  But I have one issue.  Although the viewport is set to the size of the texture, it seems the rendering dimensions of the FBO are the same as the current window.  For example, if my main window size is set to 1280x800, and I create a 256x256 texture, the drawing is rendered within the texture properly; however, if I draw a perfect square centered relative to the texture, it will instead draw a much smaller rectangle in the lower left corner. 

I might have missed a thing or two about how frame buffers objects work.  Maybe that's just the way they are implemented and I have to provide a workaround for that.  My code is nearly identical to the FBO tutorial code in the wiki. 



There's basically what I'm talking about.  The dimensions of the texture are 256x256 and the window was 800x600. I just drew a sequence of lines to the corners of the texture size.  What I would expect is a border of sorts around the perimeter of the texture.  No such luck.  If I made those lines go to the corners of the window dimensions, it would put a perfect border around the texture.

I tried playing with the ortho settings, setting it to the dimensions of the texture, but nothing I tried seemed to work.  Is there some step I'm missing before/after the viewport setting?

Here's some very truncated code:
private int fboId;
private int textureId;
private IntBuffer buffer;
private int texSize;

//Set up the FBO and the Texture
buffer = ByteBuffer.allocateDirect(1*4).order(ByteOrder.nativeOrder()).asIntBuffer(); // allocate a 1 int byte buffer
EXTFramebufferObject.glGenFramebuffersEXT( buffer ); // generate 
fboId = buffer.get();
			
textureId=jrTexture.makeTexture(texSize);
			
EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fboId );
EXTFramebufferObject.glFramebufferTexture2DEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,GL11.GL_TEXTURE_2D, textureId, 0);

//Start drawing to the FBO
EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fboId );
GL11.glPushAttrib(GL11.GL_VIEWPORT_BIT);
GL11.glViewport(0,0,texSize, texSize);

/*************************
 My engine draws some lines here
*************************/

//Stop drawing to the FBO
GL11.glPopAttrib();
EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);


Any ideas?  Can you tell I have absolutely no idea what I'm doing?  With all that said, I got text to work all on my own!  That seemed like a challenge at first, but looking back at it, it wasn't too bad at all.


EDIT:
Maybe I should be using PBuffers for this sort of thing?

Kai

Hi,

Quote[...]it seems the rendering dimensions of the FBO are the same as the current window
Nope, these are always specified via glViewport.

It seems like you use a wrong transformation matrix (modelview or projection).

If you are going to render into the FBO a border with four lines, try the following (pseudocode):
bind FBO
viewport(0, 0, texSize, texSize)
modelviewMatrix = identity
projectionMatrix = identity
lineWidth = 3 (at least, to see the lines at y = 1 and x = 1)
drawLine(start=(-1, -1, 0), end=(1, -1, 0))
drawLine(start=(1, -1, 0), end=(1, 1, 0))
drawLine(start=(1, 1, 0), end=(-1, 1, 0))
drawLine(start=(-1, 1, 0), end=(-1, -1, 0))
unbind FBO

(Note: you might as well use the "QUAD" primitive and provide the four corners to it)

Now, bind the texture to the quad you want to draw onto the screen and use proper texture coordinates (u=[0..1], v=[0..1]) on it.

QuoteMaybe I should be using PBuffers for this sort of thing?
FBOs are really easier to use and way faster, since there is not additional GL context switching involved.

Schmidget

It looks like that did the trick.


One thing though, I had to reset back to the original ortho settings by hand.  Is there anyway to push/pop those settings or will I have to code around that?

By the way the line drawing was just used for illustration.  I'm not really going through all this trouble just to draw lines around a square  :P
It's just going to be a separate drawable surface.  Kinda like how you can make a buffered image, grab a graphics2D from it, draw some stuff to it, then render it to a window.  Speaking of which, is there a limit to the number of FBO's one can have?

Kai

Quote[...]Is there anyway to push/pop those settings or will I have to code around that?
Yes, fortunately there is. As you did push the viewport attribute with glPushAttrib/glPopAttrib, thereis an equivalent glPushMatrix/glPopMatrix for the currently active matrix mode.

Quote[...]is there a limit to the number of FBO's one can have?
You surely don't need a separate FBO for each texture you want to draw to. One FBO is quite sufficient for anything you want to render into arbitrary textures.
The glFramebufferTexture2DEXT you used to bind a texture to the FBO can be called as many times as necessary to bind other textures to the FBO.

Schmidget

Alright that makes sense.  So I need to create just one FBO and then switch which textures are attached to it.  It will be interesting trying to make that work with my current engine paradigm.

EDIT:

Well, I gave the ol' push/pop matrix a go:



Not quite what I expected.  The previous settings still seem to be in effect...

Kai

QuoteThe previous settings still seem to be in effect...
You must make sure that you push/pop both the modelview and projection matrices separately.

matrixmode = modelview
pushMatrix
matrixmode = projection
pushMatrix

do the FBO stuff

matrixmode = modelview
popMatrix
matrixmode = projection
popMatrix

now, everything  is back to normal


The glPushMatrix/glPopMatrix commands affect the "current" active! matrix mode (set via glMatrixMode!)

Schmidget

Awesome! That did the trick!  Thanks!  It looks like I need to buy an OpenGL book.  Any recommendations?

Now I have to do a bit of restructuring to make RenderTargets work the way I want.  I think I have an idea of how I'll do it.
The first time a RenderTarget is made, it will generate the FBO and a corresponding texture.  Then every other RenderTarget will just generate a new texture, and steal the already created FBO.  Whenever some drawing is started it will just make sure the FBO attached texture is set to the correct texture.

Kai

QuoteAny recommendations?
I do recommend reading the OpenGL tutorials at http://wiki.delphigl.com/index.php/DelphiGL as well as working through the famous nehe tutorials at http://nehe.gamedev.net/lesson.asp?index=01.

Schmidget

Hello again.  That last trick worked like a charm.  I set some things up allowing me to make RenderTargets and I was able to render paragraphs of text to one.  The only other thing I wanted to do was fake a 3d rotation from within the ortho2D mode.  I did this by just moving the vertexes of the quad in such a way that it gave a pretty convincing illusion of rotation. 

Basically what I'm doing is using a GL11.glRotatef(rY,0f,1f,0f),tThen moving the moving the corner Y values toward or away from each other. Unfortunately, it looks like there are some limitations to this method because of the way the polys get textured.  The texture is rendered on each triangle of the quad in an expected, but unintended way.





There's the result.  In order to make the rotation more convincing, there are only two things I can think of: 
-Pull out of ortho mode for a second to render the quad in 3D space.
-Or give the shape more polys.

I'm very new to openGL and I don't really know how to bounce back and forth between the coordinate systems so the first one seems kind of tricky.

I was wondering if there was any sort of texturing mode which might give me a better result, or if I'm stuck with one of those two methods.

Any advice?

Kai

Hi,

what you did, as you described it, is simulating a 3D effect using the already perspectively transformed vertices (if you would have used 3D) and render those using a non-perspective (orthogonal) projection matrix.

QuotePull out of ortho mode for a second to render the quad in 3D space.
That's what I would do.
Because texture interpolation also takes the depth/perspective of the scene into account, that would be the more reasonable approach.
This is also the reason why you are getting that distorted texture interpolation, because your scene is entirely on one 2D-surface (with the same z-value everywhere).

Assuming you have a basic understanding of matrix manipulation i.e. linear algebra in general, I think it would be worth first learning about the co-ordinate systems in OpenGL and how they transform into each other (what is "model space", "world space", "camera/view space", "clipping space", "screen/device space", etc.). On top of that you might want to know what a perspective matrix actually is (what values play an important role in such a matrix).
If you get a hang of that, it should be easier to apply that knowledge to OpenGL (at least that how I would have wanted to learned it, had I done it right in the first place :-)).