c++openglvertex-buffermultitexturing

OpenGL binding many textures while drawing the one mesh


I would like to bind for example 80 textures on one mesh and put it in my VBO. How can I achieve this?

I've read glActiveTexture is able to do that, however it allows max around 32 textures (GPU dependant).

My VBO code:

//Generating VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d) + textureCoords.size()*sizeof(Vector2d), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size()*sizeof(Vector3d), vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d), textureCoords.size()*sizeof(Vector2d), textureCoords.data());

glGenBuffers(1, &IND);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

//Drawing VBO:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

glVertexPointer(3, GL_DOUBLE, 0, 0);
glTexCoordPointer(2, GL_DOUBLE, 0, (void*)(vertices.size()*sizeof(Vector3d)));

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void*)0);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

Solution

  • Binding many (100s of) textures

    I'm not sure of a way to bind that many separate textures at once. There are bindless textures but I don't have much experience with that extension. You could also use an array texture if many of your textures are the same size. But the standard approach to this problem is to use a texture atlas, where you pack lots of textures into the one, record where they're placed and adjust the texture coordinates to match.

    Update: you could also use many texture arrays to store texture atlases (see comments and @Ethan's answer).


    Applying multiple textures to a mesh

    How will I tell the VBO, what faces will have which texture?

    I think a more immediate problem is is how you go about applying different textures (or materials) to the same mesh. There's a few things to consider...

    1. The most common case for applying multiple textures is where each stores a different material attribute but they all use the same texture coordinates/"UVs". E.g. diffuse, normal, specular maps. I guess in the extreme case when you have 100s of different attributes is where you'd want an array texture.

    2. If each texture needs to be mapped differently you'd have a separate per-vertex texture coordinate VBO for each texture. Then you'll have to decide how the textures interact or blend as they're applied.

    3. You have completely separate materials/texture per face. Commonly there are only a few materials on the mesh. The way you render it is in separate batches, grouping by material. Bind the right texture, set the shader uniforms, draw triangle indices A to B.

    4. If nearly every face has a different material. I guess this might be the case if you're drawing a tile based game with lots of different tiles. The problem here is the number of draw calls becomes a bottleneck, so you'll have to combine different materials into the same draw call. You could do this by storing the material on vertex attributes, such as adding a vertex colour VBO. Rather than just colour, you could store a per-vertex texture ID, and if you're using a texture atlas, the region in the atlas where your texture can be found. This starts to get inefficient because you'll have the same material data stored multiple times on each vertex of your triangles. To minimize the overhead, you could store a material index per vertex, which points to a material defined in a table somewhere (either in a small uniform array, or if you need more materials, another texture). Then add texture ID and atlas region to the material in the table.

      Hopefully this last point answers your question.