Sign in to follow this  
Misantes

OpenGL Quick texture array question

Recommended Posts

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

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

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

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

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

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

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

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

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

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


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

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  

  • Announcements

  • Forum Statistics

    • Total Topics
      628333
    • Total Posts
      2982138
  • Similar Content

    • By DejayHextrix
      Hi, New here. 
      I need some help. My fiance and I like to play this mobile game online that goes by real time. Her and I are always working but when we have free time we like to play this game. We don't always got time throughout the day to Queue Buildings, troops, Upgrades....etc.... 
      I was told to look into DLL Injection and OpenGL/DirectX Hooking. Is this true? Is this what I need to learn? 
      How do I read the Android files, or modify the files, or get the in-game tags/variables for the game I want? 
      Any assistance on this would be most appreciated. I been everywhere and seems no one knows or is to lazy to help me out. It would be nice to have assistance for once. I don't know what I need to learn. 
      So links of topics I need to learn within the comment section would be SOOOOO.....Helpful. Anything to just get me started. 
      Thanks, 
      Dejay Hextrix 
    • By mellinoe
      Hi all,
      First time poster here, although I've been reading posts here for quite a while. This place has been invaluable for learning graphics programming -- thanks for a great resource!
      Right now, I'm working on a graphics abstraction layer for .NET which supports D3D11, Vulkan, and OpenGL at the moment. I have implemented most of my planned features already, and things are working well. Some remaining features that I am planning are Compute Shaders, and some flavor of read-write shader resources. At the moment, my shaders can just get simple read-only access to a uniform (or constant) buffer, a texture, or a sampler. Unfortunately, I'm having a tough time grasping the distinctions between all of the different kinds of read-write resources that are available. In D3D alone, there seem to be 5 or 6 different kinds of resources with similar but different characteristics. On top of that, I get the impression that some of them are more or less "obsoleted" by the newer kinds, and don't have much of a place in modern code. There seem to be a few pivots:
      The data source/destination (buffer or texture) Read-write or read-only Structured or unstructured (?) Ordered vs unordered (?) These are just my observations based on a lot of MSDN and OpenGL doc reading. For my library, I'm not interested in exposing every possibility to the user -- just trying to find a good "middle-ground" that can be represented cleanly across API's which is good enough for common scenarios.
      Can anyone give a sort of "overview" of the different options, and perhaps compare/contrast the concepts between Direct3D, OpenGL, and Vulkan? I'd also be very interested in hearing how other folks have abstracted these concepts in their libraries.
    • By aejt
      I recently started getting into graphics programming (2nd try, first try was many years ago) and I'm working on a 3d rendering engine which I hope to be able to make a 3D game with sooner or later. I have plenty of C++ experience, but not a lot when it comes to graphics, and while it's definitely going much better this time, I'm having trouble figuring out how assets are usually handled by engines.
      I'm not having trouble with handling the GPU resources, but more so with how the resources should be defined and used in the system (materials, models, etc).
      This is my plan now, I've implemented most of it except for the XML parts and factories and those are the ones I'm not sure of at all:
      I have these classes:
      For GPU resources:
      Geometry: holds and manages everything needed to render a geometry: VAO, VBO, EBO. Texture: holds and manages a texture which is loaded into the GPU. Shader: holds and manages a shader which is loaded into the GPU. For assets relying on GPU resources:
      Material: holds a shader resource, multiple texture resources, as well as uniform settings. Mesh: holds a geometry and a material. Model: holds multiple meshes, possibly in a tree structure to more easily support skinning later on? For handling GPU resources:
      ResourceCache<T>: T can be any resource loaded into the GPU. It owns these resources and only hands out handles to them on request (currently string identifiers are used when requesting handles, but all resources are stored in a vector and each handle only contains resource's index in that vector) Resource<T>: The handles given out from ResourceCache. The handles are reference counted and to get the underlying resource you simply deference like with pointers (*handle).  
      And my plan is to define everything into these XML documents to abstract away files:
      Resources.xml for ref-counted GPU resources (geometry, shaders, textures) Resources are assigned names/ids and resource files, and possibly some attributes (what vertex attributes does this geometry have? what vertex attributes does this shader expect? what uniforms does this shader use? and so on) Are reference counted using ResourceCache<T> Assets.xml for assets using the GPU resources (materials, meshes, models) Assets are not reference counted, but they hold handles to ref-counted resources. References the resources defined in Resources.xml by names/ids. The XMLs are loaded into some structure in memory which is then used for loading the resources/assets using factory classes:
      Factory classes for resources:
      For example, a texture factory could contain the texture definitions from the XML containing data about textures in the game, as well as a cache containing all loaded textures. This means it has mappings from each name/id to a file and when asked to load a texture with a name/id, it can look up its path and use a "BinaryLoader" to either load the file and create the resource directly, or asynchronously load the file's data into a queue which then can be read from later to create the resources synchronously in the GL context. These factories only return handles.
      Factory classes for assets:
      Much like for resources, these classes contain the definitions for the assets they can load. For example, with the definition the MaterialFactory will know which shader, textures and possibly uniform a certain material has, and with the help of TextureFactory and ShaderFactory, it can retrieve handles to the resources it needs (Shader + Textures), setup itself from XML data (uniform values), and return a created instance of requested material. These factories return actual instances, not handles (but the instances contain handles).
       
       
      Is this a good or commonly used approach? Is this going to bite me in the ass later on? Are there other more preferable approaches? Is this outside of the scope of a 3d renderer and should be on the engine side? I'd love to receive and kind of advice or suggestions!
      Thanks!
    • By nedondev
      I 'm learning how to create game by using opengl with c/c++ coding, so here is my fist game. In video description also have game contain in Dropbox. May be I will make it better in future.
      Thanks.
    • By Abecederia
      So I've recently started learning some GLSL and now I'm toying with a POM shader. I'm trying to optimize it and notice that it starts having issues at high texture sizes, especially with self-shadowing.
      Now I know POM is expensive either way, but would pulling the heightmap out of the normalmap alpha channel and in it's own 8bit texture make doing all those dozens of texture fetches more cheap? Or is everything in the cache aligned to 32bit anyway? I haven't implemented texture compression yet, I think that would help? But regardless, should there be a performance boost from decoupling the heightmap? I could also keep it in a lower resolution than the normalmap if that would improve performance.
      Any help is much appreciated, please keep in mind I'm somewhat of a newbie. Thanks!
  • Popular Now