Render to texture

Folks,

I am trying to make render to texture work on opengl es 2. I am testing my code on ubuntu using opengles2 mesa.

I don’t get any error but my texture contains only background color. Any advice?

Core looks like this:

glGenFramebuffers(1, &this->m_frameBufferHandle);

glGenTextures(1, &this->m_textureHandle);
glBindTexture(GL_TEXTURE_2D, this->m_textureHandle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture.width, texture.height, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, NULL);

glGenRenderbuffers(1, &this->renderBufferHandle);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
texture.width(), texture.height());

glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBufferHandle);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->m_textureHandle, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->renderBufferHandle);


render()

Not sure if my code is doing it redundantly, but you’re missing a couple of things:

  1. You’re not setting the viewport with glViewport
  2. You’re not setting the draw buffer to GL_FRONT
  3. My code calls wglSetPbufferAttribARB (before drawing TO the texture) - guessing that won’t apply for you but maybe you need to do something different, I’m using it to select a cubemap face for environment mapping
  4. Do you need to use another context for it? I am. So I don’t have to do a whole lot of state thrashing.
  5. glRenderbufferStorage may not necessarily create a bitmap with the exact size requested, right? I had to read-back the actually created size in my (windows) code.
  6. Are you (can you?) calling *glShareLists, I am so I don’t have to duplicate a lot of stuff in my render to texture.

Sorry, I must admin I really don’t know ES very well. I do have working render to texture, trying to help.

Doug,

Thanks for your reply. I am setting view port (just not posted the code here), in ES there is no such call as glDrawBuffer, 3) does not apply, 4) I don’t think I need another context for it (not that I know of)
5) I am not so sure, 6) I am not calling glShareLists (as there is none on ES)

But thanks for your help!.. any other suggestions?


glGenFramebuffers(1, &this->m_frameBufferHandle);

glGenTextures(1, &this->m_textureHandle);
glBindTexture(GL_TEXTURE_2D, this->m_textureHandle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture.width, texture.height, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, NULL);

glGenRenderbuffers(1, &this->renderBufferHandle);

/*
  Add this command! you forgot to bind the render buffer!
*/
glBindRenderbuffer(GL_RENDERBUFFER, this->renderBufferHandle);


glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
texture.width(), texture.height());

glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBufferHandle);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->m_textureHandle, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, this->renderBufferHandle);



Add the code to bind the renderbuffer, and then the above should be fine to initialize the FBO, but the ick you have left out is the actual drawing to the FBO and presenting the contents. To be complete:

Draw to texture:


glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBufferHandle)
glViewport(0, 0, texture.width, texture.height)

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
drawTeapot(); 

Present the texture contents:


glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, window.width, window.height);

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

//draw your quad textured with this->m_textureHandle
drawQuad(this->m_textureHandle);


Also, have you checked for GL errors? On another note, MESA is not a particularly reliable GL implementation. I do not trust it. If you need to code to GLES2 AND if you have GL already working on your hardware, I strongly advise getting a GLES2 emulation library, both Imaginations Technology and ARM Mali provide one. Both of these just map to the local GL implementation but do a minor amount of data massaging.

Hi kRogue,

Sorry when I copy pasted the code, I made a mistake but I do bind render buffer, I even tried to use a depth texture none of them worked. For my testing, I just called glClearColor(1.0f, 0.0f, 0.0f, 1.0f), that did show up in the texture. What you mentioned, is what I am doing (I have used FBO’s in the past on desktops). Missing part is the geometry. Now if I don’t use FBO, geometry does show up, so it is not a clipping or any other issue. You might be right that I am relying on Mesa here but I could not find a 64 bit emulator (both Mali and Imagitec are 32 bit).

Also in fragment shader all I am doing is this:

gl_FragColor = myColor;

I even tried gl_FragData[0], same result.

Could you build for 32bit target and use the GLES2 emulation libs though? (I’ve never tried this).

Also, unless you are not using vertex attribute 0 in your shaders, code for GLES2 will usually work just fine with no issues for GL2, if either GL_ARB_framebuffer_object is present (or change the FBO calls to glSomeCallEXT) or require GL3 or higher (where FBO is core).

One more bit of paranoia: the jazz to render your object, if it uses blending that uses the alpha channel, then that would result in a difference between render to screen vs render to texture.

Also, I advise to making a depth-stencil texture and attaching that as both the stencil and depth buffers… this is the most reliable rendering path on desktops usually (but not on embedded devices though).

If you are not doing any blending you can get desperate. On your shader that you use the texture, try the following:


gl_FragColor=vec4(texture2d(samplerName, texture_coordinate).rgb, 1.0);

If that works, then you’ve found a MESA bug. Another attempt of desperation you could try GL_UNSIGNED_BYTE and GL_RGBA in place of GL_RGB565 and GL_RGB… but in all honesty this is just finding and then getting around MESA bugs.

I could try 32bit target but that would take some time as I would have to setup a system.

I am not sure if I understood what you said here:
Also, unless you are not using vertex attribute 0 in your shaders, code for GLES2 will usually work just fine with no issues for GL2, if either GL_ARB_framebuffer_object is present (or change the FBO calls to glSomeCallEXT) or require GL3 or higher (where FBO is core).

Are you saying that I should not be using 0 for vertex attribute?

I was using blend and blend function (most common one), but for testing I took it out. Also just to clarify, when I am rendering to buffer I am using (in fragment shader)

gl_FragColor = color

and when showing on a quad using:

gl_FragColor=vec4(texture2d(samplerName, texture_coordinate).rgb, 1.0);

Now like I said the the color that I used (glClearColor) for clear does show up in texture.

Also, unless you are not using vertex attribute 0 in your shaders, code for GLES2 will usually work just fine with no issues for GL2

What I mean here is the following: in desktop GL (2, 3 compatibility profile, 4 compatibility profile), vertex attribute 0 must be “used”. The basic beans is that if you specify all the attributes of your vertex shader via glBindAttribLocation so that none of the active attributes is 0, then GLES2 is ok, but desktop GL is not-ok. This is one of the rare case the GLES2 code will not just work in GL compatibility profiles [shaders are another matter though].

…if either GL_ARB_framebuffer_object is present (or change the FBO calls to glSomeCallEXT) or require GL3 or higher (where FBO is core).

Here the beans is this: FBO’s are not core in GL2. There are 2 extensions for FBO’s for GL: GL_EXT_framebuffer_object and GL_ARB_framebuffer_object. The EXT-extension, all function names are glSomethingEXT and should be available for quite older hardware on quite old drivers. The ARB extension is a “back port” of FBO as found in GL3(or higher) as an extension. The function names are glSomething (no EXT and no ARB). As a side note, the ARB extension includes functionality that a number of related EXT extensions of GL_EXT_framebuffer_object specify. AFAIK, NVIDIA cards back to GeForce6 support GL_ARB_framebuffer_object (but I am not too sure about FX or before though).

My main hunches are the following:

  • you are using blending when you render to the texture (this is what I am thinking about) that relies on the alpha channel. Since you have a 3 channel texture, the alpha value is considered to always be 1 (I think). But since clear works, I suspect that when you are drawing to the texture some blending is going on.[] stencil-depth state: possibly not clearing the depth and stencil buffers of the FBO when you draw to the texture. Also possible issues about depth and stencil test not being set correctly when you draw to the texture. On the subject of GL on desktop, I strongly advise to use depth24-stencil8 as the depth and stencil buffer. Embedded systems are different, but the desktop really, really prefers that.[] GL error happened somewhere[*] MESA bug