1
votes

To give textures to my shader I use uniform of Sampler2D type but, since I have a lot of vertex all using different textures and different shaders, I reach a bottleneck when I'm passing for each vertex is correct texture. So I had try to use a global array of used texture and pass it as layout to my shader:

layout (location = 6) in sampler2D aTexture;\n

Problem is, my shader wont compile raising the error :

0(24) : error C7514: OpenGL does not allow varying of type sampler2D
0(24) : error C7554: OpenGL requires sampler variables to be explicitly declared as uniform

Since we can't give texture to shader using layout, how you guys use textures dodging these kind of bottleneck? I'm forced to use uniform?

1
Have you looked into array textures to multiplex more textures into the same sampler slot?genpfault
After looking at array textures, it seems to be a good solution to send a lot of texture to shader using one uniform call (I'm right ?) but beside it, looking at this exemple : show me it still use uniform, so it mean I will be forced to send data to shader at each frame ?Xemuth
"since I have a lot of vertex all using different textures and different shaders", If you use different shaders, you use different draw calls anyway, and can also switch texture bindings in-between,derhass
@derhass, each frame I need to bind shader I want to use and passe the glTexture array to is uniform. I'm sorry, I begin in openGL. Maybe I have a bad vision on how everything work.Xemuth
No idea what tour issue even is. The GL does not care about "frames" at all. It is all draw calls and state changes.derhass

1 Answers

4
votes

In short: No, you can't use textures samplers as vertex input. They must be uniform.

So, there are two possible solutions, each solution is better at specifics scenrios:

  1. If each of your geometry (what you call vertices) has different shader code, then if your uber-shader (the one shader that renders them all) is pretty heavy (lots of branching and function calls) I recommend you separate them in more than one draw call. For that, you must be sure that each of your shaders procedure is very different from each other (e.g., some are opaque while others are transparent or alpha tested). But if some just have different maps (like some does normal mapping and others dont), then I recomend you recycle the code without using branching, like using a 1x1 pixel normalmap when you don't have normal mapping

  2. If each of your geometry has quite similar shader code but different textures you may use Array textures, they are not memory friendly (because all textures on the array need to have the same size) but you may draw them using one draw call:

    • on CPU side: Array textures are created like usual 2D textures (just use GL_TEXTURE_2D_ARRAY for creation and binding)
    • when loading to GPU you have to load like a 3D texture, i.e., using glTexSubImage3D. Your zoffset represents the texture index and your depth must be 1 for each element on the array
    • on the shader side you use sampler2DArray and sample it like a 3D texture, where Z is the texture index.

Here is a sample shader fragment of code:

uniform sampler2DArray myArrayTexture;
in vec2 texCoord;
...
vec4 color1 = texture(myArrayTexture, vec3(texCoord, 0)); // sampling index 0
vec4 color2 = texture(myArrayTexture, vec3(texCoord, 1)); // sampling index 1

here is how you load the array into your GPU:

glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, width, height, 1, format, type, dataAtIndex0);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 1, width, height, 1, format, type, dataAtIndex1);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 2, width, height, 1, format, type, dataAtIndex2);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 3, width, height, 1, format, type, dataAtIndex3);
...