I have a scenario where I need to change texture parameters and load a new data. Can I generate a texture id (glGenTextures) only once and then call for a user request the following code:
glBindTexture(GL_TEXTURE_2D, texId);
glTexImage2D(GL_TEXTURE_2D, 0, img.internalformat, img.width, img.height, 0, img.format, GL_UNSIGNED_BYTE, img.buf);
Should I delete and generate a new texture id before calling subsequent glTexImage2D ?
Yes! If i understood your question correctly you can call glDeleteTextures, delete the texture and reuse the name. Here is more information:
https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glDeleteTextures.xml
Related
I was finding the relationship between glActiveTexture(...) and glBindTexture(...) and I found an awesome answer here, the very top answer(the author/user Alfonse) gives us a pseudocode for how the both functions behave, and I understood most of it. But, in it he mentions in calls such as this:
glActiveTexture(GL_TEXTURE0 + 5);
glBindTexture(GL_TEXTURE_2D, object);
glTexImage2D(GL_TEXTURE_2D, ...);
but one often binds a texture to the context just to upload some data or to modify it. It doesn’t matter at that point which texture unit you bind it to, so there’s no need to set the current texture unit. glTexImage2D doesn’t care if the current active texture is 0, 1, 40, or whatever.
So my problem is:
when generating two texture we do something like this:
glGenTextures(1, &texture1);
glBindTexture(GL_TEXTURE_2D, texture1);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenTextures(1, &texture2);
glBindTexture(GL_TEXTURE_2D, texture2);
glTextureParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//some more code
//inside the render loop
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glDrawElements(...); glSwapBuffers();
//end of render loop
Notice, in the code before the render loop, I have used two texture glBindTexture(...) without calling glActiveTexture(...). Since, the default active texture unit is: GL_TEXTURE0, does this mean the parameters set for texture1 is overwritten by texture2?
No, texture parameters (set by glTexParameter) are set for a specific texture (the one that's currently bound to the active texture unit), not for a texture unit (not for one of GL_TEXTUREi, that is).
Note that your use of glTextureParameteri incorrect. Rather than GL_TEXTURE_2D, it expects a handle of a texture, as returned by glGenTextures1. You're confusing it with glTexParameteri, which indeed can be called with GL_TEXTURE_2D.
1 As noted by #derhass, glGenTextures (unlike glCreateTextures) merely reserves the handle. A texture with this handle is created only when you pass it to glBindTexture. It doesn't matter if you use glTexParameter, but if you want to use glTextureParameteri and other functions that operate directly on texture handles, it might be important.
I'm trying to copy a slice from one OpenGL texture array to another. I'd like to do this on the GPU without resubmitting anything from the CPU if possible. (This is pretty easy to do in D3D, but I'm new to modern OpenGL.)
The closest I've been able to get, based on google and StackOverflow searches, is below. This almost works, except it only copies from the first slice in the source array (to the correct slice of the destination array). I tried using glFramebufferTexture3D so I could specify the source slice (the commented line), but that generates GL_INVALID_ENUM if I use GL_TEXTURE_2D_ARRAY for the textarget parameter, and GL_INVALID_OPERATION if I use GL_TEXTURE_3D.
GLuint fb;
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb);
glFramebufferTexture(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, src_texture_handle, 0);
//glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, src_texture_handle, 0, src_slice);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glCopyTextureSubImage3D(dst_texture_handle, 0, 0, 0, dst_slice, 0, 0, width, height);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fb);
I'm trying to copy a slice from one OpenGL texture array to another.
Then the function you should be using is glCopyImageSubData. glCopyTextureSubImage copies from the framebuffer. glCopyImageSubData copies from one texture to another.
The correct command to attach a specific layer of a 2D array texture to a framebuffer is glFrameBufferTextureLayer.
I created a framebuffer:
glBindFramebuffer(GL.GL_FRAMEBUFFER, &fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
Is reading pixels from the framebuffer via
glBindFramebuffer(GL_FRAMEBUFFER, &fbo);
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, &data);
equivalent to
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, &data);
?
It is not equivalent, reading the GL_COLOR_ATTACHMENT0 will get you data from the currently bound framebuffer, which could be completely different from the one you created.
So basically you need to guarantee you have your framebuffer bound by calling
glBindFramebuffer(GL_FRAMEBUFFER, &fbo);
before any operations using it.
GL_COLOR_ATTACHMENT0 is just an attribute of the Frame buffer object and it is not related to any specific frame buffer. By calling it with another framebuffer bound you are going to read its data which is not what you intend.
Those are completely different calls. Let me provide some background on what FBOs really are to hopefully make this all much clearer.
A framebuffer object (aka FBO) is just a collection of state. The following calls change state tracked in the currently bound FBO:
glFramebufferTexture2D()
glFramebufferRenderbuffer()
glDrawBuffers()
glReadBuffer()
(and a few other variations of similar calls)
This means that anytime you make one of these calls, the state tracked in the currently bound FBO is updated to reflect the change from the call. For example, if you call glDrawBuffers(), the list of draw buffers in the currently bound FBO is updated.
Then, anytime you bind an FBO, the state tracked in the FBO will become active again. So if you previously called glDrawBuffers() while FBO foo was bound, and later bind foo again, the draw buffer setting from the earlier call is active again.
Note that the FBO does not own the renderbuffers/textures that are attached to it. The FBO only contains information on which renderbuffer is attached to the FBO at a given attachment point. In your code, FBO foo stores the fact that renderbuffer rbo is attached to attachment point GL_COLOR_ATTACHMENT0. For example, it is completely legal to attach the same renderbuffer to multiple FBOs.
Now, more specifically on your code:
The glBindFramebuffer() calls have the wrong argument type:
glBindFramebuffer(GL.GL_FRAMEBUFFER, &fbo);
The second argument is the name (id) of the FBO, not an address. So the call is:
glBindFramebuffer(GL.GL_FRAMEBUFFER, fbo);
This call does nothing:
glReadBuffer(GL_COLOR_ATTACHMENT0);
GL_COLOR_ATTACHMENT0 is the default read buffer for FBOs. So unless you previously set it to a different value before, this call is redundant, and only sets the same value that was the default anyway. As the naming suggests, FBOs can have multiple attachments, and you would use glReadBuffer() if you had attached a renderbuffer/texture to an attachment other than ATTACHMENT0, and wanted to read from that one.
As long as you're just using a single attachment for the FBO, the only thing you really need to do is bind the FBO you want to read from:
glBindFramebuffer(GL.GL_FRAMEBUFFER, fbo);
glReadPixels(...);
glReadPixels() always reads from the currently bound FBO, so there is no way around this.
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, &data);
data over here will be read from current bounded frame buffer and this wont be equivalent to
glBindFramebuffer(GL_FRAMEBUFFER, &fbo);
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, &data); ( if the framebuffer is not bounded to respective fbo in first case)
I think that is the reason why glNamedFramebufferReadBuffer API is provided,to read data directly from the frame buffer mentioned as the first parameter.
I'm trying to use a 32F-per-channel texture attached to a frame buffer to do render to texture. I did it properly with a normal unsigned RGBA texture, but I need more resolution in every channel.
I changed texture's internal format, but doing the attachment the app threw me INVALID_ENUM error. I read that is possible to attach textures with this kind of format link link. So the error might be elsewhere.
Here are the snippets of code:
glGenTextures(1, &mTexId);
glBindTexture(GL_TEXTURE_2D, mTexId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _width, _height, 0, GL_RGBA32F , GL_UNSIGNED_BYTE, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, mBufferId);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexId, 0);
checkErrors(); // <<--- Here I check the possible errors and it's where i got the INVALID_ENUM
Can anybody helps me?
Thank you very much.
Your glTexImage2D call is invalid.
GL_RGBA32F is a valid internal format, but not a valid client side format enum. Since you are only creating the texture without copying pixel data from client memory, the format you specify there does not even matter, but it must be still valid.
Use
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _width, _height, 0, GL_RGBA, GL_FLOAT, nullptr);
instead.
I'm wrapping my head around generating mipmaps on the fly, and reading this bit with this code: http://www.g-truc.net/post-0256.html
//Create the mipmapped texture
glGenTextures(1, &ColorbufferName);
glBindTexture(ColorbufferName);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_UNSIGNED_BYTE, NULL);
glGenerateMipmap(GL_TEXTURE_2D); // /!\ Allocate the mipmaps /!\
...
//Create the framebuffer object and attach the mipmapped texture
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ColorbufferName, 0);
...
//Commands to actually draw something
render();
...
//Generate the mipmaps of ColorbufferName
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, ColorbufferName);
glGenerateMipmap(GL_TEXTURE_2D);
My questions:
Why does glGenerateMipmap needs to be called twice in the case of render to texture?
Does it have to be called like this every frame?
If I for example import a diffuse 2d texture I only need to call it once after I load it into OpenGL like this:
GLCALL(glGenTextures(1, &mTexture));
GLCALL(glBindTexture(GL_TEXTURE_2D, mTexture));
GLint format = (colorFormat == ColorFormat::COLOR_FORMAT_RGB ? GL_RGB : colorFormat == ColorFormat::COLOR_FORMAT_RGBA ? GL_RGBA : GL_RED);
GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format, textureWidth, textureHeight, 0, format, GL_UNSIGNED_BYTE, &textureData[0]));
GLCALL(glGenerateMipmap(GL_TEXTURE_2D));
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
I suspect it is because the textures are redrawn every frame and the mipmap generation uses its content in the process but I want confirmation of this.
3 - Also, if I render to my gbuffer and then immediately glBlitFramebuffer it to the default FBO, do I need to bind and glGenerateMipmap like this?
GLCALL(glBindTexture(GL_TEXTURE_2D, mGBufferTextures[GBuffer::GBUFFER_TEXTURE_DIFFUSE]));
GLCALL(glGenerateMipmap(GL_TEXTURE_2D));
GLCALL(glReadBuffer(GL_COLOR_ATTACHMENT0 + GBuffer::GBUFFER_TEXTURE_DIFFUSE));
GLCALL(glBlitFramebuffer(0, 0, mWindowWidth, mWindowHeight, 0, 0, mWindowWidth, mWindowHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR));
As explained in the post you link to, "[glGenerateMipmap] does actually two things which is maybe the only issue with it: It allocates the mipmaps memory and generate the mipmaps."
Notice that what precedes the first glGenerateMipmap call is a glTexImage2D call with a NULL data pointer. Those two calls combined will simply allocate the memory for all of the texture's levels. The data they contain at this point is garbage.
Once you have an image loaded into the texture's first level, you will have to call glGenerateMipmap a second time to actually fill the smaller levels with downsampled images.
Your guess is right, glGenerateMipmap is called every frame because the image rendered to the texture's first level changes every frame (since it is being rendered to). If you don't call the function, then the smaller mipmaps will never be modified (if you were to map such a texture, you would see your uninitialized smaller mipmap levels when far enough away).
No. Mipmaps are only needed if you intend to map the texture to triangles with a texture filtering mode that uses mipmaps. If you're only dealing with the first level of the texture, you don't need to generate the mipmaps. In fact, if you never map the texture, you can use a renderbuffer instead of a texture in your framebuffer.