sending textures to trhe fragment shader

Hi all,

I have the following code example from the book “Interactive Computer Graphics A Top-Down Approach 6th Edition” that exemplifies the use of textures.
So far I was ok with the book, but I started having problems understanding how texture are sent to the fragment shader.

  1. According to OpenGL reference page: “You must use glGenTextures to generate a set of new texture names.”, and this is what the first glBindTexture( GL_TEXTURE_2D, textures[0] ) is doing.
    Why is glBindTexture( GL_TEXTURE_2D, textures[0] ) being called a second time if the name of the texture has already been generated?

  2. According to the reference: “glActiveTexture selects which texture unit subsequent texture state calls will affect. The number of texture units an implementation supports is implementation dependent, but must be at least 80.”
    What does this really means?

  3. What command should I execute and where if I want to send to the fragment shader textures[1] rather than texture[0] ?

Any help would be much appreciated!!

// Texture objects and storage for texture image
GLuint textures[2];

void init() {
// Initialize texture objects
    glGenTextures( 2, textures );

[b]    glBindTexture( GL_TEXTURE_2D, textures[0] );[/u]
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TextureSize, TextureSize, 0, GL_RGB, GL_UNSIGNED_BYTE, image );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );

    glBindTexture( GL_TEXTURE_2D, textures[1] );
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TextureSize, TextureSize, 0, GL_RGB, GL_UNSIGNED_BYTE, image2 );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );

[b]    glActiveTexture( GL_TEXTURE0 );[/b]
[b]    glBindTexture( GL_TEXTURE_2D, textures[0] );[/b]


    // Create a vertex array object
    ...
    // Create and initialize a buffer object
    ...
    // Load shaders and use the resulting shader program
    GLuint program = InitShader( "vshader71.glsl", "fshader71.glsl" );
    glUseProgram( program );
    // set up vertex arrays
    ...


    // Set the value of the fragment shader texture sampler variable
    //   ("texture") to the the appropriate texture unit. In this case,
    //   zero, for GL_TEXTURE0 which was previously set by calling
    //   glActiveTexture().
    glUniform1i( glGetUniformLocation(program, "texture"), 0 );

...
}


Glut display callback function

void display( void ) {
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    ...
    glDrawArrays( GL_TRIANGLES, 0, NumVertices );
    glutSwapBuffers();
}

Fragment shader

#version 150
in  vec4 color;
in  vec2 texCoord;
out vec3 fColor;


uniform sampler2D texture10;

void main() {
    fColor = texture2D( texture0, texCoord ).rgb;

}

In OpenGL, the textures you generate are accessed with a so called “texture offset”. GL_TEXTURE0 is the offset to the first texture, and after that, you just increment the offset for each texture. You can define offsets beforehand to not run into conflicts during execution.

1+2) Generating a texture requires:


glActiveTexture(GL_TEXTURE0 + textureOffset);
glGenTextures(1, &textureAddress);
glBindTexture(GL_TEXTURE_2D, textureAddress);

Activating the texture slot defines where the information will be written to (if I’m not mistaken), glGenTextures will create an empty texture template that can be filled, and glBindTexture will define which slot will be altered for any of the following texture calls, i.e.


glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width, texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer);

The glBindTextures is also important every time it is being used! I have no idea what the “at least 80” means, but the offset you define for the first texture should alwys be zero. In my implementation GL_TEXTURE0 is 0x84C0 (far greater than 80), and this value is only needed in glActiveTexture.

  1. You can of course define and activate multiple textures. For any running shader, I’ve been told the maximum of active textures is 32, but I’ve never reached that value.

// bind texture slot 0
glActiveTexture(GL_TEXTURE0 + textureOffset0); // should be 0
glBindTexture(GL_TEXTURE_2D, textureAddress0);
		
// bind texture slot 0
glActiveTexture(GL_TEXTURE0 + textureOffset1); // should be 1
glBindTexture(GL_TEXTURE_2D, textureAddress1);

When accessing a texture in the shader, the syntax is simply like this:


glUniform1i(shader_textureOffset0, textureOffset0);
glUniform1i(shader_textureOffset1, textureOffset1);

with the offsets being the same as when creating the texture.

Unfortunately I haven’t read that book, but considering that you have such questions some important aspects of texturing in OpenGL are missing.

  • glGenTextures() - allocates (creates) a texture ID
  • glBindTexture() - called for the first time actually creates (and selects) a texture, all subsequent calls select the texture with ID sent as a parameter
  • Prior to NV Kepler GPU, a texture required a slot in a fixed-size binding table in order to be accessed in a GPU. The number of slots in the table limited the maximal number of textures a shader can read from. In Fermi GPUs that number is 128, slightly higher than the specification requires (80). With glActivetexture() you are selecting a slot.

Not to sound like a nitpicker but to clarify this, would it not be more accurate to call this creating of the texture framework? Because glTexImageD/glTexStorageD are actually “creating” the texture or at last make it a complete texture.

glTexImage / glTexStorage is creating a texture image. The texture itself has already been created, its just an empty container at this point without any actual data.

thanks for the prompt replies!!
Know I have a better understanding how these three functions work