从 OpenGL 计算着色器中的不同采样器读取会导致奇怪的像素化

Reading from different samplers in an OpenGL Compute Shader results in odd pixelation

使用 OpenGL 4.5 计算着色器时,以下列方式基于变量从不同纹理采样会导致奇怪的像素化。 (第一个纹理是红色,第二个纹理是蓝色)

#version 450

uniform sampler2D textures[2];

layout (binding = 0, rgba32f) uniform image2D framebuffer;

layout (local_size_x = 32, local_size_y = 32) in;

void main() {
    ivec2 pix = ivec2(gl_GlobalInvocationID.xy);
    ivec2 size = imageSize(framebuffer);
    if (pix.x >= size.x || pix.y >= size.y) {
        return;
    }
    vec2 tex_coords = vec2(pix)/size;

    int index;
    vec4 col;
    if (tex_coords.x > tex_coords.y) {
        index = 0;
    } else {
        index = 1;
    }

    /* This works */
    // for (int i=0; i<=index; i++)
    //     if (i==index)
    //         col = textureLod(textures[index], vec2(0,0), 0);

    /* These don't */
    col = textureLod(textures[index], vec2(0,0), 0);
    // col = texelFetch(textures[index], ivec2(0,0), 0);

    imageStore(framebuffer, pix, col);
}

奇怪的是,当不同纹理的样本发生时使用 while 循环进行偏移似乎可以解决问题。使用大小为 1 的工作组似乎也可以解决此问题。任何人都知道为什么会发生这种行为 and/or 有更简单的预防方法吗?

代码的完整 MRE 可以在 https://github.com/Luminic/TextureSamplingIssues

找到

您得到的结果完全符合规范。 GLSL 规范指出:

Texture-combined sampler types are opaque types, declared and behaving as described above for opaque types. When aggregated into arrays within a shader, they can only be indexed with a dynamically uniform integral expression, otherwise results are undefined.

你不能真的那样做,循环的解决方法仍然是未定义的行为(尽管它更有可能按照当前 GPU 的工作方式工作)。正确的解决方法是:

vec4 texSamples[2];
texSamples[0]=texture(textures[0],...);
texSamples[1]=texture(textures[1],...);
col = texSamples[index];

但是,您可以使用 阵列纹理 ,您可以通过任意 non-uniform 表达式 select 图层。