下采样和上采样纹理偏移,OpenGL GLSL

Downsample and upsample texture offsets, OpenGL GLSL

假设我想将纹素纹理从 4x4 下采样到 2x2,做一些花哨的东西,然后再次从 2x2 上采样到 4x4。如何计算正确的相邻纹素偏移量?我不能使用双线性过滤或最近过滤。我需要为每个片段执行选择 4 个样本,并在下采样之前选择最大的一个。上采样通道也是如此,即我需要为每个片段执行选择 4 个样本。

我是否正确计算了相邻偏移量(我使用的是全屏四边形)?

//Downsample: 1.0 / 2.0, Upsample: 1.0 / 4.0.
vec2 texelSize = vec2(1.0 / textureWidth, 1.0 / textureHeight);

const vec2 DOWNSAMPLE_OFFSETS[4] = vec2[]
(
    vec2(-0.5, -0.5) * texelSize,
    vec2(-0.5, 0.5) * texelSize,
    vec2(0.5, -0.5) * texelSize,
    vec2(0.5, 0.5) * texelSize
);

const vec2 UPSAMPLE_OFFSETS[4] = vec2[]
(
    vec2(-1.0, -1.0) * texelSize,
    vec2(-1.0, 1.0) * texelSize,
    vec2(1.0, -1.0) * texelSize,
    vec2(1.0, 1.0) * texelSize
);

//Fragment shader.
#version 400 core

uniform sampler2D mainTexture;
in vec2 texCoord;
out vec4 fragColor;

void main(void) 
{
    #if defined(DOWNSAMPLE)
    vec2 uv0 = texCoord + DOWNSAMPLE_OFFSETS[0];
    vec2 uv1 = texCoord + DOWNSAMPLE_OFFSETS[1];
    vec2 uv2 = texCoord + DOWNSAMPLE_OFFSETS[2];
    vec2 uv3 = texCoord + DOWNSAMPLE_OFFSETS[3];
    #else
    vec2 uv0 = texCoord + UPSAMPLE_OFFSETS[0];
    vec2 uv1 = texCoord + UPSAMPLE_OFFSETS[1];
    vec2 uv2 = texCoord + UPSAMPLE_OFFSETS[2];
    vec2 uv3 = texCoord + UPSAMPLE_OFFSETS[3];
    #endif

    float val0 = texture(mainTexture, uv0).r;
    float val1 = texture(mainTexture, uv1).r;
    float val2 = texture(mainTexture, uv2).r;
    float val3 = texture(mainTexture, uv3).r;

    //Do some stuff...

    fragColor = ...;
}

偏移量看起来是正确的,假设 texelSize 在这两种情况下都是 渲染目标 的纹理元素大小。也就是说,下采样通道的大小是上采样通道的两倍。在上采样的情况下,您并没有准确地击中源纹素中心,而是足够接近以至于最近的邻居过滤将它们捕捉到预期的结果。

一个更有效的选择是使用 textureGather instruction, specified in the ARB_texture_gather 扩展。当用于对纹理进行采样时,它 returns 相同的四​​个纹素,将用于过滤。它仅 returns 每个纹素的单个组件来生成 vec4,但鉴于您只关心红色组件,如果扩展可用,这是一个理想的解决方案。下采样和上采样的代码将相同:

#define GATHER_RED_COMPONENT 0
vec4 vals = textureGather(mainTexture, texcoord, GATHER_RED_COMPONENT);

// Output the maximum value
fragColor = max(max(vals.x, vals.y), max(vals.z, vals.w));