什么是使用 OpenGL 的纹理下采样(downscaling)?

use*_*743 3 opengl shader glsl

我没有找到任何解释如何使用 OpenGL 缩小纹理的教程。

例如,如果我有一个 1024x720 的纹理,我想按 1/4 的因子生成缩小比例,该怎么做?

这是一个讨论下采样的教程

更新

我在片段着色器中尝试了以下过滤代码:

vec4 DownSampleFrame(sampler2D uniformSampler)
{
    vec2 pixelOffset = vec2(1.0f/1024.0f, 1.0f/720.0f);

    vec3 downScaleColor = vec3(0.0f);
    {
        downScaleColor += texture(uniformSampler, vec2(TexCoords.x - 4.0f * pixelOffset.x, TexCoords.y)).xyz;
        downScaleColor += texture(uniformSampler, vec2(TexCoords.x + 4.0f * pixelOffset.x, TexCoords.y)).xyz;
        downScaleColor += texture(uniformSampler, vec2(TexCoords.x, TexCoords.y - 4.0f * pixelOffset.y)).xyz;
        downScaleColor += texture(uniformSampler, vec2(TexCoords.x, TexCoords.y + 4.0f * pixelOffset.y)).xyz;
        downScaleColor *= 0.25f;
    }
    return (vec4(downScaleColor, 1.0f));
}
Run Code Online (Sandbox Code Playgroud)

这种代码是指下采样算法吗?

Ret*_*adi 8

这里有几个方面。如果您已经拥有完整尺寸的纹理,我真的想不出一个很好的理由来创建一个缩小的纹理。如果您真的想以低于全分辨率的方式对其进行采样,则可以仅以缩小的形式使用它。

映射

在 OpenGL 中使用低分辨率版本纹理的主要方法是 mipmapping。您可以使用以下方法为纹理生成 mipmap texId

glBindTexture(GL_TEXTURE_2D, texId);
glGenerateMipmap(GL_TEXTURE_2D);
Run Code Online (Sandbox Code Playgroud)

对于要使用的 mipmap,必须相应地设置采样参数:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
Run Code Online (Sandbox Code Playgroud)

如果您现在对纹理进行采样,它将根据您正在绘制的几何图形的大小使用缩小版本。

控制 mipmap 级别

如果您只是执行上述操作,则仍将使用全分辨率,具体取决于输出中纹理的缩放比例。您可以通过限制可以使用的 mipmap 级别来防止这种情况。例如,如果要从采样中排除最低的 4 个 mipmap 级别:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 4);
Run Code Online (Sandbox Code Playgroud)

由于每个 mipmap 级别是前一个级别的线性分辨率的一半,因此将以完整纹理线性分辨率的 1/16 进行采样。

缩小规模

如果出于某种原因,您确实想要缩小的纹理,则有几种选择。假设您想从 的第 4 级创建一个新纹理texId,并且您创建了如上所示的 mipmap。您可以使用此纹理的第 4 级作为附件创建一个 FBO:

GLuint fboId = 0;
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboId);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D, texId, 4);
Run Code Online (Sandbox Code Playgroud)

然后将内容复制到新的纹理中:

GLuint smallTexId = 0;
glGenTextures(GL_TEXTURE_2D, &smallTexId);
glBindTexture(GL_TEXTURE_2D, smallTexId);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, smallWidth, smallHeight, 0);
Run Code Online (Sandbox Code Playgroud)

另一种解决方案是使用glBlitFramebuffer()

GLuint fboIds[2] = {0};
glGenFramebuffers(2, fboIds);

glBindFramebuffer(GL_READ_FRAMEBUFFER, fboIds[0]);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D, texId, 0);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboIds[1]);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D, smallTexId, 0);

glBlitFramebuffer(0, 0, width, height,
                  0, 0, smallWidth, smallHeight,
                  GL_COLOR_BUFFER_BIT, GL_LINEAR);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您不需要原始纹理上的 mipmap。即使下采样的质量可能不是很好,如果它超过 2 倍。