i personally favour array textures, there is only 1 obvious “problem”: constant resolution for all layers
1 way to get around that problem is re-texturing of all models you use, and make them fit into (let’s say) 1024 x 1024 RGBA
(that would be ~4MB per texture layer)
with that appproach, you can even switch textures within 1 mesh (instance):
–> stream a “int mapKd” as vertex attribute to the vertex shader, pass it to the fragment shader and access your array texture with that index
i draw all of my meshes as GL_TRIANGLES, the vertices look like this:
struct Vertex {
vec3 Position;
vec2 TexCoord;
vec3 Normal;
int MaterialIndex;
};
i’m using “Material” structs in my fragmentshader, all materials (put into a buffer) are bound to an uniform block
materials look like that: (GLSL)
struct Material {
vec4 Ka, Kd, Ks;
float Ns;
float d;
int map_Kd;
};
layout (std140, binding = 1) uniform MaterialBlock
{
Material Materials[MAX_MATERIALS];
};
uniform sampler2DArray textureKd;
void main()
{
// ...
int map_Kd = Materials[vs_out.materialindex].map_Kd;
vec3 Kd = Materials[vs_out.materialindex].Kd.rgb * texture(textureKd, vec3(vs_out.texcoord, map_Kd)).rgb;
}
the streamed vertex attribute “int MaterialIndex” is used to access the correct material
that material itself has then the texture index “int map_Kd” which is use to access the correct texture (diffuse)
that way i can enable / disable textures within 1 mesh, just by avoiding a uniform “switch ON/OFF” variable
if a certain face doesnt need textures at all, the texture index will be 0 and the first layer of the tarray texture is completely white
if you want to use different textures for the same instanced rendered mesh, stream another instanced “int override_mapKd” to the vertex shader and pass it instead of the “int MaterialIndex”
RESTRICTIONS:
– of course all textures have the same resolution
– maximum number of materials per drawcall is limited (GL_MAX_UNIFORM_BLOCK_SIZE bytes per block)
(but i think openGl requires at least 16KB, that is ~250 different materials per drawcall)
(my [old] NVIDIA GT 640 has 65536 bytes, that means about 1000 different materials / drawcall)