Sign in to follow this  
Misantes

OpenGL Quick texture array question

Recommended Posts

Misantes    2092

Generally, my method for creating/using texture arrays works fine. However, I've noticed that the use of arrays seemingly negates my ability to use any textures that are not part of the array, even if loaded separately. Specifically, I'm trying to access my depth texture for a shadow map. If I bind the diffuse/normal/specular maps individually, and not part of the array, things render as expected. If I bind using an array, the shadow map is not accessible. 

 

I'm wondering if binding the array overrides the non-arrayed shadow map or if I should be calling things differently.

 

I'm likely making a small mistake here, but is there a way to use both in a shader? The opengl docs don't mention this scenario.

 

pseudo-code example:

//binding
//shadow map
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glUniform1i(shadowMapID, 0);

//diffuse image
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearray);
glUniform1i(LayerNumID1, imageIndex.x);

//normal map
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearray);
glUniform1i(LayerNumID2, imageIndex.y);

//specular map
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearray);
glUniform1i(LayerNumID3, imageIndex.z);

in fragment shader:

uniform sampler2DShadow shadowMap;
uniform sampler2DArray DiffuseTextureSampler;
uniform sampler2DArray NormalTextureSampler;
uniform sampler2DArray SpecularTextureSampler;
uniform int layer_index1;
uniform int layer_index2;
uniform int layer_index3;

Share this post


Link to post
Share on other sites
NumberXaero    2624

The general idea is certainly possible, buts its hard to tell from pseudo-code, youre binding "texturearray" to three different texture units, and using three different samplers in the shader? plus passing a 0 to the shader for the shadow uniform, not sure if you are actually doing that or this is just a mistake in the example code.

But in general you should be able to set active texture, bind, set active texture + 1, bind, etc.

Share this post


Link to post
Share on other sites
Misantes    2092

Ugh, have I been wrong about that all along? I was under the impression that that value was for the texture unit. I.e. if it's GL_TEXTURE0, then you bind 0, if it's GL_TEXTURE1, then you bind 1, unless it's an array, then you bind the index location \. 

I've looked at the opengl docs multiple times over this, but they seem...less than helpful in this instance. Though, perhaps I'm just not following the terminology correctly:

v0, v1, v2, v3
For the scalar commands, specifies the new values to be used for the specified uniform variable.

To your other comment. I've always just used the 3 samplers (my shaders are relatively simple) for diffuse/specular/normals. I gather from your comments it's possible to just bind one sampler array, and index it in the shader similarly as an array. I'll incorporate that. It definitely seems ideal.

Edited by Misantes

Share this post


Link to post
Share on other sites
jmakitalo    668

As NumberXaero suggested, you bind the array to one location, say 1:

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearray);
glUniform1i(location, 1);

In shaders you use

uniform sampler2DArray arrayTex;

/* ... */

void main()
{
 float index = 0.0;
 vec4 color = texture(arrayTex, vec3(texCoord.xy, index));
 /* ... */
}

The third component of the second argument to texture is the array index. Arrays are great for overcoming texture image unit limitations, although the layers will need to have the same properties

Share this post


Link to post
Share on other sites
Misantes    2092

Ok, I get that, and other than using multiple id's in the shader, I'm using them correctly, I believe. But, to the other question, when binding a single texture, the second value for the glUniform1i(), what actually goes there, if not the texture number (again, say 0 for GL_TEXTURE0)?

Share this post


Link to post
Share on other sites
jmakitalo    668

Ok, I get that, and other than using multiple id's in the shader, I'm using them correctly, I believe. But, to the other question, when binding a single texture, the second value for the glUniform1i(), what actually goes there, if not the texture number (again, say 0 for GL_TEXTURE0)?

 

The value for glUniform1i() maps to the active texture unit, i.e., glUniform1i(textureUniformLoc, 4); corresponds to glActiveTexture(GL_TEXTURE4); This works the same for all types of textures. Only difference is how you access the texture data in the shaders. I usually set the uniform once during initialization when setting up the shaders.

Share this post


Link to post
Share on other sites
NumberXaero    2624

If this is what youre doing, as jmakitalo posted

 

As NumberXaero suggested, you bind the array to one location, say 1:

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearray);
glUniform1i(location, 1);

In shaders you use

uniform sampler2DArray arrayTex;

/* ... */

void main()
{
 float index = 0.0;
 vec4 color = texture(arrayTex, vec3(texCoord.xy, index));
 /* ... */
}

The third component of the second argument to texture is the array index. Arrays are great for overcoming texture image unit limitations, although the layers will need to have the same properties

 

 

then thats correct. You generate an id and it goes to bind, you set an activate texture unit before bind, and pass that active index to the sampler location. Assuming

"texturearray" isnt a variable being changed between the bind calls, and assuming you are using three arrays containing the textures grouped by use

//binding
//shadow map
glActiveTexture(GL_TEXTURE0);                  // unit 0
glBindTexture(GL_TEXTURE_2D, depthTexture);    // GenTexture id
glUniform1i(shadowMapSamplerUniformLocation, 0);     // sampler (index)

//diffuse image
glActiveTexture(GL_TEXTURE1);                               // unit 1
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearrayDiffuse);    // GenTexture id, bound to 1
glUniform1i(diffuseArraySamplerUniformLocation, 1);        // sampler (index)
glUniform1i(LayerNumID1, imageIndex.x);       // the diffuse you want to access I take it?

//normal image
glActiveTexture(GL_TEXTURE2);                               // unit 2
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearrayNormal);    // GenTexture id, bound to 2
glUniform1i(normalArraySamplerUniformLocation, 2);        // sampler (index)
glUniform1i(LayerNumID2, imageIndex.y);       // the normal you want to access I take it?

// spec......

if "texturearray" is a big list of diffuse/normal/spec textures altogether then the shader would have a single, uniform sampler2DArray, rather then 3, and setup

glActiveTexture(GL_TEXTURE1); // unit 1
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearray); // GenTexture id, bound to 1, the only array
glUniform1i(arraySamplerUniformLocation, 1); // sampler (index)
glUniform1i(LayerNumID1, imageIndex.x); // the diffuse you want to access?
glUniform1i(LayerNumID2, imageIndex.y); // the normal you want to access?
glUniform1i(LayerNumID3, imageIndex.z); // the spec you want to access?

Short version, the sampler uniform needs the texture unit index.

Share this post


Link to post
Share on other sites
haegarr    7372

In other words:

 

One has to make a distinction between the texture object name (the number generated by glGenTexture, and used as 2nd parameter to glBindTexture, for example), and the texture unit address (the trailing number at the symbolic constant when calling glActiveTexture or the 2nd parameter of glUniform1i in your case). The former names the texture, the latter the texture unit.

 

A texture unit is a part of the GPU hardware. From the outside, you bind a texture object to the texture unit, so saying "when this texture unit is accessed, then the returned data should come from this texture object"; that is done in 2 steps, first by glActiveTexture to specify the texture unit, then by glBindTexture to specify the texture object. Then, within your shader script, you have a sampler. The sampler works on a texture unit. So you need to call glUniform to specify which texture unit should be used by the specific sampler.

 

In the end you have an indirect access of the sampler onto the texture data, with the texture unit in-between:

          texture object --bound_to--> texture unit <--read_from-- sampler

Share this post


Link to post
Share on other sites
cgrant    1826

The second number to the call to glUniform1i is the texture unit the texture for the sampler is bound to. You cannot bind individual layers of an array texture to an sampler( just don't make any sense ). Also, I would recommend downloading the GL specification for the version you are using for reference. Its very handy to have whenever you need a little clarification.

Share this post


Link to post
Share on other sites
Misantes    2092

Hm, I think due to a misunderstanding and posting pseudo-code, we're becoming a little off-base here. I think there was some initial confusion between us about binding 0 to GL_TEXTURE0, which I think has been cleared up. And, while I wasn't aware you could use a single sampler for the array, that seems relatively straightforward.

 

However, the initial problem still exists where I'm unable to use the array with the depth texture.

 

For clarity here are the bind calls and shader (after adjustments for the single sampler, thank you)

glActiveTexture(GL_TEXTURE0); 
glBindTexture(GL_TEXTURE_2D, depthTexture); 
glUniform1i(ShadowMapID, 0); 

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D_ARRAY, texturearray);
glUniform1i(ArrayID, 1);
glUniform1i(LayerNumID1, imageIndex.x);//array index numbers
glUniform1i(LayerNumID2, imageIndex.y);
glUniform1i(LayerNumID3, imageIndex.z);

fragment shader:

uniform sampler2DShadow shadowMap; //corresponds to ShadowMapID 
uniform sampler2DArray ArraySampler; //ArrayID
uniform int layer_index1;
uniform int layer_index2;
uniform int layer_index3;
void main()
{
    vec3 MaterialDiffuseColor = texture( ArraySampler,vec3(UV, layer_index1) ).rgb;
    visibility -= 0.3*(1.0-texture( shadowMap, vec3(ShadowCoord.xy + poissonDisk[index]/700.0,  (ShadowCoord.z-bias)/ShadowCoord.w) ));

Which doesn't work. The shadow map doesn't seem to be accessible. Again, the texture array on its own is working fine, and the shadow map, when bound with individual textures, works fine as well. But, when I try to use the shadow map, while using an array for the other textures, things aren't rendering properly. To be clear though, there are no errors reported, but the shader is clearly not reading the shadowmap correctly.

 

If this code looks relatively fine, then my issue is likely elsewhere.

Edited by Misantes

Share this post


Link to post
Share on other sites
jmakitalo    668


Which doesn't work. The shadow map doesn't seem to be accessible. Again, the texture array on its own is working fine, and the shadow map, when bound with individual textures, works fine as well. But, when I try to use the shadow map, while using an array for the other textures, things aren't rendering properly. To be clear though, there are no errors reported, but the shader is clearly not reading the shadowmap correctly.
 
If this code looks relatively fine, then my issue is likely elsewhere.

 

The code looks fine to me as far as I can interpret it without further information. Are you sure that your uniform ids are properly resolved? Are you binding the shaders before calling glUniform etc?

Share this post


Link to post
Share on other sites
Misantes    2092

Are you setting tex parameter GL_TEXTURE_COMPARE_MODE and GL_TEXTURE_COMPARE_FUNC for the shadow map texture when using it with sampler2DShadow?

What GL context and GLSL version are you using?

I'm calling:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);

when creating the depth texture, but only then.

 

 


The code looks fine to me as far as I can interpret it without further information. Are you sure that your uniform ids are properly resolved? Are you binding the shaders before calling glUniform etc?

Yeah, I've triple checked the ids now, and am binding the shaders right before binding the uniforms.

 

Alright, so I think I must be goofing elsewhere. Thanks for the advice and effort everyone. If I come across more information on where I'm going wrong, I'll make a new thread.

 

Edit*

Yup. In adapting the changes, I made a mistake with an inherited class, and hadn't updated the virtual function that bound the layer indexes to the shader. >,<

Stupid.

 

Anyhow, I still appreciate the help from everyone. Looks like I was still going about things the wrong way (multiple samplers, not binding the sampler to the texture unit, etc), so I definitely learned a lot.

Cheers :)

Edited by Misantes

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By cebugdev
      hi all,

      i am trying to build an OpenGL 2D GUI system, (yeah yeah, i know i should not be re inventing the wheel, but this is for educational and some other purpose only),
      i have built GUI system before using 2D systems such as that of HTML/JS canvas, but in 2D system, i can directly match a mouse coordinates to the actual graphic coordinates with additional computation for screen size/ratio/scale ofcourse.
      now i want to port it to OpenGL, i know that to render a 2D object in OpenGL we specify coordiantes in Clip space or use the orthographic projection, now heres what i need help about.
      1. what is the right way of rendering the GUI? is it thru drawing in clip space or switching to ortho projection?
      2. from screen coordinates (top left is 0,0 nd bottom right is width height), how can i map the mouse coordinates to OpenGL 2D so that mouse events such as button click works? In consideration ofcourse to the current screen/size dimension.
      3. when let say if the screen size/dimension is different, how to handle this? in my previous javascript 2D engine using canvas, i just have my working coordinates and then just perform the bitblk or copying my working canvas to screen canvas and scale the mouse coordinates from there, in OpenGL how to work on a multiple screen sizes (more like an OpenGL ES question).
      lastly, if you guys know any books, resources, links or tutorials that handle or discuss this, i found one with marekknows opengl game engine website but its not free,
      Just let me know. Did not have any luck finding resource in google for writing our own OpenGL GUI framework.
      IF there are no any available online, just let me know, what things do i need to look into for OpenGL and i will study them one by one to make it work.
      thank you, and looking forward to positive replies.
    • By fllwr0491
      I have a few beginner questions about tesselation that I really have no clue.
      The opengl wiki doesn't seem to talk anything about the details.
       
      What is the relationship between TCS layout out and TES layout in?
      How does the tesselator know how control points are organized?
          e.g. If TES input requests triangles, but TCS can output N vertices.
             What happens in this case?
      In this article,
      http://www.informit.com/articles/article.aspx?p=2120983
      the isoline example TCS out=4, but TES in=isoline.
      And gl_TessCoord is only a single one.
      So which ones are the control points?
      How are tesselator building primitives?
    • By Orella
      I've been developing a 2D Engine using SFML + ImGui.
      Here you can see an image
      The editor is rendered using ImGui and the scene window is a sf::RenderTexture where I draw the GameObjects and then is converted to ImGui::Image to render it in the editor.
      Now I need to create a 3D Engine during this year in my Bachelor Degree but using SDL2 + ImGui and I want to recreate what I did with the 2D Engine. 
      I've managed to render the editor like I did in the 2D Engine using this example that comes with ImGui. 
      3D Editor preview
      But I don't know how to create an equivalent of sf::RenderTexture in SDL2, so I can draw the 3D scene there and convert it to ImGui::Image to show it in the editor.
      If you can provide code will be better. And if you want me to provide any specific code tell me.
      Thanks!
    • By Picpenguin
      Hi
      I'm new to learning OpenGL and still learning C. I'm using SDL2, glew, OpenGL 3.3, linmath and stb_image.
      I started following through learnopengl.com and got through it until I had to load models. The problem is, it uses Assimp for loading models. Assimp is C++ and uses things I don't want in my program (boost for example) and C support doesn't seem that good.
      Things like glVertexAttribPointer and shaders are still confusing to me, but I have to start somewhere right?
      I can't seem to find any good loading/rendering tutorials or source code that is simple to use and easy to understand.
      I have tried this for over a week by myself, searching for solutions but so far no luck. With tinyobjloader-c and project that uses it, FantasyGolfSimulator, I was able to actually load the model with plain color (always the same color no matter what I do) on screen and move it around, but cannot figure out how to use textures or use its multiple textures with it.
      I don't ask much: I just want to load models with textures in them, maybe have lights affect them (directional spotlight etc). Also, some models have multiple parts and multiple textures in them, how can I handle those?
      Are there solutions anywhere?
      Thank you for your time. Sorry if this is a bit confusing, English isn't my native language
    • By dpadam450
      FINALLY, upgrading my engine to openGL 4. I was having some trouble so I started with a stripped down application and was wondering if VAO's are required, because I have a sample working, but if I remove the VAO then it doesn't seem to like drawing my triangle.
  • Popular Now