FBO render to texture results in white texture - opengl

I'm trying to use FBO's for performance improvements and for the gained knowledge by trying out something new, but I have run in following problem:
When I render some texture to the back buffer it works perfect (just a bit slow because of multiple layers of textures on top of each other)
But when I try to first draw the textures onto another texture using an FBO the new texture always keeps white.
Now to the Code
This is my FBOsetup function (called at the beginning (after creating the Opengl context)):
int FBOId;
int FBOTexId;
void setupFBO(){
IntBuffer buffer = ByteBuffer.allocateDirect(1 * 4).order(ByteOrder.nativeOrder()).asIntBuffer();
glGenFramebuffersEXT(buffer);
FBOId= buffer.get();
FBOTexId=glGenTextures();
glBindTexture(GL_TEXTURE_2D, FBOTexId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tileSize, tileSize, 0, GL_RGB, GL_UNSIGNED_BYTE, ByteBuffer.allocateDirect(4*tileSize*tileSize));
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBOId);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, FBOTexId, 0);
}
Now the render function:
void redraw(){
glPushMatrix();
glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBOId);
glLoadIdentity();
glOrtho(0, tileSize, tileSize, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
Main.drawTexture(0, 0, tileSize, tileSize, textureRotation, textureId);
glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
glPopAttrib();
glPopMatrix();
}
And the final draw function:
void draw(){
Main.drawTexture(x*tileSize, y*tileSize, tileSize, tileSize, FBOTexId);
}
And for all who want it my drawTexture function:
public static void drawTexture(float x, float y, float xSize, float ySize, float rot, int textureId){
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
GL11.glMatrixMode(GL11.GL_TEXTURE);
GL11.glLoadIdentity();
GL11.glTranslatef(0.5f,0.5f,0.0f);
GL11.glRotatef(rot,0.0f,0.0f,1.0f);
GL11.glTranslatef(-0.5f,-0.5f,0.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0,0);
GL11.glVertex2f(x,y);
GL11.glTexCoord2f(1,0);
GL11.glVertex2f(x+xSize,y);
GL11.glTexCoord2f(1,1);
GL11.glVertex2f(x+xSize,y+ySize);
GL11.glTexCoord2f(0,1);
GL11.glVertex2f(x,y+ySize);
GL11.glEnd();
GL11.glMatrixMode(GL11.GL_MODELVIEW);
}
If I replace the Main.draw line in the draw() function with this Main.drawTexture(x*tileSize, y*tileSize, tileSize, tileSize, textureRotation, textureId); it directly draws the texture to the correct position on the screen, but the problem is that I would always have to redraw all layers of textures and with the FBO's I draw all the layers everytime something changes and then only draw the texture from the FBO.

Well first thanks for all the comments. I havent realy found the error nor do I understand why this is necessary but this is how it works:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
By adding these two lines of code after the glBindTexture(GL_TEXTURE_2D, FBOTextId) in the setupFBO() function everything works fine.
If u replace the GL_NEAREST in above lines with GL_LINEAR works too, but it has some strange artifacts when scaling the image.
By the way just a short question which has nothing to do with this thread:
Does someone know a way of making parts of a texture (by drawing to it with an fbo) transparant by evaluating the colors from another texture?

Related

Calling glActiveTexture(GL_TEXTURE1) before update() on a QOpenGLWidget causes textures to appear black

When inheriting from QOpenGLWidget and QOpenGLFunctions_4_5_Core, if I call glActiveTexture(GL_TEXTURE1) (or any other non-zero number) before calling update() textures appear completely black on the screen.
Relevant code snippets:
void OpenGLWidget::paintGL() {
if (fp) {
// First paint seems to always happen before the first update
qDebug() << "First Paint";
fp = false;
}
glClear(GL_COLOR_BUFFER_BIT);
unsigned int tex;
glGenTextures(1, &tex);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
QImage img = QImage("textures/awesomeface.png").convertToFormat(QImage::Format_RGBA8888).mirrored();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
glTextureParameteri(tex, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(tex, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameteri(tex, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTextureParameteri(tex, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glUseProgram(frame_shader.get_id());
glBindVertexArray(frame_vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
// Clean up
glDeleteTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
// This doesn't cause the textures to be black
glActiveTexture(GL_TEXTURE1);
}
And the mainloop function:
void OpenGLWidget::main_loop() {
if (fu) {
qDebug() << "First Update";
fu = false;
}
// This causes the textures to completely black
// Change GL_TEXTURE1 to GL_TEXTURE0 (or get rid of it glActiveTexture
// completely) and textures will work once again
glActiveTexture(GL_TEXTURE1);
update();
}
The shaders can still draw to the screen; if I set a solid color in the fragment shader, the color will properly display to the screen. It seems only user-made textures are turning completely black.
I'm not getting any OpenGL Errors.
The full MRE can be found at: https://github.com/Luminic/MRE_QOpenGLWidget_glActiveTexture_GL_TEXTURE1_before_update
Does anyone know what is causing this odd behavior?
Why is this supposed to be weird behaviour? It is completely reasonable that telling OpenGL to use the Texture Unit 1 of your hardware only draws black content, because in your code you do not have a texture attached to that unit. The
glActiveTexture(GL_TEXTURE1)
command sets the active texture unit to 1. Before you created the texture, you bound unit 0, so the texture lives there. Not setting this parameter at all is the same as setting it to 0, as this is the default unit. Calling glBindTexture after the glActiveTexture would resolve your problem too!

OpenGL rendering with texture unclear

I'm using the latest version of OpenGL. But when I create textures using the following function is written in C++:
GLuint Texture::Generate2dTexture(int width, int height, char* data, int length)
{
GLuint textureIndex;
glGenTextures(1, &textureIndex);
glBindTexture(GL_TEXTURE_2D, textureIndex);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return textureIndex;
}
and render using:
void Renderer::DrawRectangle(GLuint textureID, RECTD rect)
{
glBindTexture(GL_TEXTURE_2D, textureID);
glBegin(GL_QUADS);
{
glTexCoord2f(0.0f, 1.0f);
glVertex2d(rect.left, rect.top);
glTexCoord2f(0.0f, 0.0f);
glVertex2d(rect.left, rect.bottom);
glTexCoord2f(1.0f, 0.0f);
glVertex2d(rect.right, rect.bottom);
glTexCoord2f(1.0f, 1.0f);
glVertex2d(rect.right, rect.top);
}
glEnd();
}
They appear unclear after rendering. It seems quite different from the appearance in the image viewer made by M$.
What cause that to happen and how to avoid the risk?
Check the dimensions of your image. Most image loaders will expect images to be presented in powers of 2. So, an 8x8 pixel image should look clear (as opposed to stretched out or garbled). Try clipping the image to 32x32 or 128x128 etc to see if that helps. If the image you want cannot be represented where height=width you can still adjust the canvas so it is something like 128x128 and then simply use the UV coordinates to take the portion of the image you want for your texture.
Also, I think if you disable bilinear filtering any blurring should be taken care of:
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Please note this is not a definite answer - I don't have enough rep to comment...

Error rendering with GLSL framebuffer

I am trying to get into screen a video frame in a 2d texture covering the screen, I must use framebuffers, because eventually I wish to do the ping-pong rendering technique. But for the time being I want first to achieve just to render on the screen by using framebuffers.
This is my setup code:
// Texture setup
int[] text = new int[1];
glGenTextures(1, text, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, text[0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 512, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, null);
// Frambuffer setup
int[] fbo = new int[1];
glGenFramebuffers(1, fbo, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, text[0], 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Till here all ok, I didn't write here the testing code to keep it small, but right after I check if the frame buffer was created correctly, and all is fine.
Now in my Render loop I do next:
// Use the GLSL program
glUseProgram(programHandle);
// Swap to my FBO
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
glViewport(0, 0, 512, 512);
// Pass the new image data to the program so the fragment shader processes it.
// Using glTexSubImage2D to speed up
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, text[0]);
glUniform1i(glGetUniformLocation(programHandle, "u_texture"), 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 512, 512, GL_LUMINANCE, GL_UNSIGNED_BYTE, NewImageData);
// Draw the quad
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Swap back to the default screen frambuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
At this point I get a black screen, and on the log I can see a GL_INVALID_FRAMEBUFFER_OPERATION 1286.
I tried putting the glDrawArrays after the glBindFramebuffer call, but then the application crashes.
Any thoughts? Thanks in advance.
LUMINANCE textures are not renderable, this means you can't render to them using a FBO. This problem is solved with the GL_ARB_texture_rg extension, which introduces one and two channel texture formats that are renderable.

glTexImage2D multiple images

I'm drawing an image from openCV full screen, this is a large image at 60fps so I needed a faster way than the openCV gui.
Using OpenGL I do:
void paintGL() {
glClear (GL_COLOR_BUFFER_BIT);
glClearColor (0.0,0.0,0.0,1.0);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,width,height,0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, the_image_data );
glBegin(GL_QUADS);
glTexCoord2i(0,0); glVertex2i(0,height);
glTexCoord2i(0,1); glVertex2i(0,0);
glTexCoord2i(1,1); glVertex2i(width,0);
glTexCoord2i(1,0); glVertex2i(width,height);
glEnd();
glDisable(GL_TEXTURE_2D);
}
Now I want to draw two images side:side - using the openGL hardware to scale them.
I can shrink the image by changing the quad size I don't understand how to load two images with glTexImage2() since there is no handle or id associated with the image.
The reason why you cannot see how to add another texture is because you are missing two critical functions in the code that you posted: glGenTextures and glBindTexture. The first will generate texture objects in the OpenGL context (places for textures to exist on the graphics hardware). The second "selects" one of those texture objects for subsequent calls (glTex..) to affect it.
First of all, the functions like glTexParameteri and glTexImage2D do not need to be called again at every rendering loop... but I guess in your case, you should do that because the images are always changing. By default, in your code, the texture object used is the zeroth object (a reserved one for the default). You should create two texture objects and bind them one after the other to achieve the desired result:
GLuint tex_obj[2]; //create two names for the texture (should not be global variables, but just for sake of this example).
void initGL() {
glClearColor (0.0,0.0,0.0,1.0);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,width,height,0);
glEnable(GL_TEXTURE_2D);
glGenTextures(2,tex_obj); //generate 2 texture objects with names tex_obj[0] and [1]
glBindTexture(GL_TEXTURE_2D, tex_obj[0]); //bind the first texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //set its parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, tex_obj[1]); //bind the second texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //set its parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
void paintGL() {
glClear (GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D,tex_obj[0]); //bind the first texture.
//then load it into the graphics hardware:
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width0, height0, 0, GL_RGB, GL_UNSIGNED_BYTE, the_image_data0 );
glBegin(GL_QUADS);
glTexCoord2i(0,0); glVertex2i(0,height); //you should probably change these vertices.
glTexCoord2i(0,1); glVertex2i(0,0);
glTexCoord2i(1,1); glVertex2i(width,0);
glTexCoord2i(1,0); glVertex2i(width,height);
glEnd();
glBindTexture(GL_TEXTURE_2D, tex_obj[1]); //bind the second texture.
//then load it into the graphics hardware:
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGB, GL_UNSIGNED_BYTE, the_image_data1 );
glBegin(GL_QUADS);
glTexCoord2i(0,0); glVertex2i(0,height); //you should probably change these vertices.
glTexCoord2i(0,1); glVertex2i(0,0);
glTexCoord2i(1,1); glVertex2i(width,0);
glTexCoord2i(1,0); glVertex2i(width,height);
glEnd();
}
That is basically how it is done. But I have to warn you that my knowledge of OpenGL is a bit outdated, so there might be more efficient ways to do this (I know at least that glBegin/glEnd is deprecated in C++, replaced by VBOs).
Remember openGL is a state machine - you put it into a state, give it a command and it replays the states later.
One nice thing about textures is that you can do things outside the paint call - so if in your image processing step you generate image 1 you can load it into the card at that point.
glBindTexture(GL_TEXTURE_2D,tex_obj[1]); // select image 1 slot
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGB, GL_UNSIGNED_BYTE, the_image_data1 ); // load it into the graphics card memory
And then recall it in the paint call
glBindTexture(GL_TEXTURE_2D,tex_obj[1]); // select pre loaded image 1
glBegin(GL_QUADS); // draw it

OpenGL Nvidia Driver 259.12 texture not working

My OpenGL application which was working fine on ATI card stopped working when I put in an NVIDIA Quadro card. Texture simply don't work at all! I've reduced my program to a single display function which doesn't work:
void glutDispCallback()
{
//ALLOCATE TEXTURE
unsigned char * noise = new unsigned char [32 * 32 * 3];
memset(noise, 255, 32*32*3);
glEnable(GL_TEXTURE_2D);
GLuint textureID;
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 32, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, noise);
delete [] noise;
//DRAW
glDrawBuffer(GL_BACK);
glViewport(0, 0, 1024, 1024);
setOrthographicProjection();
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
glBindTexture(GL_TEXTURE_2D, textureID);
glColor4f(0,0,1,0);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex2f(-0.4,-0.4);
glTexCoord2f(0, 1);
glVertex2f(-0.4, 0.4);
glTexCoord2f(1, 1);
glVertex2f(0.4, 0.4);
glTexCoord2f(1,0);
glVertex2f(0.4,-0.4);
glEnd();
glutSwapBuffers();
//CLEANUP
GL_ERROR();
glDeleteTextures(1, &textureID);
}
The result is a blue quad (or whatever is specified by glColor4f()), and not a white quad which is what the texture is. I have followed the FAQ on OpenGL site. I have disabled blending in case texture was being blended out. I have disabled lighting. I have looked through glGetError() - no errors. I've also set glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); and GL_DECAL. Same result. I've also tried different polygon winding - CW and CCW.
Anyone else encounter this?
Can you try using GL_REPLACE in glTexEnvi? It could be a bug in the NV driver.
Your code is correct and does what it should.
memset(noise, 255, 32*32*3); makes the texture white, but you call glColor4f(0,0,1,0); so the final color will be (1,1,1)*(0,0,1) = (0,0,1) = blue.
What is the behavior you would like to have ?
I found the error. Somewhere else in my code I had initialized a GL_TEXTURE_3D object and had not called glDisable(GL_TEXTURE_3D);
Even though I had called glBindTexture(GL_TEXTURE_2D, textureID); it should have bound a 2D texture as the current texture and used that - as this code always worked on ATI cards. Well apparently the nVidia driver wasn't doing that - it was using that 3D texture for some reason. So adding glDisable(GL_TEXTURE_3D); fixed the problem and everything works as expected.
Thanks all who tried to help.