PDA

View Full Version : How do you implement texture arrays?



BrianH
12-10-2016, 10:11 AM
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 (https://github.com/brianhoy/ProceduralTerrain/blob/master/ProceduralTerrain/Renderer.cpp))

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

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

2. 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++;

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

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

john_connor
12-10-2016, 11:20 AM
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

BrianH
12-10-2016, 01:39 PM
It started working, not really sure exactly why, but here is the diff (https://github.com/brianhoy/ProceduralTerrain/commit/c38ea97b7d0254fc634d71ecc15e152013565f51#diff-5dca5ed4c61b5e41084c9f5d97587007) 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.

mhagain
12-10-2016, 02:36 PM
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. https://www.opengl.org/sdk/docs/man/html/glTexStorage3D.xhtml - glTexStorage requires a sized internal format.