multitexturing

Hello forum,

i am trying to implement a simple multi-texturing sample as follows, but i just see output of one texture:


void startup()
{
    loadShaders();

    glEnable(GL_DEPTH_TEST);

    //initiate the cube to render
    cube = new VboCube(shader);

    //create ids for 2 texture object
    glGenTextures(2,textureIDs);

    int textureWidth = 0;
    int textureHeight = 0;
    int channels = 0;

    //load the brick texture into channel 0
    glActiveTexture(GL_TEXTURE0);
    std::string fileName = "images/brick1.tga";

    GLubyte *data = SOIL_load_image(fileName.c_str(),
                                    &textureWidth,
                                    &textureHeight,
                                    &channels,
                                    SOIL_LOAD_AUTO);

    if(data == NULL)
    {
        std::cerr << "Failed to load the texture image: " << fileName << std::endl;
        exit(EXIT_FAILURE);
    }

    glBindTexture(GL_TEXTURE_2D,textureIDs[0]);

    //allocate storage
    glTexStorage2D(GL_TEXTURE_2D,1,GL_RGB8,textureWidth,textureHeight);

    //copy the data to the storage
    glTexSubImage2D(GL_TEXTURE_2D,0,0,0,textureWidth,textureHeight,GL_RGB,GL_UNSIGNED_BYTE,data);

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

    //free the soil image data
    SOIL_free_image_data(data);

    //load the moss texture in the channel 1
    glActiveTexture(GL_TEXTURE1);

    textureWidth = 0;
    textureHeight = 0;
    channels = 0;
    data = NULL;

    fileName = "images/moss.tga";

    data = SOIL_load_image(fileName.c_str(),
                           &textureWidth,
                           &textureHeight,
                           &channels,
                           SOIL_LOAD_AUTO);

    if(data == NULL)
    {
        std::cerr << "Failed to load the texture image: " << fileName << std::endl;
        exit(EXIT_FAILURE);
    }

    glBindTexture(GL_TEXTURE_2D,textureIDs[1]);

    //allocate storage
    glTexStorage2D(GL_TEXTURE_2D,1,GL_RGBA8,textureWidth,textureHeight);

    //copy the image to the storage
    glTexSubImage2D(GL_TEXTURE_2D,0,0,0,textureWidth,textureHeight,GL_RGBA,GL_UNSIGNED_BYTE,data);

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

    //free the soil image data
    SOIL_free_image_data(data);

}

The above snippet shows the texture image loading, creation of texture object and activating the channels. Check out the following shader entries:

Vertex shader


#version 430 core

//vertex attributes from the application
in vec3 vertexPosition;
in vec3 vertexNormal;
in vec2 vertexTexCoord;

out VS_OUT
{
  vec3 position;
  vec3 normal;
  vec2 texCoord;
} vs_out;

//uniform values from the application
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ModelViewProjectionMatrix;

void main()
{
   //pass through the texture coordinate	
   vs_out.texCoord = vertexTexCoord;

   //transform the normal and store it
   vs_out.normal = normalize(NormalMatrix * vertexNormal);
   
   //model position in the camera coordinates
   vs_out.position = vec3(ModelViewMatrix * vec4(vertexPosition,1.0));

   //model position in the clip coordinates
   gl_Position = ModelViewProjectionMatrix * vec4(vertexPosition,1.0);
}


Fragment shader


#version 430 core

in VS_OUT
{
  vec3 position;
  vec3 normal;
  vec2 texCoord;
} fs_in;

uniform sampler2D BrickTex;
uniform sampler2D MossTex;

struct LightInfo
{
  // light position in eye coordinates
  vec4 position ;

  // A,D,S intensity
  vec3 intensity;
};

uniform LightInfo light;

struct MaterialInfo
{
  vec3 ka; // ambient reflectivity
  vec3 kd; // diffuse reflectivity
  vec3 ks; // specular reflectivity
  float shininess; // specular shininess factor
};

uniform MaterialInfo material;

out vec4 color;


void phongModel( vec3 pos, vec3 norm, out vec3 ambAndDiff, out vec3 spec)
{
   //vector  to the light source	
   vec3 s = normalize(vec3(light.position) - pos);

   vec3 v = normalize(-pos.xyz);

   vec3 r = reflect( -s, norm);

   vec3 ambient = light.intensity * material.ka;

   float sDotN = max(dot(s,norm),0.0);

   vec3 diffuse = light.intensity * material.kd * sDotN;

   spec = vec3(0.0);

   if( sDotN > 0.0 )
     spec = light.intensity * material.ks * pow(max(dot(r,v),0.0),material.shininess);

   ambAndDiff = ambient + diffuse;
}

void main()
{
   vec3 ambAndDiff, spec;

   vec4 brickTexColor = texture(BrickTex,fs_in.texCoord);

   vec4 mossTexColor = texture(MossTex,fs_in.texCoord);

   phongModel(fs_in.position,
	      fs_in.normal,
              ambAndDiff,
              spec);

   vec4 texColor = mix(brickTexColor,mossTexColor,mossTexColor.a);

   color = vec4(ambAndDiff,1.0) * texColor +  vec4(spec,1.0);
}

Check the image :

I can only see the brick pattern and the other one is not visible.

Any hint on what i might be missing ?

Thanks

I don’t see where you assign the texture units to BrickTex and MossTex.

If you’re not actually assigning them, it’s entirely possible that both variables refer to texture unit zero (the brick texture).

Actually i am , sorry that i did not upload them in my last post. Here it goes:


void loadShaders()
{
    shader = new GLSLShader();

    shader->LoadFromFile(GL_VERTEX_SHADER,"shaders/multitexture.vert");
    shader->LoadFromFile(GL_FRAGMENT_SHADER,"shaders/multitexture.frag");

    shader->CreateAndLinkProgram();

    shader->Use();

    shader->AddAttribute("vertexPosition");
    shader->AddAttribute("vertexNormal");
    shader->AddAttribute("vertexTexCoord");

    shader->AddUniform("ModelViewMatrix");
    shader->AddUniform("NormalMatrix");
    shader->AddUniform("ModelViewProjectionMatrix");

    shader->AddUniform("BrickTex");
    shader->AddUniform("MossTex");

    shader->AddUniform("light.intensity");
    shader->AddUniform("light.position");

    shader->AddUniform("material.kd");
    shader->AddUniform("material.ks");
    shader->AddUniform("material.ka");
    shader->AddUniform("material.shininess");

    glUniform1f((*shader)("BrickTex"),0);
    glUniform1f((*shader)("MossTex"),1);

    glUniform3fv((*shader)("light.intensity"),1,glm::value_ptr(glm::vec3(1.f,1.f,1.0f)));
    glUniform4fv((*shader)("light.position"),1,glm::value_ptr(glm::vec4(1.0f,1.25f,1.25f,1.0f)));

    glUniform3fv((*shader)("material.kd"),1,glm::value_ptr(glm::vec3(0.9f,0.9f,0.9f)));
    glUniform3fv((*shader)("material.ks"),1,glm::value_ptr(glm::vec3(0.95f,0.95f,0.95f)));
    glUniform3fv((*shader)("material.ka"),1,glm::value_ptr(glm::vec3(0.1f,0.1f,0.1f)));
    glUniform1f((*shader)("material.shininess"),100.0f);

    shader->UnUse();
}

Check the snippet from above:


    glUniform1f((*shader)("BrickTex"),0);
    glUniform1f((*shader)("MossTex"),1);

Is not that enough ?

Hi again,

Since i did not get any response from the forum for a while, i thought of posting the whole source for your review:


#include "defines.h"
#include "GLSLShader.h"
#include "VboCube.h"

int winWidth = 512;
int winHeight = 512;

GLFWwindow *window = NULL;

GLSLShader *shader = NULL;

VboCube *cube = NULL;

GLuint textureIDs[2];

float zoom = 1.f;

glm::mat4 ViewMatrix = glm::mat4(1.0f);
glm::mat4 ModelMatrix = glm::mat4(1.0f);
glm::mat4 ModelViewMatrix = glm::mat4(1.0f);
glm::mat4 ProjectionMatrix = glm::mat4(1.0f);
glm::mat3 NormalMatrix = glm::mat3(1.0f);

void loadShaders();
void startup();
void shutdown();
void render(float);

static void framebuffer_size_callback(GLFWwindow *window,int width,int height);
static void scroll_callback(GLFWwindow *window,double x,double y);

int main()
{
    // Initialise GLFW before using any of its function
    if( !glfwInit() )
    {
       std::cerr << "Failed to initialize GLFW." << std::endl;
       exit(EXIT_FAILURE);
    }

    glfwWindowHint(GLFW_SAMPLES, 4);
    //we want the opengl 4
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
    //we do not want the old opengl
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Open a window and create its OpenGL context
    window = glfwCreateWindow( winWidth, winHeight, "Teapot Tessellation", NULL, NULL);

    if( window == NULL )
    {
       fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 4.3 compatible. Try the 2.1 version of the tutorials.
" );

       //we could not initialize the glfw window
       //so we terminate the glfw
       glfwTerminate();
       exit(EXIT_FAILURE);
    }


    glfwSetFramebufferSizeCallback(window,framebuffer_size_callback);
    glfwSetScrollCallback(window,scroll_callback);

    //make the current window context the current one
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    glfwGetFramebufferSize(window,&winWidth,&winHeight);
    framebuffer_size_callback(window,winWidth,winHeight);

    //initialize glew
    //needed for the core profile
    glewExperimental  = true;

    if(glewInit() != GLEW_OK)
    {
        std::cerr << "Failed to initialize GLEW" << std::endl;
        exit(EXIT_FAILURE);
    }

    if(!glewIsSupported("GL_VERSION_4_4"))
    {
        std::cerr << "OpenGL version 4.4 is yet to be supported" << std::endl;
        exit(EXIT_FAILURE);
    }

    while(glGetError() != GL_NO_ERROR) {}

    std::cout << "**************** OpenGL Driver Information *********************" << std::endl;

    std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
    std::cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
    std::cout << "GLEW version: " << glewGetString(GLEW_VERSION) << std::endl;
    std::cout << "OpenGL vendor: " << glGetString(GL_VENDOR) << std::endl;
    std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl;

    std::cout << "****************************************************************" << std::endl;

    //call some initialization function
    startup();


    do
    {
        render((float)glfwGetTime());
        glfwSwapBuffers(window);
        glfwPollEvents();
    } while(glfwGetKey(window,GLFW_KEY_ESCAPE) != GLFW_PRESS &&
            glfwWindowShouldClose(window) == 0);

    //once the following function is called
    //no more events will be dilivered for that
    //window and its handle becomes invalid
    glfwDestroyWindow(window);

    // Close OpenGL window and terminate GLFW
    glfwTerminate();

    //release all the resources that are allocated
    shutdown();

    exit(EXIT_SUCCESS);
}

void loadShaders()
{
    shader = new GLSLShader();

    shader->LoadFromFile(GL_VERTEX_SHADER,"shaders/multitexture.vert");
    shader->LoadFromFile(GL_FRAGMENT_SHADER,"shaders/multitexture.frag");

    shader->CreateAndLinkProgram();

    shader->Use();

    shader->AddAttribute("vertexPosition");
    shader->AddAttribute("vertexNormal");
    shader->AddAttribute("vertexTexCoord");

    shader->AddUniform("ModelViewMatrix");
    shader->AddUniform("NormalMatrix");
    shader->AddUniform("ModelViewProjectionMatrix");

    shader->AddUniform("BrickTex");
    shader->AddUniform("MossTex");

    shader->AddUniform("light.intensity");
    shader->AddUniform("light.position");

    shader->AddUniform("material.kd");
    shader->AddUniform("material.ks");
    shader->AddUniform("material.ka");
    shader->AddUniform("material.shininess");

    glUniform1f((*shader)("BrickTex"),0);
    glUniform1f((*shader)("MossTex"),1);

    glUniform3fv((*shader)("light.intensity"),1,glm::value_ptr(glm::vec3(1.f,1.f,1.0f)));
    glUniform4fv((*shader)("light.position"),1,glm::value_ptr(glm::vec4(1.0f,1.25f,1.25f,1.0f)));

    glUniform3fv((*shader)("material.kd"),1,glm::value_ptr(glm::vec3(0.9f,0.9f,0.9f)));
    glUniform3fv((*shader)("material.ks"),1,glm::value_ptr(glm::vec3(0.95f,0.95f,0.95f)));
    glUniform3fv((*shader)("material.ka"),1,glm::value_ptr(glm::vec3(0.1f,0.1f,0.1f)));
    glUniform1f((*shader)("material.shininess"),100.0f);

    shader->UnUse();
}

void startup()
{
    loadShaders();

    glEnable(GL_DEPTH_TEST);

    //initiate the cube to render
    cube = new VboCube(shader);

    //create ids for 2 texture object
    glGenTextures(2,textureIDs);

    int textureWidth = 0;
    int textureHeight = 0;
    int channels = 0;
    GLubyte *data = NULL;

    //load the brick texture into channel 0
    glActiveTexture(GL_TEXTURE0);
    std::string fileName = "images/brick1.tga";

    data = SOIL_load_image(fileName.c_str(),
                                    &textureWidth,
                                    &textureHeight,
                                    &channels,
                                    SOIL_LOAD_AUTO);

    if(data == NULL)
    {
        std::cerr << "Failed to load the texture image: " << fileName << std::endl;
        exit(EXIT_FAILURE);
    }

    glBindTexture(GL_TEXTURE_2D,textureIDs[0]);

    //allocate storage
    glTexStorage2D(GL_TEXTURE_2D,1,GL_RGB8,textureWidth,textureHeight);

    //copy the data to the storage
    glTexSubImage2D(GL_TEXTURE_2D,0,0,0,textureWidth,textureHeight,GL_RGB,GL_UNSIGNED_BYTE,data);

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

    //free the soil image data
    SOIL_free_image_data(data);

    //load the moss texture in the channel 1
    glActiveTexture(GL_TEXTURE1);

    textureWidth = 0;
    textureHeight = 0;
    channels = 0;
    data = NULL;

    fileName = "images/moss.tga";

    data = SOIL_load_image(fileName.c_str(),
                           &textureWidth,
                           &textureHeight,
                           &channels,
                           SOIL_LOAD_AUTO);

    if(data == NULL)
    {
        std::cerr << "Failed to load the texture image: " << fileName << std::endl;
        exit(EXIT_FAILURE);
    }

    glBindTexture(GL_TEXTURE_2D,textureIDs[1]);

    //allocate storage
    glTexStorage2D(GL_TEXTURE_2D,1,GL_RGBA8,textureWidth,textureHeight);

    //copy the image to the storage
    glTexSubImage2D(GL_TEXTURE_2D,0,0,0,textureWidth,textureHeight,GL_RGBA,GL_UNSIGNED_BYTE,data);

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

    //free the soil image data
    SOIL_free_image_data(data);

}

void shutdown()
{
    if(shader)
    {
        shader->DeleteShaderProgram();
        delete shader;
        shader = NULL;
    }

    if(cube)
    {
        delete cube;
        cube = NULL;
    }

    glDeleteTextures(2,textureIDs);
}

void render(float currentTime)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::mat4 translation = glm::translate(glm::mat4(1.0f),glm::vec3(0.0f,0.0f,-zoom));
    glm::mat4 rotY = glm::rotate(glm::mat4(1.0f),currentTime,glm::vec3(0.0f,1.0f,0.0f));
    glm::mat4 rotX = glm::rotate(glm::mat4(1.0f),currentTime,glm::vec3(1.0f,0.0f,0.0f));

    ModelMatrix = translation * rotY * rotX;


    ModelViewMatrix = ViewMatrix * ModelMatrix;

    //calculate the normal matrix from the modelview matrix
    NormalMatrix = glm::inverseTranspose(glm::mat3(ModelViewMatrix));

    shader->Use();

    glUniformMatrix4fv((*shader)("ModelViewMatrix"),1,GL_FALSE,glm::value_ptr(ModelViewMatrix));
    glUniformMatrix3fv((*shader)("NormalMatrix"),1,GL_FALSE,glm::value_ptr(NormalMatrix));
    glUniformMatrix4fv((*shader)("ModelViewProjectionMatrix"),1,GL_FALSE,glm::value_ptr(ProjectionMatrix * ModelViewMatrix));

    cube->render();

    shader->UnUse();
}

void framebuffer_size_callback(GLFWwindow *window,int width,int height)
{
    if(height < 1)
        height = 1;

    winWidth = width;
    winHeight = height;


    GLfloat aspect = (GLfloat)winWidth/(GLfloat)winHeight;

    //setup the projection matrix
    ProjectionMatrix = glm::perspective(30.0f,aspect,0.1f,1000.0f);

    glViewport(0,0,winWidth,winHeight);
}

void scroll_callback(GLFWwindow *window,double x,double y)
{
    //increase/decrease the field of view
    zoom += (float)y/4.f;

    if(zoom < 0)
        zoom = 0;
}

Sorry Folks ,

To get you into this.

It was a tiny mistake. It was before :


glUniform1f((*shader)("BrickTex"),0);
glUniform1f((*shader)("MossTex"),1);

It must be the following:


glUniform1i((*shader)("BrickTex"),0);
glUniform1i((*shader)("MossTex"),1);

Now it is solved. Thanks