6
$\begingroup$

I am trying to generate mipmaps, which are based on depthbuffer values. To generate the next mipmap level, I am trying to read in the 4 pixels of the upper mipmap level per pixel. Unlike the usual mipmap generation. I am checking the depth values, and only averaging those of the 4 pixels which are in depth range. To do so, I need to read in the next larger mipmap level than the current one I am suppose to render to. I know, that reading from the same texture than rendering to is not allowed. but I found this post on stackoverflow: https://stackoverflow.com/questions/44349792/is-it-possible-to-render-to-textures-mipmap-level-1-while-sampling-from-level-0 Here in the comments one person is talking about "texture mipmap range specifiers". Does that mean, that I don't need to use two framebuffers (one for reading and one for writing and for each mipmap level switching between these both framebuffers?) with two textures to do what I am trying? If so. How can I specify which mipmap should be read from the shader? I am using

  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, mipmaplevelToRenderTo);

command to render into a specific mipmap level. And I only want to read pixels from level "mipmaplevelToRenderTo - 1"

$\endgroup$
1
  • $\begingroup$ If I correctly understand the wiki article referenced in the comments to the linked question, setting the filtering mode to one that doesn't use mipmaps should be sufficient. $\endgroup$
    – lisyarus
    Commented Dec 21, 2021 at 20:01

1 Answer 1

4
$\begingroup$

This is possible with only a single framebuffer and a single texture (with mips).

To select the mip level to render to, you can use glFramebufferTexture2D, as in the example you gave. Be sure to also set glViewport to the width/height of the mip you are rendering to.

glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, mipmaplevelToRenderTo);
glViewport(0, 0, mipWidth, mipHeight);

Then, to limit the mip level that you're sampling from, the safest1 way is to use the GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL texture parameters.

glBindTexture(GL_TEXTURE_2D, textureID);
int mipToSampleFrom = mipmaplevelToRenderTo - 1;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, mipToSampleFrom);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipToSampleFrom);

This will allow you to use texture(sampler, uv) (or similar) in your shader as normal, and it will only sample from the one mip level you specified. Note that GL_TEXTURE_BASE_LEVEL also changes the meaning of GLSL functions like textureSize(), which takes a lod parameter: if you've modified GL_TEXTURE_BASE_LEVEL, then lod will be relative to the base level, meaning that textureSize(sampler, 0) will conveniently return the size of the currently configured base mip level.

To reset, just set those params to their default OpenGL values:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1000);

1 Whenever a texture is sampled from while also being rendered to, you can run the risk of hitting undefined behavior. The OpenGL spec is fairly conservative about what can constitute undefined behavior, even if the shader wouldn't actually ever sample from the same texel that it's writing to, so one way to avoid the issue is to make it impossible by using the GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL params. See the spec for details: https://registry.khronos.org/OpenGL/specs/es/3.0/es_spec_3.0.pdf#page=224

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.