0
votes

I have to texturize a mesh using the OpenGL API and shaders.

To accomplish this, I did the following steps:

  1. Load the picture and create a texture

    img::ImageLoader imgLoader;
    unsigned char* data = imgLoader.LoadTextureFromFile("../Texturen/brickwork.jpg", &width, &height, true);
    
    glGenTextures(1, &texId);
    glBindTexture(GL_TEXTURE_2D, texId);{
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    }
    
  2. Create vertices, normals and texture coords

    std::vector<float> v, n, t;
    
    // actual calculation is left out to make it more readable
    
    obj = new GLBatch;
        obj->Begin(GL_TRIANGLES, v.size()/3, t.size()/2);{
        obj->CopyVertexData3f(v.data());
        obj->CopyNormalDataf(n.data());
        obj->CopyTexCoordData2f(t.data(), 0);
    }obj->End();
    
  3. Load the shaders

    shaders =  gltLoadShaderPairWithAttributes("VertexShader.glsl", "FragmentShader.glsl", 2, 
        GLT_ATTRIBUTE_VERTEX, "vVertex", 
        GLT_ATTRIBUTE_NORMAL, "vNormal",
        GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");
    
    gltCheckErrors(shaders);
    

    (VertexShader.glsl)

    #version 130
    in vec4 vVertex;
    in vec4 vNormal;
    in vec2 vTexCoord;
    
    uniform mat4 mvpMatrix;
    uniform mat4 mvMatrix;
    uniform mat3 normalMatrix;
    /// Light position in Eye-Space
    uniform vec4 light_pos_vs ;
    /// Light diffuse color
    uniform vec4 light_diffuse ;
    uniform vec4 light_ambient ;
    /// Light specular color
    uniform vec4 light_specular ;
    /// Specular power (shininess)
    uniform float spec_power;
    
    /// Material parameters
    uniform vec4 mat_emissive;
    uniform vec4 mat_ambient; 
    uniform vec4 mat_diffuse;   
    uniform vec4 mat_specular;  
    
    /// output
    out vec4 color;
    out vec2 texCoords;
    
    void main()
    {   
        texCoords = vTexCoord;
        // Transform vertex from objekt to clip-space
        gl_Position = mvpMatrix * vVertex ;
    
        // Transform vertex from object to eye-space
        vec4 vertex_vs = mvMatrix * vVertex;
        vec3 ecPos = vertex_vs.xyz / vertex_vs.w;
    
        // Calculate light direction
        vec3 light_dir_vs = normalize(vec3(light_pos_vs.xyz));
    
        // Transform normals from object into eye-space
        vec3 normal_vs = normalize(normalMatrix * (vNormal).xyz) ;
    
        // Viewing vector in eye-space
        vec3 view_dir_vs = normalize(-ecPos );
    
        // Halfway vektor for Phong-Blinn light modell
        vec3 halfway_vs = normalize(view_dir_vs + light_dir_vs ) ;
    
        // Diffuse
        float NdotL = max(dot(normal_vs, light_dir_vs),0.0) ;
        vec4 diffuse_color = NdotL * mat_diffuse * light_diffuse ;
    
        // Specular
        float NdotH = max(dot(normal_vs, halfway_vs),0.0) ;
        vec4 specular_color = pow(NdotH ,spec_power) * mat_specular * light_specular ;
    
        // Color output
        color = mat_emissive + light_ambient*mat_ambient + diffuse_color + specular_color;
    }
    

    (FragmentShader.glsl)

    #version 130
    
    in vec2 texCoords;
    in vec4 color;
    
    uniform sampler2D textureMap;
    
    out vec4 fragColor;
    
    void main()
    {
        fragColor = texture(textureMap, texCoords);
        fragColor *= color;
    }
    
  4. Draw everything in the display function

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glLineWidth(INDICATOR_WIDTH);
    glBindTexture(GL_TEXTURE_2D, texId);
    
    modelViewMatrix.LoadIdentity();
    modelViewMatrix.Translate(0,0,-5);
    modelViewMatrix.PushMatrix();{
    
        M3DMatrix44f rot;
        m3dQuatToRotationMatrix(rot,rotation);
        modelViewMatrix.MultMatrix(rot);
    
        // set shader
        glUseProgram(shaders);
        // pass matrices
        glUniformMatrix4fv(glGetUniformLocation(shaders, "mvpMatrix"), 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
        glUniformMatrix4fv(glGetUniformLocation(shaders, "mvMatrix"),  1, GL_FALSE, transformPipeline.GetModelViewMatrix());
        glUniformMatrix3fv(glGetUniformLocation(shaders, "normalMatrix"),  1, GL_FALSE, transformPipeline.GetNormalMatrix(true));
        // pass light properties
        glUniform4fv(glGetUniformLocation(shaders, "light_pos_vs"),1,light_pos);
        glUniform4fv(glGetUniformLocation(shaders, "light_ambient"),1,light_ambient);
        glUniform4fv(glGetUniformLocation(shaders, "light_diffuse"),1,light_diffuse);
        glUniform4fv(glGetUniformLocation(shaders, "light_specular"),1,light_specular);
        glUniform1f(glGetUniformLocation(shaders, "spec_power"),specular_power);
        // pass material properties
        glUniform4fv(glGetUniformLocation(shaders, "mat_emissive"),1,mat_emissive);
        glUniform4fv(glGetUniformLocation(shaders, "mat_ambient"),1,mat_ambient);
        glUniform4fv(glGetUniformLocation(shaders, "mat_diffuse"),1,mat_diffuse);
        glUniform4fv(glGetUniformLocation(shaders, "mat_specular"),1,mat_specular);
    
        drawObject();
    
    }modelViewMatrix.PopMatrix();
    
    gltCheckErrors(shaders);
    glutSwapBuffers();
    glutPostRedisplay();
    

After all those steps, the result looks fine but has no texture :(

Screenshot

What actually happens here is, that every vertex is mapped to the same pixel of my Texture which is apparently grey.

I tried texture coords from (0,0) to (1,1) and (0,0) to (width,height) but nothing changed.

2
Yea sounds like your texture coordinates might not be right. Check this answer out (look at the wikipedia cube map link too): stackoverflow.com/questions/4983532/… - vincent
Where are your glGetUniformLocation() and glUniform1i() calls for textureMap? - genpfault
Try changing this: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data) to this: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA8, GL_UNSIGNED_BYTE, &data ) if the texture has an alpha channel or to glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB8, GL_UNSIGNED_BYTE, &data ) if it doesn't and also notice that I'm using the address of data. Also move this function call to after your filtering & mipmap calls. And as genpfault has mentioned you are missing calls to glGetUniformLocation() & glUniform1i()... - Francis Cugler
@FrancisCugler I'm pretty sure my color format is correct since your suggestions just make the loaded texture black. I'm not quite sure what you and @genpfault were talking about when saying glGetUniformLocation() and glUniform1i() are missing. As far as i understand, glBindTexture() in combination with the sampler2D prefix should work. Maybe thats my missconception, could you elaborate a bit? - RobinW
Draw out texture coordinates as color on your mesh and make sure they are correct. - Bartek Banachewicz

2 Answers

2
votes

Change

shaders =  gltLoadShaderPairWithAttributes(
    "VertexShader.glsl", 
    "FragmentShader.glsl",
    2, 
    GLT_ATTRIBUTE_VERTEX, "vVertex", 
    GLT_ATTRIBUTE_NORMAL, "vNormal",
    GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");

to

shaders =  gltLoadShaderPairWithAttributes(
    "VertexShader.glsl", 
    "FragmentShader.glsl",
    3, // < -------------------- 
    GLT_ATTRIBUTE_VERTEX, "vVertex", 
    GLT_ATTRIBUTE_NORMAL, "vNormal",
    GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");

because the 3rd parameter in the function signature is the number of the attributes that immediately follow and should be linked to the shader. In this case there are 3 attributes: GLT_ATTRIBUTE_VERTEX, GLT_ATTRIBUTE_NORMAL and GLT_ATTRIBUTE_TEXTURE0. In the original code only GLT_ATTRIBUTE_VERTEX, GLT_ATTRIBUTE_NORMAL are linked an so no texture coordinates were passed to the shader.

1
votes

First, when you bind a texture you should specify the texture unit that you use for this texture. This can be done by glActiveTexture

int textureUnit = 0; // <- put the number of the txture unit in here
glActiveTexture( GL_TEXTURE0 + textureUnit );
glGenTextures( 1, &texId );
glBindTexture( GL_TEXTURE_2D, texId );

The maximum nuber of texture units can be asked by glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,...). The number of texture units is implementation dependent, but must be at least 80. Since you only need one 0 is ok for you. Texture unit 0 is default, so if you never change it you can skip this.

Next make sure you used glTexImage2D in the right way, especially check wether the format suits to your data. Use glGetError to check if specifying the target texture succeeded.

When you use your shader program you have to link the texture unit to your uniform texture sampler.

int texMapLocation = glGetUniformLocation( shaders, "textureMap" );
...
glUseProgram( shaders );
...
glUniform1i( texMapLocation, textureUnit ); // <- you are missing this