How do you implement texture arrays?

Hi! I’m trying to use texture arrays (OpenGL 4.4, GTX 980, Win 10) to make it so I don’t have to bind textures each frame, but the fragment shader always outputs a black pixel. Does anyone know what I’m doing wrong? It was working fine with normal textures. Here is my current code (simplified to just show necessary parts, the full code can be found here)

  1. Fragment Shader (GLSL)

	#version 440 core

	in vec2 TexCoords;
	out vec4 color;

	layout (binding=0) uniform sampler2DArray textureArray;
	layout (location=1) uniform int layer;

	void main()
	{    
	    color = vec4(texture(textureArray, vec3(TexCoords.xy, layer)));
	}

  1. Initialize Texture Array
	glGenTextures(1, &arrayTexture);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D_ARRAY, arrayTexture);

	glTexStorage3D(GL_TEXTURE_2D_ARRAY,
		5,                    //5 mipmaps
		GL_RGB,               //Internal format
		1024, 1024,           //width,height
		256                   //Number of layers
	);

	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

  1. For each unique texture, upload it using glTexSubImage3D
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D_ARRAY, arrayTexture);

	if (!texture->loaded) texture->loadImageData();
	glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
		0,                      //Mipmap number
		0, 0, currentSpotInArrayTexture, //xoffset, yoffset, zoffset
		1024, 1024, 1,          //width, height, depth
		GL_RGB,                 //format
		GL_UNSIGNED_BYTE,       //type
		texture->image); //pointer to data
	texture->freeImageData();

	texture->textureArrayLocation = currentSpotInArrayTexture;
	currentSpotInArrayTexture++;

  1. Once all the textures are uploaded, generate mipmaps
	glBindTexture(GL_TEXTURE_2D_ARRAY, arrayTexture);
	glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

	glGenerateMipmap(GL_TEXTURE_2D_ARRAY);

  1. In the render loop, for each mesh, set the shader’s layer uniform (explicitly set at location 1) to the location of that mesh’s texture, and bind it (only binding it every frame for testing purposes)
	glActiveTexture(GL_TEXTURE0);
	glUniform1i(1, textures->at(i).textureArrayLocation);
	glBindTexture(GL_TEXTURE_2D_ARRAY, arrayTexture);

did you check for GL / shader compilation / linking errors ?
https://www.opengl.org/wiki/OpenGL_Error#Testing_for_errors
https://www.opengl.org/wiki/Shader_Compilation#Example

here are 2 examples:
https://www.opengl.org/wiki/Array_Texture#Creation_and_Management
https://sites.google.com/site/john87connor/texture-object/tutorial-09-6-array-texture

the setup seems correct to me
set the internal format in glTexStorage3D(…) to GL_RGB8

there are basically 2 steps:
– building the texture
– connecting the texture to the sampler in your fragment shader

go a few steps back, create a texture array with 1 layer, 1 texel / layer, set it to green
set the texture layer in the fragment shader to index “0” (not a uniform variable)

can you access green ?

the next step: set the layer count to 3, set them to
red= layer 0
green = layer 1
blue= layer 2

change the layer index in the fragment shader to 1
can you access green ?
can you access red ?
can you access blue ?

then expand each layer to 1024 x 1024, and set each layer to the desired image data
can you access any image ?

then use a uniform int to access any layer

It started working, not really sure exactly why, but here is the diff if anyone wants to see what I changed. Thank you john_connor, I did use your method of doing 1x1 textures first then moving up to real textures.

The main thing I see from a cursory glance at the code is that you changed from an unsized to a sized internal format: GL_RGB8 instead of GL_RGB. glTexStorage3D - OpenGL 4 Reference Pages - glTexStorage requires a sized internal format.