I'm trying to update a texture with glTexSubImage2D - c++

I started learning OpenGL recently and I've been messing with texture. I updated my texture using glTexImage2D but I've learned that it's better to use glTexSubImage2D, so I tried to change my code but i doesn't work.
Working code
void GLWidget::updateTextures(){
QImage t = img.mirrored();
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits());
glBindTexture( GL_TEXTURE_2D, 0);
}
Not working code
void GLWidget::updateTextures(){
QImage t = img.mirrored();
glBindTexture(GL_TEXTURE_2D, tex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, t.width(), t.height(), GL_RGBA, GL_UNSIGNED_BYTE, t.bits());
glBindTexture( GL_TEXTURE_2D, 0);
}
All I have is a black screen.
Thanks.
EDIT :
Here is the initialization of my texture :
void GLWidget::initializeGL(){
...
LoadGLTextures();
...
}
void GLWidget::LoadGLTextures(){
QImage t = img.mirrored();
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture( GL_TEXTURE_2D, 0);
}
img is a QImage variable containing the pixel data.
glGetError() Returns code 1281.

glTexSubImage2D updates the content of a previously allocated texture. glTexImage2D has to be called at least once to trigger the allocation:
void GLWidget::initializeGL(){
//...
QImage t = img.mirrored();
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(
GL_TEXTURE_2D,
0,
3,
t.width(),
t.height(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
t.bits()
);
glBindTexture( GL_TEXTURE_2D, 0);
// ...
}
Update with glTexSubImage2D:
void GLWidget::updateTextures(){
QImage t = img.mirrored();
glBindTexture(GL_TEXTURE_2D, tex);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
t.width(),
t.height(),
GL_RGBA,
GL_UNSIGNED_BYTE,
t.bits()
);
glBindTexture( GL_TEXTURE_2D, 0);
}
EDIT: the problem was glTexImage2D and glTexSubImage2D were called with different image sizes, generating the error GL_INVALID_VALUE (1281, 0x501) on glTexSubImage2D call.

Related

Using glGetTexImage() to aquire OpenCV Mat

Im trying to make an OpenCV Mat() using output from OpenGL's glGetTexImage(). The texture I am trying to get information from was made using the call;
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8UI, iWidth, iHeight, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, pImageData);
and so I've tried to do this using;
unsigned char* texture_bytes = (unsigned char*)malloc(sizeof(unsigned char)*texture_width*texture_height * 3);
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, texture_bytes);
Matrix = Mat(texture_height, texture_width, CV_8UC3, texture_bytes);
What I am wondering is If anyone knows what I should set the format and type of glGetTexImage() to in order for this to work. Also, what should i set the type of the Mat() to?
You can assume that the context is set correctly, and that the texture that is input is correct. I have verified this by displaying the texture on screen using OpenGL. Thanks in advance!
I have been faced with the problem of getting data from OpenGL to OpenCV recently. I didn't use glGetTexImage though.
What I did was an offscreen render in a framebuffer with a texture initialized like this:
GLuint texture;
if (glIsTexture(texture)) {
glDeleteTextures(1, &texture);
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glBindTexture(GL_TEXTURE_2D, 0);
Then after my draw calls, I get the data using glReadPixels:
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadBuffer(GL_COLOR_ATTACHMENT0);
cv::Mat texture = cv::Mat::zeros(height, width, CV_32FC3);
glReadPixels(0, 0, width, height, GL_BGR, GL_FLOAT, texture.data);
Hope it helps you.
You have a mismatch in the format parameter used for the glGetTexImage() call and the internal format of the texture:
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8UI, iWidth, iHeight, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, pImageData);
...
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR, GL_UNSIGNED_BYTE, texture_bytes);
For an integer texture, which you have in this case, you need to use a format parameter to glGetTexImage() that works for integer textures. In your example, that would be:
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGR_INTEGER, GL_UNSIGNED_BYTE, texture_bytes);
It is always a good idea to call glGetError() if you have any kind of problem getting the desired OpenGL behavior. In this case, you would have gotten a GL_INVALID_OPERATION error, based on this error condition in the spec:
format is one of the integer formats in table 8.3 and the internal format of the texture image is not integer, or format is not one of the integer formats in table 8.3 and the internal format is integer.

Can't add a texture to GL_QUAD

I have a series of rectangles and I am trying to add a texture to just one of them. Here is my current code:
glEnable (GL_TEXTURE_2D);
QBitmap image;
GLuint texture;
float pixels[] = {
42, 0, 1, 0, 42, 1,
-42 , 0, 1, 0, -42, 1,
};
image.load("texture.bmp");
GLuint m_TextureID;
glGenTextures(1, &m_TextureID);
glBindTexture ( GL_TEXTURE_2D, m_TextureID);
glTexEnvf ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_MODULATE);
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 84, 84, 0, GL_RGB, GL_FLOAT, pixels);
glEnable(GL_TEXTURE_2D);
glBindTexture ( GL_TEXTURE_2D, m_TextureID);
glBegin(GL_QUADS);
glBegin(GL_QUADS);
glVertex3f(42, 0, 42);
glVertex3f(42, 0, -42);
glVertex3f(-42, 0, -42);
glVertex3f(-42, 0, 42);
glEnd();
Where am I going wrong?
Where's your call to glTexImage2D? The data in the image variable isn't going to "magically" jump into the OpenGL texture. Oh, and you should not reload the image/texture upon every redraw.

OpenGL framebuffer resizeble texture

I'm using single color rendering in frame buffer
glGenFramebuffersEXT(1, &frontFramebufferId);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frontFramebufferId);
glGenTextures(1, &frontTextureId);
glBindTexture(GL_TEXTURE_2D, frontTextureId);
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_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, frontTextureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, frameStride, frameHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frontFramebufferId);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, frontTextureId, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
When I'm resizing window it's gives me black color.
Resizing function:
glViewport(0, 0, frameStride, frameHeight);
glBindTexture(GL_TEXTURE_2D, frontTextureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, frameStride, frameHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frontFramebufferId);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, frontTextureId, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
It's necessary to use glFramebufferTexture2DEXT function on resize event? Or what is the problem? I'm using Nvidia's Cg framework.

copy opengl main framebuffer to a fbo

I want to copy the opengl main framebuffer to a fbo, which attach two texture object. then I want transfer the color buffer and depth buffer to the two texture object. I use glbiltframebuffer,but the texure is black, what is right way? my code :
// Create the FBO
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
// Create textures
glGenTextures(1, &m_colorTexture);
glGenTextures(1, &m_depthTexture);
// color texture
glBindTexture(GL_TEXTURE_2D, m_colorTexture);
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_FLOAT, NULL);
glFramebufferTexture2(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorTexture, 0);
// depth texture
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
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_DEPTH_COMPONENT24, Width, Height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0);
GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (Status != GL_FRAMEBUFFER_COMPLETE) {
printf("error, status: 0x%x\n", Status);
return false;
}
// restore default FBO
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
//copy the main framebuffer to FBO
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
glBlitFramebuffer(0, 0, Width, Height, 0, 0, Width, Height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
GLenum error = glGetError();
`
I solved it, the code is right. Error occurred in other place, I am sorry.
But I has been nagged by the bilt speed. I copy the main framebuffer to the fbo every frame. but it seems that the frame rate down a lot. can every one give some suggestion.

How Can I Render To One Face Of An OpenGL Cubemap texture

I'm making a Cube map render target class.
I already have a 2D one that works fine. But for this cube map render target class I want to be able to render to a specific face as i wish. Maybe I want to render circles on the "X+" face but triangles in the "Y+" face.
This is what my class looks like
class CRenderTarget
{
private:
//frame buffer to render on
unsigned m_uifboHandle;
//depth stencil
unsigned m_uiDepthStencilHandle;
//the texture we will render on
unsigned m_uiTextureHandle;
public:
CCubeRenderTarget( void );
~CCubeRenderTarget( void );
void Create( unsigned uiHeightWidth = 512,
int iInternalFormat = 0x1908 ); //GL_RGBA
void Bind( void );
void UnBind( void );
}
This is how my create function looks like
void Create( unsigned uiHeightWidth, int iInternalFormat )
{
//generate our variables
glGenFramebuffers(1, &m_uifboHandle);
glGenRenderbuffers(1, &m_uiDepthStencilHandle);
glGenTextures(1, &m_uiTextureHandle);
// Initialize FBO
glBindFramebuffer( GL_FRAMEBUFFER, m_uifboHandle);
glBindTexture( GL_TEXTURE_CUBE_MAP, m_uiTextureHandle);
// Pre-allocate the correct sized cube map
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, iInternalFormat, uiHeightWidth, uiHeightWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, iInternalFormat, uiHeightWidth, uiHeightWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, iInternalFormat, uiHeightWidth, uiHeightWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, iInternalFormat, uiHeightWidth, uiHeightWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, iInternalFormat, uiHeightWidth, uiHeightWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, iInternalFormat, uiHeightWidth, uiHeightWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// Must attach texture to framebuffer. Has Stencil and depth
glBindRenderbuffer(GL_RENDERBUFFER, m_uiDepthStencilHandle);
glRenderbufferStorage(GL_RENDERBUFFER, /*GL_DEPTH_STENCIL*/GL_DEPTH24_STENCIL8, uiHeightWidth, uiHeightWidth );
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_uiDepthStencilHandle);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_uiDepthStencilHandle);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
this is what my bind function looks like
void Bind( void )
{
glBindFramebuffer( GL_FRAMEBUFFER, m_uifboHandle );
}
//this is what my unbind function looks like
void Unbind( void )
{
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
}
I done tons of research for the past week. I can't seem to find a way that i can just some how instead of binding my entire cube map just bind maybe 1 face of my cube map. which is my overall goal. I know that in DirectX you can by just grabbing the 6 faces and manually handling them but how can i manually handle each face on an openGL cube map?
Having bound the framebuffer, you need to specify what level of the texture should be targetted. It should be something like this:
glBindFramebuffer( GL_FRAMEBUFFER, m_uifboHandle );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, m_uiTextureHandle, 0);