1
votes

I am currently experiencing an issue with rendering multiple textures at once with OpenGL 3.3 Core. I load 2 separate images through SOIL ( an image loading library ) but only one of the images appears in the final program. This is my current code:

#include <iostream>
#include <GL\glew.h>
#include <GL\GL.h>
#include <GLFW\glfw3.h>
#include <SOIL.h>
#include "Shader.h"
#include "texture2D.h"

using namespace std;

void processInput(GLFWwindow *window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

int main() {

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow *window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
    if (window == NULL) {
        cout << "GLFW WINDOW CREATION FAILED! " << endl;
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);

    cout << "Made By Rial Seebran " << endl;
    cout << glfwGetVersionString() << endl;

    glewInit();
    if (glewInit() != GLEW_OK) {
        cout << "GLEW INITIALIZATION FAILED! " << endl;
        glfwTerminate();
        return -1;
    }

    float positions[] = {
        -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
        -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
        0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
        0.5f, 0.5f, 0.0f, 1.0f, 1.0f
    };

    unsigned int indices[] = {
        0, 1, 2,
        3, 2, 1
    };

    unsigned int VAO;
    unsigned int VBO;
    unsigned int EBO;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, ((GLvoid*)(0)));
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, ((GLvoid*)(sizeof(float) * 3)));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    Shader shader("shader.vs", "shader.fs");

    Texture2D texture1;
    texture1.LoadTexture("container.jpg");

    Texture2D texture2;
    texture2.LoadTexture("awesomeface.png");

    shader.Use();

    while (!glfwWindowShouldClose(window)) {

        glClearColor(0.1f, 0.15f, 0.2f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        texture1.BindTexture(0);
        texture2.BindTexture(1);

        shader.Uniform1I("myTexture1", 0);
        shader.Uniform1I("myTexture2", 1);

        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        processInput(window);
        glfwPollEvents();
        glfwSwapBuffers(window);
    }

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);


    glfwTerminate();
    return 0;
}

And this is the texture class (all in a .h file):

#ifndef TEXTURE2D
#define TEXTURE2D

#include <GL\glew.h>
#include <GL\GL.h>
#include <SOIL.h>
#include <iostream>

using namespace std;

class Texture2D {
public:
    Texture2D();
    ~Texture2D();
    void LoadTexture(const char* texPath);
    void BindTexture(unsigned int texUnit);
    unsigned int texture_M;
};

Texture2D::Texture2D() {

}

Texture2D::~Texture2D() {
    glDeleteTextures(1, &texture_M);
}

void Texture2D::LoadTexture(const char* texPath) {
    int width;
    int height;
    unsigned char *image = SOIL_load_image(texPath, &width, &height, 0, SOIL_LOAD_RGBA);
    if (image == NULL) {
        cout << "Failed to load Image! " << endl;
    }

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glBindTexture(GL_TEXTURE_2D, texture_M);
    if (image != NULL) {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
        glGenerateMipmap(GL_TEXTURE_2D);
    }

    SOIL_free_image_data(image);
    glBindTexture(GL_TEXTURE_2D, 0);
}

void Texture2D::BindTexture(unsigned int texUnit) {
    glActiveTexture(GL_TEXTURE0 + texUnit);
    glBindTexture(GL_TEXTURE_2D, texture_M);
}

#endif 

In the fragment shader, I use the mix() function which linearly interpolates the 2 textures, yet the "awesomeface.png" image is the only texture which shows up in the final program. What should be fixed, for the program to display both textures?

final program output

3
Where do you generate the texture names (glGenTextures)? - Rabbid76
Please post your shader code. - user11313931
If possible, consider using the new Direct State Access mode introduced in OpenGL 4.5 to avoid binding. - user11313931
thanks i assumed that creating texture_M in the public area of the class would create the texture. You have answered my question @Rabbid76 - rial

3 Answers

2
votes

You have to add the following line at the beggining of Texture::LoadTexture() to generate the texture ID:

glGenTextures(1, &texture_M);

This will reserve a valid ID used to identify the texture object (that will later have to be initialized by a call to glBindTexture()). It can be used to reference the texture in subsequent OpenGL calls (including deleting the texture using glDeleteTextures()).

1
votes

When a unused name is bound to a texture target by glBindTexture, then a texture object is generated. But a new unused texture name has to be reserved by glGenTextures.

The texture parameters which set by glTexParameteri are set to the texture object which is bound to the specified target.

Reserve the unused texture name, then create the texture object. After that you can set the parameters and specify the two-dimensional texture image.

// 1. reserve texture name 
glGenTextures(1, &texture_M);

// 2. generate texture object
glBindTexture(GL_TEXTURE_2D, texture_M);

// set parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// generate texture image
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
1
votes

I did not call glGenTextures() in the texture2D class. Thanks to stackOverflow user @Rabbid76 for pointing that out