Search code examples
goopenglshadercompute-shader

How can I properly create an array texture in OpenGL (Go)?


I have a total of two textures, the first is used as a framebuffer to work with inside a computeshader, which is later blitted using BlitFramebuffer(...). The second is supposed to be an OpenGL array texture, which is used to look up textures and copy them onto the framebuffer. It's created in the following way:

var texarray uint32
gl.GenTextures(1, &texarray)
gl.ActiveTexture(gl.TEXTURE0 + 1)
gl.BindTexture(gl.TEXTURE_2D_ARRAY, texarray)

gl.TexParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR)

gl.TexImage3D(
    gl.TEXTURE_2D_ARRAY,
    0,
    gl.RGBA8,
    16,
    16,
    22*48,
    0,
    gl.RGBA, gl.UNSIGNED_BYTE,
    gl.Ptr(sheet.Pix))
gl.BindImageTexture(1, texarray, 0, false, 0, gl.READ_ONLY, gl.RGBA8)

sheet.Pix is just the pixel array of an image loaded as a *image.NRGBA The compute-shader looks like this:

#version 430
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img;

layout(binding = 1) uniform sampler2DArray texAtlas;

void main() {
    ivec2 iCoords = ivec2(gl_GlobalInvocationID.xy);
    vec4 c = texture(texAtlas, vec3(iCoords.x%16, iCoords.y%16, 7));
    imageStore(img, iCoords, c);
}

When i run the program however, the result is just a window filled with the same color: window screenshot So my question is: What did I do wrong during the shader creation and what needs to be corrected?

For any open code questions, here's the corresponding repo


Solution

  • vec4 c = texture(texAtlas, vec3(iCoords.x%16, iCoords.y%16, 7))
    

    That can't work. texture samples the texture at normalized coordinates, so the texture is in [0,1] (in the st domain, the third dimension is the layer and is correct here), coordinates outside of that ar handled via the GL_WRAP_... modes you specified (repeat, clamp to edge, clamp to border). Since int % 16 is always an integer, and even with repetition only the fractional part of the coordinate will matter, you are basically sampling the same texel over and over again.

    If you need the full texture sampling (texture filtering, sRGB conversions etc.), you have to use the normalized coordinates instead. But if you only want to access individual texel data, you can use texelFetch and keep the integer data instead.

    Note, since you set the texture filter to GL_LINEAR, you seem to want filtering, however, your coordinates appear as if you would want at to access the texel centers, so if you're going the texture route , thenvec3(vec2(iCoords.xy)/vec2(16) + vec2(1.0/32.0) , layer) would be the proper normalization to reach the texel centers (together with GL_REPEAT), but then, the GL_LINEAR filtering would yield identical results to GL_NEAREST.