Texturing a cube with different images using OpenGL

I have a project from school I’m currently working on and I need to texture a non-rotating cube showing just 3 faces. I’ve tried doing it on my own but I only get one image on all the 3 faces. I don’t know if it’s my method that’s wrong or the way I’m loading the remaining two images. I would really appreciate help from anyone.

this is how I create my texture

    //Load Image
    //int width, height; // width1, height1;
    //unsigned char* image = SOIL_load_image("res/images/image1.jpg", &width, &height, 0, SOIL_LOAD_RGBA);

    GLuint texture1, texture2, texture3;
    // texture 1
    // ---------
    glGenTextures(1, &texture1);
    glBindTexture(GL_TEXTURE_2D, texture1);
    // set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // load image, create texture and generate mipmaps
    int width, height;
    stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
    unsigned char* image = SOIL_load_image("res/images/image1.jpg", &width, &height, 0, SOIL_LOAD_RGBA);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
    glGenerateMipmap(GL_TEXTURE_2D);

    SOIL_free_image_data(image);
    glBindTexture(GL_TEXTURE_2D, 0);
    // texture 2
    // ---------
    glGenTextures(1, &texture2);
    glBindTexture(GL_TEXTURE_2D, texture2);
    // set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // load image, create texture and generate mipmaps
    int width1, height1;
    unsigned char* image1 = SOIL_load_image("res/images/image2.jpg", &width1, &height1, 0, SOIL_LOAD_RGBA);

    // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1);
    glGenerateMipmap(GL_TEXTURE_2D);

    SOIL_free_image_data(image1);
    glBindTexture(GL_TEXTURE_2D, 1);

    // texture 3
    // ---------
    glGenTextures(1, &texture3);
    glBindTexture(GL_TEXTURE_2D, texture3);
    // set the texture wrapping parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    // set texture filtering parameters
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // load image, create texture and generate mipmaps
    int width2, height2;
    unsigned char* image2 = SOIL_load_image("res/images/image3.jpg", &width2, &height2, 0, SOIL_LOAD_RGBA);

    // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, image2);
    glGenerateMipmap(GL_TEXTURE_2D);

    SOIL_free_image_data(image2);
    glBindTexture(GL_TEXTURE_2D, 2);

shader.Use();
    shader.setInt("texture0", 0); // Function to get UniformLocation
    shader.setInt("texture1", 0);
    shader.setInt("texture2", 2);

And this is the code for when I activate and bind the texture in the rendering Loop

shader.Use();
        glActiveTexture(GL_TEXTURE0);
        glBindVertexArray(VAO);

        glBindTexture(GL_TEXTURE_2D, texture1);

        glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);

        glActiveTexture(GL_TEXTURE1);
        glBindVertexArray(VAO);
        glBindTexture(GL_TEXTURE_2D, texture2);

        glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);
        
        glActiveTexture(GL_TEXTURE2);
        glBindVertexArray(VAO);
        glBindTexture(GL_TEXTURE_2D, texture2);

        glDrawArrays(GL_TRIANGLES, 0, 36);
        glBindVertexArray(0);

This is my fragment shader for the program. I really don’t know how to use the 3 sampler2D variables I also created here

#version 330 core
in vec2 textCoords;
out vec4 color1;

uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;

void main()
{
     color1 = texture(texture0,textCoords) ;   
 }


This is the result I get for now with this code, but I want different images on the three faces 
![image|690x387](upload://ml895Vmp2Vu566AlCk89fwHeXfw.png)![cube|690x387](upload://the6jR0JeXxLIkLcUBdOBXkeY8z.jpeg)

you should have a look at
ActiveTexture(enum)
It sets the texture-unit that you load your images on. The argument is an enum
TEXTUREi = TEXTURE0+i
It’s probably needed at you initiate, not just when you want to use it.

Texturing is not particularly intuitive to setup and use.

can you please give an example of how I would do this with texture atlas

I take, that my suggestions so far has been usefull. It could be usefull to others that reads the posts if you give feedback.

I cannot accomodate you on any code-example. I’ve never met the term texture atlas in my books. But, I can suggest what to do: I’ll assume that you want to use the full capacity of the texture-units … they may be able to store very large images.
First, plan the layout of the images on the texture-unit. Order the accumulated width*height when you call glTexImage2D(..) and provide a null-pointer for data.
Then call glTexSubImage() for writing each image into the proper place (according to your plan) in the texture.
I do this with fonts and words, use one texture and then take on the administery of finding the proper texture-coordinates whenever I use the texture. Keeping track of the lower-left pixel-position for each images reduces this administery in your case where you add this coordinate to the coordinate you would use in the setup on 3 tex-units.
I would probably erect a uniform in the shader and set this lower-left there … then you shouldn’t have to change the tex-coords you already use.
… does this make sense?
Recall that the name uniform refers to a variable that changes much less than each execution of the vertices … the variable is uniformly used on those.