0
votes

so i have a very simple glsl shader that renders an object with texture and directional light.

now I'm having a really tough time trying to get the texture to display, everything else works except for that.

when i disable the shader( glUseProgram(0) ) the texture renders in black and white but when i enable it the whole mesh is in a single color and not textured, and it changes color when I try different textures.

this is how i load my texture

data = CImg<unsigned char>(src);
glGenTextures(1, &m_textureObj);
glBindTexture(GL_TEXTURE_2D, m_textureObj);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, data.width(), data.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

this is how i bind my texture

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_textureObj);

and this is my vertex shader

#version 330

layout (location = 0) in vec3 Position;
layout (location = 1) in vec2 TexCoord;
layout (location = 2) in vec3 Normal;

uniform mat4 gWVP;
uniform mat4 gWorld;

out vec2 TexCoord0;
out vec3 Normal0;

void main()
{
    gl_Position = (gWVP * gWorld) * vec4(Position, 1.0);
    TexCoord0 = TexCoord;
    Normal0 = (gWorld * vec4(Normal, 0.0)).xyz;
}

and this is my fragment shader

#version 330

in vec2 TexCoord0;
in vec3 Normal0;                                                                    

out vec4 FragColor;                                                                 

struct DirectionalLight                                                             
{                                                                                   
    vec3 Color;                                                                     
    float AmbientIntensity;                                                         
    float DiffuseIntensity;                                                         
    vec3 Direction;                                                                 
};                                                                                  

uniform DirectionalLight gDirectionalLight;                                         
uniform sampler2D gSampler;                                                         

void main()                                                                         
{                                                                                   
    vec4 AmbientColor = vec4(gDirectionalLight.Color, 1.0f) *                       
                    gDirectionalLight.AmbientIntensity;                         

    float DiffuseFactor = dot(normalize(Normal0), -gDirectionalLight.Direction);    

    vec4 DiffuseColor;                                                              

    if (DiffuseFactor > 0) {                                                        
        DiffuseColor = vec4(gDirectionalLight.Color, 1.0f) *                        
                   gDirectionalLight.DiffuseIntensity *                         
                   DiffuseFactor;                                               
    }                                                                               
    else {                                                                          
        DiffuseColor = vec4(0, 0, 0, 0);                                            
    }                                                                               

    FragColor = texture2D(gSampler, TexCoord0.xy) *
            (AmbientColor + DiffuseColor);
}

and last but not least i tell my shader to use the correct texture

glUniform1i(GetUniformLocation("gSampler"), 0);

I have done a F**** ton of reading online on how to properly do this simple and task and ran it in a bunch of different configurations only to become frustrated.

If anyone can point out what I'm doing wrong I would be thrilled, I'm sure I'm missing one stupid detail but i cant seem to find it. please don't refer me to https://www.opengl.org/wiki/Common_Mistakes#Creating_a_complete_texture thanks for reading.

this is how i create my mesh and upload it to the GPU. this is the vertex constructor Vertex(x, y, z, u, v)

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

unsigned int Indices[] = {
        0, 3, 1,
        1, 3, 2,
        2, 3, 0,
        1, 2, 0
    };
    Vertex Vertices[4] = {
        Vertex(-1.0f, -1.0f, 0.5773f, 0.0f, 0.0f),
        Vertex(0.0f, -1.0f, -1.15475f, 0.5f, 0.0f),
        Vertex(1.0f, -1.0f, 0.5773f,  1.0f, 0.0f),
        Vertex(0.0f, 1.0f, 0.0f, 0.5f, 1.0f)
    };
    Mesh *data = new Mesh(Vertices, 4, Indices, 12);

    glGenBuffers(1, &vbo);
        glGenBuffers(1, &ibo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

            glEnableVertexAttribArray(0);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
            glEnableVertexAttribArray(1);
            glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(12));
            glEnableVertexAttribArray(2);
            glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(24));

            glBufferData(GL_ARRAY_BUFFER, data->count*Vertex::Size(),  data->verts, GL_STATIC_DRAW);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, data->indsCount*sizeof(unsigned int), data->inds, GL_STATIC_DRAW);

    unsigned int Vertex::Size() {
        return 32;
    }

 /*In the update function*/
 glDrawElements(GL_TRIANGLES, data->indsCount, GL_UNSIGNED_INT, 0);

this is my vertex class http://pastebin.com/iYwjEdTQ

Edit

I HAVE SOLVED IT! i was binding the vertex the old way, then after ratchet freak showed me how to bind it correctly i noticed that i was binding the texture coordinates to location 2 but in the shader i was looking for in in location 1.

glEnableVertexAttribArray(2);
            glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(24));

(the frag shader)

layout (location = 1) in vec2 TexCoord;

so i changed the fragment shader to

layout (location = 2) in vec2 TexCoord;

and now it works beautifully. Thanks ratchet freak and birdypme for helping I'm gonna accept ratchet freak's answer because it lead me to the solution but you both steered me in the right direction.

2
Hello, can you add the code that creates the geometry? Even if it's a simple quad with 4 vertices. My initial feeling from the symptoms is that the texture coordinates may not be completely bound (as hinted by the fact that different textures show different colors).birdypme
sure thing. just addedAmit Hendin

2 Answers

4
votes

This is your problem:

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(0));
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(12));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(24));

This uses the old and deprecated fixed-function style specification instead you wan to use glVertexAttribPointer:

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, Vertex::Size(), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, Vertex::Size(), BUFFER_OFFSET(12));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, Vertex::Size(), BUFFER_OFFSET(24));

The other problem I see is that your Vertex class doesn't take the normal in the constructor. And Vertex::Size() should be equal to sizeof(Vertex)

1
votes

Generally speaking, you should be using sizeof() instead of hard-coded offsets, to avoid bad surprises.

    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3, GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(0));
    glEnableClientState(GL_NORMAL_ARRAY);
    glNormalPointer(GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(3*sizeof(float)));
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2, GL_FLOAT, Vertex::Size(), BUFFER_OFFSET(6*sizeof(float)));

and in vertex.h

    static unsigned int Size() {
        return 8*sizeof(float);
    }

However, this is unlikely to properly answer your question. I am not deleting my answer to keep the vertex.h pastebin below, which can be important, but I'll probably delete it once a valid answer has been posted.