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

时间:2015-05-17 11:29:15

标签: opengl glsl shader

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

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

这里a tutorial谈论下采样。<​​/ p>

更新

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

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));
}

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

2 个答案:

答案 0 :(得分:4)

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

mipmap处理

在OpenGL中使用低分辨率版本纹理的主要方法是mipmapping。您可以使用:

为纹理texId生成mipmap
glBindTexture(GL_TEXTURE_2D, texId);
glGenerateMipmap(GL_TEXTURE_2D);

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

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

如果现在对纹理进行采样,它将使用缩小版本,具体取决于您绘制的几何体的大小。

控制mipmap级别

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

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 4);

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

降尺度

如果由于某种原因,你真的想要缩小纹理,那么有几种选择。假设您要从texId的第4级创建新纹理,并创建了如上所示的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);

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

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);

另一种解决方案是使用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);

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

答案 1 :(得分:0)

在不知道您为什么要对纹理进行下采样的原因的情况下,这里有 是我能想到的选择:

  • 如果你需要较小的纹理,只需使用较小的纹理;您可以在离线过程中预处理较大的纹理
  • 通常硬件进行纹理过滤,你可以使用MIP映射; MIP映射级别的映像可以来自脱机过程

离线流程可以使用链接教程中的方法生成 较低的MIP地图级别,首先用高斯滤波器进行卷积以摆脱 高频然后丢掉3/4像素(对于两个方向的2:1下采样情况)。如果你知道的话 预先丢弃的像素(例如,在2:1中缩减采样) 两个方向)这些像素的卷积计算被浪费了 可以省略。

你当然可以在片段着色器中完成它,但你必须确保这一点 采样器设置为不过滤(最近邻居)。