Hello,
I have create a frame buffer object with the following code. However, when I bind it, I cannot draw to the texture at all (not even change the color with glClear). Absolutely nothing happens. What am I missing?
Here is how I generate the FBO:
// Generate the fbo
int fbo = EXTFramebufferObject.glGenFramebuffersEXT();
GLErrorCheck();
// Attach a texture to render to
int texture = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
// The null at the end must be cast to tell javac which overload to use,
// even though the last parameter (for the different overloads) isn't even used
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer)null);
// Unbind texture
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
GLErrorCheck();
// Bind the fbo for use
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo);
EXTFramebufferObject.glFramebufferTexture2DEXT(
EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,
GL11.GL_TEXTURE_2D, texture, 0); // The 0 is for mip map levels, we aren't using any
GLErrorCheck();
// Attach a depth buffer render buffer if desired
if(depthBuffer)
{
int depthRenBuff = EXTFramebufferObject.glGenRenderbuffersEXT();
// Bind it so we can set it up
EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, depthRenBuff);
// Set up the depth buffer
EXTFramebufferObject.glRenderbufferStorageEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, GL11.GL_DEPTH_COMPONENT, width, height);
// Attach the dpeth buffer
EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, depthRenBuff);
GLErrorCheck();
}
// Check
if(EXTFramebufferObject.glCheckFramebufferStatusEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT) != EXTFramebufferObject.GL_FRAMEBUFFER_COMPLETE_EXT)
throw new Error("Could not create FBO!");
// An fbo has its own viewport, so lets set it
GL11.glViewport(0, 0, width, height);
// Unbind
EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
GLErrorCheck();
Binding it:
// Unbind textures
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo);
// Save view port information, since this will in almost all cases change (states are shared with main context)
GL11.glPushAttrib(GL11.GL_VIEWPORT_BIT | GL11.GL_COLOR_BUFFER_BIT);
Unbinding:
// Finish all operations so can use texture
GL11.glFlush();
// Restore saved information for main rendering context
GL11.glPopAttrib();
// Unbind
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
After the FBO is bound I do the following:
// Create the view port for this render texture
GL11.glViewport(0, 0, m_width, m_height);
GL11.glClearColor(0.5f, 0.2f, 0.8f, 1.0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
After unbinding the FBO, I bind the texture that went with it and draw a quad, but it is plain white every time.
Without all of your code, it's hard to tell what the problem is, but I don't see that you are enabling texturing (which would explain why everything appears white). Make sure you call GL11.glEnable(GL11.GL_TEXTURE_2D).
Here is a complete and minimal code example that produces this problem:
public static void main(String[] args)
{
try
{
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create();
Display.setVSyncEnabled(true);
}
catch(LWJGLException e)
{
e.printStackTrace();
System.exit(0);
}
// Requirements
if(!GLContext.getCapabilities().GL_EXT_framebuffer_object)
throw new Error("FBOs not supported! Get a better computer!");
// Defaults
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_DEPTH_BUFFER_BIT);
// Set up orthographic projection for 2D
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glOrtho(0, 800, 0, 600, -100, 100);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
// Create a FBO
// Generate the fbo
int fbo = EXTFramebufferObject.glGenFramebuffersEXT();
// Attach a texture to render to
int texture = GL11.glGenTextures();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
// The null at the end must be cast to tell javac which overload to use,
// even though the last parameter (for the different overloads) isn't even used
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, 800, 600, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer)null);
// Unbind texture
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
// Bind the fbo for use
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo);
EXTFramebufferObject.glFramebufferTexture2DEXT(
EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,
GL11.GL_TEXTURE_2D, texture, 0); // The 0 is for mip map levels, we aren't using any
// Check
if(EXTFramebufferObject.glCheckFramebufferStatusEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT) != EXTFramebufferObject.GL_FRAMEBUFFER_COMPLETE_EXT)
throw new Error("Could not create FBO!");
// An fbo has its own viewport, so lets set it
GL11.glViewport(0, 0, 800, 600);
// Unbind
EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
// Game loop
while(!Keyboard.isKeyDown(Keyboard.KEY_ESCAPE))
{
GL11.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
// --------------------- Render to the FBO ----------------------
// Unbind textures
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, fbo);
// Save view port information
GL11.glPushAttrib(GL11.GL_VIEWPORT_BIT);
// Clear the FBO to a color
GL11.glClearColor(0.5f, 0.3f, 0.3f, 1.0f);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
// Finish all operations so can use texture
GL11.glFlush();
// Restore saved information for main rendering context
GL11.glPopAttrib();
// Unbind the FBO
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
// ------------------ Render FBO to the screen -----------------------
// Draw a quad with the FBO on it
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0.0f, 0.0f); GL11.glVertex2f(200.0f, 200.0f);
GL11.glTexCoord2f(1.0f, 0.0f); GL11.glVertex2f(600.0f, 200.0f);
GL11.glTexCoord2f(1.0f, 1.0f); GL11.glVertex2f(600.0f, 600.0f);
GL11.glTexCoord2f(0.0f, 1.0f); GL11.glVertex2f(200.0f, 600.0f);
GL11.glEnd();
Display.update();
}
}
The FBO does not change from a plain white texture, so I assume it is never really rendering to it.
Bump
Bump
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
You need to set GL_TEXTURE_MIN_FILTER to GL_LINEAR instead of GL_LINEAR_MIPMAP_LINEAR. You're only defining a single mip map level in the texture.
GL11.glDisable(GL11.GL_DEPTH_BUFFER_BIT);
Unrelated to your problem, but this line causes a GL error. You probably meant GL_DEPTH_TEST. There are a few options to catch errors like these while developing your app:
- Always put a Util.checkGLError(); in your main loop. That's the simplest solution, but it won't give you the error source.
- Use LWJGL's debug jar, which performs an error check after every GL call. This will give you the exact error source, but it will affect performance.
- Use the ARB_debug_output extension (or AMD_debug_output). This is the preferred way and it's very simple to enable:
Display.create(new PixelFormat(), new ContextAttribs(4, 2).withProfileCompatibility(true).withDebug(true));
...
if ( GLContext.getCapabilities().GL_ARB_debug_output )
ARBDebugOutput.glDebugMessageCallbackARB(new ARBDebugOutputCallback());
else if ( GLContext.getCapabilities().GL_AMD_debug_output )
AMDDebugOutput.glDebugMessageCallbackAMD(new AMDDebugOutputCallback());
Thank you very much! It was indeed the mipmap setting. Thanks for the advice on debugging!