Multi-Texture Cube

I already have a textured cube, now I want to have different textures on some of the faces, what is the best approach to achieving this?

You could just change the texture between faces. If you want to draw all faces with a single draw call, you can use a texture atlas, cube map, array texture or 3D texture.

For a single cube, it doesn’t really matter which approach you use. For multiple cubes, it depends upon the details: the number of textures used, resolution, filtering modes, the number of repetitions of each texture, and the minimum OpenGL version. Array textures are probably the most straightforward solution but require OpenGL 3.0 or the EXT_texture_array extension. A 3D texture can be used as an array texture if you don’t need mipmaps.

Okay, thanks for the info. I should’ve also mentioned that I am going to have multiple types of cubes, some will be differently textured than others. What’s the best route for achieving that? I was thinking cube maps.

You can have a cube map array (GL_TEXTURE_CUBE_MAP_ARRAY) if you want to use multiple cube maps from a single draw call. If you might use the same texture for multiple faces, or the relationship between faces and textures isn’t consistent, you’d probably be better off with a 2D array texture. Cube maps are intended for the case where you want to perform a lookup using a direction vector (e.g. environment maps). If you’re just drawing textured objects which happen to be cubes, they aren’t necessarily appropriate.

After doing some research, I figured the 2D array texture method would be best. The tutorials reference a glTexStorage3D that is not in my version of openGL (3.3), so I presume I must use glTexImage3D instead. So I have this so far :

    // Load Image
    int width, height, channels;
    unsigned char* image = SOIL_load_image("grass.png", &width, &height, &channels, SOIL_LOAD_RGB);

    // Texture
    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D_ARRAY, texture);

        1,                  //1 mipmaps
        GL_RGB,             //Internal format
        32, 32,             //width,height
        2,                  //Number of layers

    // Settings

    // Texture Image
    if (image)
        glTexImage2D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

        printf("Failed to load texture");


And of course I get no textures. I am not sure what the next step is, tutorials and docs don’t seem up to date.

That parameter should be zero. Each call to glTexImage*D supplies the data for one mipmap level. You need to at least supply the data for level zero; glGenerateMipmap will generate the rest.

Also, with that approach you need to supply the data for all of the slices (layers) in one go. If you’re loading a different image to each layer, you can pass a null pointer as the last parameter to allocate the storage without providing any data, then use glTexSubImage3D to upload individual slices.

That shouldn’t be there. 2D array textures use the *3D functions, as the underlying storage has 3 dimensions (width, height, depth). They differ from 3D textures in that filtering and wrapping are applied to the 2D slices; there’s no interpolation or wrapping in the third dimension. Also, the third texture coordinate isn’t normalised (it’s rounded to an integer to obtain a layer number).

Okay so what then is the next step, I made the changes but I’m still not there. I am just trying to get it to work using a single image right now. I am drawing using glDrawElementsInstanced btw.

I’ve implemented a texture atlas instead, and it works now. However I have read that texture arrays allow for greater performance when it comes to rendering large terrains (as I am doing), is this true?

An array texture may be able to be larger (in terms of the total number of pixels) than the largest supported 2D texture, which would mean being able to render more terrain without having to switch textures.

The other advantages of an array texture over an atlas are that you can use wrapping and you don’t have to worry about filtering causing bleeding between the tiles within an atlas.

1 Like