1
votes

So I'm trying to texture an object in OpenGL and I have two textures that I want to mix together in the fragment shader (rock.tga and grass.tga). My fragment shader:

out vec3 color;

in vec2 uv;

uniform sampler2D grasstexture;
uniform sampler2D rocktexture;

To load a sampler2D texture here's what I did in my header file in C++:

OpenGP::EigenImage<vec3> image;
OpenGP::imread("grass.tga", image);

glGenTextures(0, &_tex);
glBindTexture(GL_TEXTURE_2D, _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();
tex_id = glGetUniformLocation(_pid, "grasstexture");
glUniform1i(tex_id, 0);

Which loads the grass texture into my fragment shader. Now what I want to know is how do I load in multiple textures. I can't copy the above code twice because one texture is always over-written by the other. So how can I load in multiple textures into the fragment shader?

EDIT: Here's where my _tex is declared:

    class Mesh{
    protected:
        GLuint _tex;

        GLuint _vpoint;    ///< memory buffer
        GLuint _vnormal;   ///< memory buffer

    public:
        GLuint getProgramID(){ return _pid; }

        void init(){
//code for the textures goes in here

Here's my updated code:

OpenGP::EigenImage<vec3> image;
glActiveTexture(GL_TEXTURE0);
OpenGP::imread("grass.tga", image);

//glGenTextures(1, &_tex);
glBindTexture(GL_TEXTURE_2D, _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();
tex_id = glGetUniformLocation(_pid, "grasstexture");
glUniform1i(tex_id, 0);

glActiveTexture(GL_TEXTURE1);
OpenGP::imread("rock.tga", image);

//glGenTextures(0, &_tex);

glBindTexture(GL_TEXTURE_2D, _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, 1, GL_RGB32F,
             image.cols(), image.rows(), 0,
             GL_RGB, GL_FLOAT, image.data());
check_error_gl();
tex_id = glGetUniformLocation(_pid, "rocktexture");
glUniform1i(tex_id, 1);
1

1 Answers

4
votes

Opengl hides a lot of its context so you need to keep it in mind. You have three parts of the texture:

  • Texture name - just an integer, pass it around.
  • Active texture unit - context thing, set with GL_TEXTURE0...
  • Texture target - for starters GL_TEXTURE_2D is all you need.

Here is what you need to do in order to get a 2d texture working:

  1. Create opengl texture name with glGenTextures
  2. Set up the texture with following set of actions:

    2.1 Set active texture unit with glActiveTexture

    2.2 Specify the target of the active texture unit to which the named texture is bound glBindTexture. For this all three texture parts should be "under control".

    2.3 Specify a two-dimensional texture image for the active texture unit with glTexImage2D

    2.4 Set parameters for the active texture unit with glTexParameteri

  3. In order to simultaneously use multiple textures make sure that they have unique name and texture unit:

    3.1 Set active texture unit to 0

    3.2 Bind one named texture to active texture unit

    3.3 Pass texture unit (0) to shader

    3.4 Set active texture unit to 1

    3.5 Bind another named texture to active texture unit

    3.6 Pass texture unit (1) to shader

    ...

  4. And when you're done don't forget to delete all named textures with glDeleteTextures

The order of commands is not the only one possible and the set of commands is not minimal - it is just typical.


Original answer:

You need to set next active texture like this:

 glActiveTexture(GL_TEXTURE1);

before you bind bind the next texture. It will also work like:

std::vector<std::string> textures = {"grass.tga", "rock.tga"};
for(int i = 0; i < textures.size(); i++) {
    glActiveTexture(GL_TEXTURE0 + i);
    // create the texture
}