Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 8 of 8

Thread: How to load textures into the fragment shader?

  1. #1
    Junior Member Newbie
    Join Date
    Jul 2017
    Posts
    3

    How to load textures into the fragment shader?

    I'm trying to blend textures together in the fragment shader. I know how to do it but what I seem to be struggling on is getting these textures from my header file to the fragment shader. Here's how my shader is set up:
    Code :
    out vec3 color;
     
    in vec2 uv;
     
    uniform sampler2D grasstexture;
    uniform sampler2D rocktexture;
     
    void main() {
     
        vec4 grass = texture(grasstexture, uv);
        vec4 rock = texture(rocktexture, uv);
    And then I do my blending down below. I'm using C++ for this so my images are loaded in a header file (called mesh.h). In mesh.h here's how I set up my images:
    Code :
     OpenGP::EigenImage<vec3> image;
            OpenGP::imread("grass.tga", image);
     
            glGenTextures(1, &_diffuse_tex);
            glBindTexture(GL_TEXTURE_2D, _diffuse_tex);
     
            check_error_gl();
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            check_error_gl();
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F,
                         image.cols(), image.rows(), 0,
                         GL_RGB, GL_FLOAT, image.data());
    check_error_gl();
    And that loads the image from the header file. Now I'm trying to put multiple images into the fragment shader and use them there. One thing I tried doing is adding the following:
    Code :
    tex_id = glGetUniformLocation(_pid, "grasstexture");
    glUniform1i(tex_id, 0);
    The problem is when I try to load multiple textures, it doesn't seem to work. I'm not sure if I have to copy that entire thing for each texture I load or if I just need to say
    Code :
    OpenGP::imread("rock.tga", image);
    for the rock texture. So how do I do this?

  2. #2
    Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    429
    Use a different texture unit for each of your textures you want to use at the same time. Shaders should have their sampler uniforms defined with the texture unit to use.
    Since it seems hard to find any tutorials about it, I'll try to give you some hints.

    Code :
    // tells the shader that we will use the first texture unit for the first texture
    // and the second texture unit for the second texture
    shader.setUniform("firstSampler", 0);
    shader.setUniform("secondSampler", 1);
     
    [...]
     
    // set the first texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE2D, textureOne);
     
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE2D, textureTwo);
     
    // now render

    Hope that helps.

  3. #3
    Member Regular Contributor
    Join Date
    May 2016
    Posts
    445
    Quote Originally Posted by Silence View Post
    Code :
    // tells the shader that we will use the first texture unit for the first texture
    // and the second texture unit for the second texture
    shader.setUniform("firstSampler", 0);
    shader.setUniform("secondSampler", 1);
     
    [...]
     
    // set the first texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE2D, textureOne);
     
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE2D, textureTwo);
     
    // now render

    its usually a good idea to "reset" the selector after the textures are bound, so that next time you know that the "selector" is at GL_TEXTURE0, just in case ..
    Code :
    // set the first texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE2D, textureOne);
     
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE2D, textureTwo);
     
    glActiveTexture(GL_TEXTURE0);
     
    /* render here */

    or avoid it completely by using the newer (GL 4.5) function:
    void glBindTextureUnit(GLuint unit, GLuint texture);

  4. #4
    Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    429
    Quote Originally Posted by john_connor View Post
    its usually a good idea to "reset" the selector after the textures are bound, so that next time you know that the "selector" is at GL_TEXTURE0, just in case
    I guess this can depend on your rendering pipeline. It is common, to my opinion, to have a strong link between textures and units. Meaning that a texture will generally be used for one unit, but not another one. For example, the depth texture used for shadowing will be used for texture unit 3. And this will break things to use this unit for doing the 'basic' texture-mapping, or to use the depth texture on the texture unit 0, which might be used for the 'basic' texture-mapping.
    So, when you bind a texture, you'll most probably set it to the unit in which it will make sense for the shader to use it. Which lead to what you wrote after:

    Quote Originally Posted by john_connor View Post
    or avoid it completely by using the newer (GL 4.5) function:
    void glBindTextureUnit(GLuint unit, GLuint texture);
    Interesting. ARB_direct_state_access is really something I should have a look into. Hoping that all my hardware/drivers support it.

  5. #5
    Junior Member Newbie
    Join Date
    Jul 2017
    Posts
    3
    Quote Originally Posted by Silence View Post
    Use a different texture unit for each of your textures you want to use at the same time. Shaders should have their sampler uniforms defined with the texture unit to use.
    Since it seems hard to find any tutorials about it, I'll try to give you some hints.

    Code :
    // tells the shader that we will use the first texture unit for the first texture
    // and the second texture unit for the second texture
    shader.setUniform("firstSampler", 0);
    shader.setUniform("secondSampler", 1);
     
    [...]
     
    // set the first texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE2D, textureOne);
     
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE2D, textureTwo);
     
    // now render

    Hope that helps.
    I don't think I'm doing this right. I keep getting an error that says "shader" was not declared in this scope. What's going on with that?

  6. #6
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,523
    Quote Originally Posted by danielr View Post
    I don't think I'm doing this right. I keep getting an error that says "shader" was not declared in this scope. What's going on with that?
    You're taking his pseudocode literally.

    shader.setUniform() is a hypothetical method on a hypothetical shader object which would make the shader current, query the uniform location, and assign a value to it.

    So just replace the shader.setUniform() calls with glUseProgram(), glGetUniformLocation() and glUniform1i().

  7. #7
    Junior Member Newbie
    Join Date
    Jul 2017
    Posts
    3
    Quote Originally Posted by GClements View Post
    You're taking his pseudocode literally.

    shader.setUniform() is a hypothetical method on a hypothetical shader object which would make the shader current, query the uniform location, and assign a value to it.

    So just replace the shader.setUniform() calls with glUseProgram(), glGetUniformLocation() and glUniform1i().
    Ok so here's what I did
    Code :
            OpenGP::EigenImage<vec3> image;
            OpenGP::imread("grass.tga", image);
            OpenGP::imread("rock.tga", image);
            glGetUniformLocation(0, "grasstexture");
            glGetUniformLocation(1, "rocktexture");
     
            glGenTextures(0, &_diffuse_tex);
            glBindTexture(GL_TEXTURE_2D, _diffuse_tex);
     
            check_error_gl();
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            check_error_gl();
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F,
                         image.cols(), image.rows(), 0,
                         GL_RGB, GL_FLOAT, image.data());
            check_error_gl();
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, _diffuse_tex);
     
            glActiveTexture(GL_TEXTURE1);
            glBindTexture(GL_TEXTURE_2D, _diffuse_tex);
    The problem is that I'm only getting the rock texture with no grass. I've also had problems before where the second texture would be extremely bright. With the above code, the lighting for the textures look normal but of course there's no grass.

  8. #8
    Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    429
    Quote Originally Posted by danielr View Post
    Ok so here's what I did
    Code :
            OpenGP::EigenImage<vec3> image;
            OpenGP::imread("grass.tga", image);
            OpenGP::imread("rock.tga", image);
            glGetUniformLocation(0, "grasstexture");
            glGetUniformLocation(1, "rocktexture");
     
            glGenTextures(0, &_diffuse_tex);
            glBindTexture(GL_TEXTURE_2D, _diffuse_tex);
     
            check_error_gl();
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            check_error_gl();
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F,
                         image.cols(), image.rows(), 0,
                         GL_RGB, GL_FLOAT, image.data());
            check_error_gl();
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, _diffuse_tex);
     
            glActiveTexture(GL_TEXTURE1);
            glBindTexture(GL_TEXTURE_2D, _diffuse_tex);
    The problem is that I'm only getting the rock texture with no grass. I've also had problems before where the second texture would be extremely bright. With the above code, the lighting for the textures look normal but of course there's no grass.

    You seem to do things not the right way.
    I don't know OpenGP, but it seems you give the last loaded one (rock.tga) to OpenGL. Try to call to OpenGP::imread with a different image. Then create two different OpenGL textures.
    Plus, you use the same texture (diffuse_tex) on both texture units.

    Finally, I would advice you to read an OpenGL tutorial from the beginning. This one for example in order to have the good basics.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •