I have some code in OpenGL to render a YUV image onto an OpenGL viewport. The program works without a problem when running on nvidia cards, but it generates an error when running over the Intel HD 3000, which sadly is the target machine. The point where the error is generated is marked in the code.
The shader programs are
// Vertex Shader
#version 120
void main() {
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
// fragment shader
#version 120
uniform sampler2D texY;
uniform sampler2D texU;
uniform sampler2D texV;
void main() {
vec4 color;
float y = texture2D(texY, gl_TexCoord[0].st).r;
float u = texture2D(texU, gl_TexCoord[0].st).r;
float v = texture2D(texV, gl_TexCoord[0].st).r;
color.r = (1.164 * (y - 0.0625)) + (1.596 * (v - 0.5));
color.g = (1.164 * (y - 0.0625)) - (0.391 * (u - 0.5)) - (0.813 * (v - 0.5));
color.b = (1.164 * (y - 0.0625)) + (2.018 * (u - 0.5));
color.a = 1.0;
gl_FragColor = color;
};
Then I run the program like this:
GLuint textures[3];
glGenTextures(3, textures);
glBindTexture(GL_TEXTURE_2D, textures[YTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, textures[UTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, textures[VTEX]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
GLsizei size = width * height;
GLvoid *y = yuv_buffer;
GLvoid *u = (GLubyte *)y + size;
GLvoid *v = (GLubyte *)u + (size >> 2);
glUseProgram(program_id);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE,
GL_UNSIGNED_BYTE, y);
glUniform1i(glGetUniformLocation(program_id, "texY"), 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width >> 1, height >> 1, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, u);
glUniform1i(glGetUniformLocation(program_id, "texU"), 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, textures[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width >> 1, height >> 1, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, u);
glUniform1i(glGetUniformLocation(program_id, "texV"), 2);
glBegin(GL_QUADS);
glTexCoord2f(texLeft, texTop);
glVertex2i(left, top);
glTexCoord2f(texLeft, texBottom);
glVertex2i(left, bottom);
glTexCoord2f(texRight, texBottom);
glVertex2i(right, bottom);
glTexCoord2f(texRight, texTop);
glVertex2i(right, top);
glEnd();
// glError() returns 0x506 here
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glUseProgram(0);
update since the error happens with frame buffers, I discover they are used like this:
when the program is instantiated, a frame buffer is created like this:
glViewport(0, 0, (GLint)width, (GLint)height);
glGenFramebuffers(1, &fbo_id);
glGenTextures(1, &fbo_texture);
glGenRenderbuffers(1, &rbo_id);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo_id);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, rbo_id);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glPushAttrib(GL_TEXTURE_BIT);
glBindTexture(GL_TEXTURE_2D, m_frameTexture->texture());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glPopAttrib();
The YUV image comes spliced in tiles, which are assembled by rendering in this fbo. Whenever a frame starts, this is performed:
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer(GL_BACK);
glViewport(0, 0, (GLint)width, (GLint)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (double)width, 0.0, (double)height, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo_id);
Then the code above is executed, and after all the tiles had been assembled together
glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glPushAttrib(GL_VIEWPORT_BIT | GL_TEXTURE_BIT | GL_ENABLE_BIT);
glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, (double)width, 0.0, (double)height, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glBegin(GL_QUADS);
glTexCoord2i(0, 0);
glVertex2f(renderLeft, renderTop);
glTexCoord2i(0, 1);
glVertex2f(renderLeft, renderTop + renderHeight);
glTexCoord2i(1, 1);
glVertex2f(renderLeft + renderWidth, renderTop + renderHeight);
glTexCoord2i(1, 0);
glVertex2f(renderLeft + renderWidth, renderTop);
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
What's the value of status after:
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
If the value is anything other than GL_FRAMEBUFFER_COMPLETE, OpenGL will probably choke when it tries to read from the FBO.
The glCheckFramebufferStatus docs describes other (error) values it can return, and what causes them.
Of particular interest might be:
If the currently bound framebuffer is not framebuffer complete, then
it is an error to attempt to use the framebuffer for writing or
reading. This means that rendering commands (glDrawArrays and
glDrawElements) as well as commands that read the framebuffer
(glReadPixels, glCopyTexImage2D, and glCopyTexSubImage2D) will
generate the error GL_INVALID_FRAMEBUFFER_OPERATION if called while
the framebuffer is not framebuffer complete.
(emphasis mine)
edit based on your comments:
To paraphrase the docs wrt GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
Not all framebuffer attachment points are framebuffer attachment complete.
This means that one of the following is happening:
At least one attachment point with a renderbuffer or texture attached has its attached object no longer in existence or has an attached image with a width or height of zero,
The color attachment point has a non-color-renderable image attached. Color-renderable formats include GL_RGBA4, GL_RGB5_A1, and GL_RGB565.
The depth attachment point has a non-depth-renderable image attached. GL_DEPTH_COMPONENT16 is the only depth-renderable format.
The stencil attachment point has a non-stencil-renderable image attached. GL_STENCIL_INDEX8 is the only stencil-renderable format.
We can rule out the last 2 bullets, because it doesn't appear that you're using depth or stencil attachements. That leaves two calls to examine:
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rbo_id);
From the opengl.org wiki on FBOs:
You get GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT when any of the attachments are 'incomplete'. Criteria for completeness are:
The source object for the image still exists and has the same type it was attached with.
The image has a non-zero width and height.
The layer for 3D or array textures attachments is less than the depth of the texture.
The image's format must match the attachment point's requirements, as defined above. Color-renderable formats for color attachments, etc.
The wiki says of GL_COLOR_ATTACHMENTi​:
These attachment points can only have images bound to them with
color-renderable formats. All compressed image formats are not
color-renderable, and thus cannot be attached to an FBO.
Double check that the fbo_texture and rbo_id are still valid, and that their height/width aren't 0. Finally, it could be fbo_texture's format. You've got it set to GL_RGBA8, but the docs say valid options include GL_RGBA4, GL_RGB5_A1, and GL_RGB565. I'm not sure whether or not that excludes all other formats (like your GL_RGBA8). The wiki seems to suggest that any non-compressed format should work. Try switching it to GL_RGBA4, and see if that works out.
glGetError error codes "stick" and are not automatically cleared. If something at the beginning your program generates OpenGL error AND you check for error code 1000 opengl calls later, error will be still here.
So if you want to understand what's REALLY going on, check for errors after every OpenGL call, or call glGetError in a loop, until all error codes are returned (as OpenGL documentation suggests).
I solved the problem. It was an extensions problem which made the render buffer object disappear. I basically changed this
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rbo_id);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, rbo_id);
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
for this
glBindRenderbuffer(GL_RENDERBUFFER, rbo_id);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TURE_2D, fbo_texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, rbo_id);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
and then it worked. I still wonder exactly what the problem was, but so far I am happy with the result. Special thanks to #luke who's answer helped to locate the exact point of the problem.
Exactly, what command raises error? Try to replace GL_QUADS with GL_TRIANGLE_FAN.
Related
I have a 3D scene with some triangle meshes and I am performing an offscreen rendering to draw them onto three textures:
An RGBA color texture to render my 3D scene as usual.
A single channel INTEGER texture to be used for picking my rendered items with the mouse. Each item has its own unique integer id. When the user clicks over a pixel on the screen, I can check which value was written at that position to find out which item was clicked.
The Depth texture.
I am creating a framebuffer, creating the textures, and formating them the following way:
glGenFramebuffers(1, &_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glGenTextures(1, &_sceneTex );
glGenTextures(1, &_pickingTex );
glGenTextures(1, &_depthTex );
glBindTexture(GL_TEXTURE_2D, _sceneTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _sceneTex, 0);
glBindTexture(GL_TEXTURE_2D, _pickingTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, width, height, 0, GL_RED_INTEGER, GL_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _pickingTex, 0);
glBindTexture(GL_TEXTURE_2D, _depthTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTex, 0);
GLenum drawBuffers[2] = {GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, drawBuffers);
In the fragment shader, the color and the item ID are written to the layouts:
...
uniform int itemID;
layout( location = 0 ) out vec4 fragmentColor;
layout( location = 1 ) out int pickingInfo;
...
void main()
{
//Compute the fragment color somehow and write to fragmentColor variable.
fragmentColor = vec4(color, 1.0f);
pickingInfo = itemID;
}
The scene texture is copied to the screen after every render call.
And the picking texture is supposed to be always there, available for when the user needs to select an item.
Before rendering all items on the scene, textures are cleaned this way:
float backColor[4] = {_backgroundColor.red() / 255.f,
_backgroundColor.green() / 255.f,
_backgroundColor.blue() / 255.f,
_backgroundColor.alpha() / 255.f};
glClearBufferfv(GL_COLOR, GL_COLOR_ATTACHMENT0, backColor);
int invalidID = -1;
glClearBufferiv(GL_COLOR, GL_COLOR_ATTACHMENT1, &invalidID);
For reading the id written in the clicked position (x, y), I do:
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
glReadBuffer(GL_COLOR_ATTACHMENT1);
int value = -1;
int x = static_cast<int>(screenPoint.x());
int y = height() - static_cast<int>(screenPoint.y());
glReadPixels(x, y, 1, 1, GL_RED_INTEGER, GL_INT, &value);
The problem is: everything works completely fine with my NVIDIA GeForce MX250.
But I have the weirdest behavior when I work with my Intel(R) UHD Graphics.
There is a glDrawElements call for each item rendered. When item X is rendered, its unique ID is passed to the shader which writes it onto the picking texture in the fragments the item is positioned.
Right now, I am only able to pick the first item rendered. I successfully get its ID with glReadPixels when I click over it on the screen. For anywhere else I click (even on other items), I get the "clear value" I set.
Does someone have any idea of what I might be doing wrong? Am I doing anything that is not standard?
I'm trying to load an image using FreeImage and then generate an OpenGL texture. It loads the image and generates a texture, but there's an issue with the colors.
Here's the original image:
and here's the result:
Texture loading code:
void TextureManager::LoadTexture(std::string id, std::string filePath){
Texture tex;
tex.TextureId = 0;
FIBITMAP* image = FreeImage_Load(FreeImage_GetFileType(filePath.c_str(), 0), filePath.c_str());
if (FreeImage_GetBPP(image) != 32) {
image = FreeImage_ConvertTo32Bits(image);
}
FreeImage_FlipVertical(image);
tex.Width = FreeImage_GetWidth(image);
tex.Height = FreeImage_GetHeight(image);
glGenTextures(1, &tex.TextureId);
glBindTexture(GL_TEXTURE_2D, tex.TextureId);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,tex.Width, tex.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (void*)FreeImage_GetBits(image));
AddTextureToMap(id, tex);
FreeImage_Unload(image);
}
Here's the code that's drawing it:
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, TextureManager.TextureMap[textureSelector].TextureId);
glBegin(GL_TRIANGLES);
glTexCoord2d(0, 0);
glVertex3f(-0.75, 0.75, 0);//top left
glTexCoord2d(1, 0);
glVertex3f(0.75, 0.75, 0);//top right
glTexCoord2d(0, 1);
glVertex3f(-0.75, -0.75, 0);//bottom left
glTexCoord2d(1, 0);
glVertex3f(0.75, 0.75, 0);//top right
glTexCoord2d(1, 1);
glVertex3f(0.75, -0.75, 0);//bottom right
glTexCoord2d(0, 1);
glVertex3f(-0.75, -0.75, 0);//bottom left
glEnd();
glFinish();
I'm pretty sure it's an issue with the internal format in glTexImage2D, but I'm not sure which format I'd use if that's the case. My question is: Is it the format, if so, what should I use; or is there another issue that's causing this?
Try to use this instead
The difference is because many image formats use reverse byte order, and you should use GL_BGR_EXT or GL_BGRA_EXT image formats instead GL_RGB or GL_RGBA
void TextureManager::LoadTexture(std::string id, std::string filePath){
Texture tex;
tex.TextureId = 0;
FIBITMAP* image = FreeImage_Load(FreeImage_GetFileType(filePath.c_str(), 0), filePath.c_str());
if (FreeImage_GetBPP(image) != 32) {
image = FreeImage_ConvertTo32Bits(image);
}
FreeImage_FlipVertical(image);
tex.Width = FreeImage_GetWidth(image);
tex.Height = FreeImage_GetHeight(image);
glGenTextures(1, &tex.TextureId);
glBindTexture(GL_TEXTURE_2D, tex.TextureId);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,tex.Width, tex.Height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void*)FreeImage_GetBits(image));
AddTextureToMap(id, tex);
FreeImage_Unload(image);
}
If the RGBA order is not correct, you can change the color in fragment shader like
#version 130
uniform sampler2D tex;
in vec2 texCoordsVarying;
out vec4 color;
void main() {
vec4 c2 = texture(tex, texCoordsVarying);
color = vec4(c2.g, c2.b, c2.a, c2.r);
}
I'm trying to render to two textures, rendering from the first to the second, and then from the second to the first etc. The problem is that when I'm rendering the first texture to the second, it works fine but rendering the second to the first leaves a white texture, when it's supposed to be a purple one. I'm working with Qt and OpenGL.
Both textures are bound to the same FBO, and I'm switching them through glDrawBuffer(GL_COLOR_ATTACHMENT_i)
Here is my initialization code:
void GlWidget::initializeGL() {
glewInit();
src = true;
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
//glEnable(GL_CULL_FACE);
// Generate the texture to be drawn
tex = new float[256*256*4];
for(int i = 0; i < 256*256*4; i++){
if (i % 4 == 0){
tex[i] = 0.5;
}else if (i % 4 == 1){
tex[i] = 0.3;
}else if (i % 4 == 2){
tex[i] = 0.5;
}else if (i % 4 == 3){
tex[i] = 0;
}
}
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
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_RGBA32F, 256, 256, 0, GL_RGBA, GL_FLOAT, tex);
glGenTextures(1, &targetTex);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, targetTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
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_RGBA32F, 256, 256, 0, GL_RGBA, GL_FLOAT, NULL);
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
//Attach 2D texture to this FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, targetTex, 0);
glDrawBuffer (GL_COLOR_ATTACHMENT1);
//-------------------------
glGenRenderbuffers(1, &depth_rb);
glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 256, 256);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER, depth_rb);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
shaderProgram.addShaderFromSourceFile(QGLShader::Vertex, ":/vertexShader.vsh");
shaderProgram.addShaderFromSourceFile(QGLShader::Fragment, ":/fragmentShader.fsh");
shaderProgram.link();
vertices << QVector3D(-1, -1, -2) << QVector3D(-1, 1, -2) << QVector3D(1, 1, -2) << QVector3D(1, -1, -2);
texCoords << QVector2D(0, 0) << QVector2D(0, 1) << QVector2D(1, 1) << QVector2D(1, 0);
}
And here is my drawing code:
void GlWidget::render_to_screen () {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
qglClearColor(QColor(Qt::blue));
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(src){
glActiveTexture(GL_TEXTURE0);
}else{
glActiveTexture(GL_TEXTURE1);
}
shaderProgram.enableAttributeArray("textureCoordinates");
shaderProgram.enableAttributeArray("vertex");
glDrawArrays(GL_QUADS, 0, vertices.size());
shaderProgram.disableAttributeArray("vertex");
shaderProgram.disableAttributeArray("textureCoordinates");
}
void GlWidget::paintGL()
{
qDebug() << "Updating";
glBindFramebuffer(GL_FRAMEBUFFER, fb);
if(src) {
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glActiveTexture(GL_TEXTURE0);
}else {
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glActiveTexture(GL_TEXTURE1);
}
src = !src;
qglClearColor(QColor(Qt::white));
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 mMatrix;
QMatrix4x4 vMatrix;
shaderProgram.bind();
shaderProgram.setUniformValue("mvpMatrix", pMatrix * vMatrix * mMatrix);
shaderProgram.setAttributeArray ("textureCoordinates", texCoords.constData ());
shaderProgram.enableAttributeArray("textureCoordinates");
shaderProgram.setAttributeArray("vertex", vertices.constData());
shaderProgram.enableAttributeArray("vertex");
glDrawArrays(GL_QUADS, 0, vertices.size());
shaderProgram.disableAttributeArray("vertex");
shaderProgram.disableAttributeArray("textureCoordinates");
render_to_screen ();
shaderProgram.release();
}
I'm supposed to be getting a blue screen with a purple quad in the center, instead I'm getting a white quad in the center. What am I doing wrong here?
I see several places in your code where you set the active texture. But setting the active texture means nothing as far as what texture unit the program will pull from. That's decided by the texture image unit set into the sampler uniform that's accessing the texture. You need to change that uniform, not the active texture.
Or better yet, just bind the other texture to the context. There's no need to set the active texture image unit; just bind the texture you want to sample from. Really, there's no point in any of the glActiveTexture calls you're making.
I have been trying to render a teapot to a FBO and then use the subsequent texture as a texture map. nothing seems to come up, so I was wondering what I was doing wrong. Below is the main loop:
//switch to fbo
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0,0.0,5.0,
0.0,0.0,-1.0,
0.0f,1.0f,0.0f);
glLightfv(GL_LIGHT0, GL_POSITION, lpos);
glRotatef(a,0,1,1);
glutSolidTeapot(1);
//switch to main
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glLoadIdentity();
gluLookAt(0.0,0.0,5.0,
0.0,0.0,-1.0,
0.0f,1.0f,0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, img);
//draw cube
glColor4f(1, 1, 1, 1);
glBegin(GL_TRIANGLES);
// front faces
glNormal3f(0,0,1);
// face v0-v1-v2
glTexCoord2f(1,1); glVertex3f(1,1,1);
glTexCoord2f(0,1); glVertex3f(-1,1,1);
glTexCoord2f(0,0); glVertex3f(-1,-1,1);
...draws cube
I have tried using the glFramebufferStatus and it has returned "success"
glGenTextures(1, &img);
glBindTexture(GL_TEXTURE_2D, img);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1,&fbo);
glBindFramebuffer(GL_FRAMEBUFFER,fbo);
glGenRenderbuffers(1, &depthbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 512, 512);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuffer);
glGenTextures(1, &img);
glBindTexture(GL_TEXTURE_2D, img);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, img, 0);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status==GL_FRAMEBUFFER_COMPLETE) {
printf("success\n");
}
However, all I get is the cube with no texture mapping.
There are two possible errors here:
Rendering into the FBO fails. To check if this is the case, clear the FBO with a distinct background color (e.g. pink) and see if the texture is affected (by reading it back to the CPU, for example). You should also make sure that your transformation matrices and the viewport (glViewport) are correct.
Texture mapping fails. Make sure that you've got everything set up for texture mapping and test texture mapping with a static texture first.
What about glEnable ( GL_TEXTURE_2D ) ?
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.