0

I am trying to use a texture mapping buffer together with a vertex buffer and it's not working. I am working with lib3ds to load 3DS models. I've searched everywhere and I a can't see any error with my code.

I think the error is somewhere in the draw function:

void CModel3DS::Draw() const
{
    assert(m_TotalFaces != 0);

    glEnable(GL_TEXTURE_2D);

    // Not working!! Why?                                   
    glBindTexture(GL_TEXTURE_2D, texturemap_IDs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, m_TexcoorVBO);

    glClientActiveTexture(GL_TEXTURE0);
    glTexCoordPointer(2, GL_FLOAT, 0, 0);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);


    // Enable vertex and normal arrays
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);


    // Bind the vbo with the normals
    glBindBuffer(GL_ARRAY_BUFFER, m_NormalVBO);
    // The pointer for the normals is NULL which means that OpenGL will use the currently bound vbo
    glNormalPointer(GL_FLOAT, 0, NULL);

    glBindBuffer(GL_ARRAY_BUFFER, m_VertexVBO);
    glVertexPointer(3, GL_FLOAT, 0, NULL);

    // Render the triangles
    glDrawArrays(GL_TRIANGLES, 0, m_TotalFaces * 3);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
}

CModel3DS * model;

To initialize the buffers I use:

// Copy vertices and normals to the memory of the GPU
void CModel3DS::CreateVBO()
{
    assert(m_model != NULL);

    // Calculate the number of faces we have in total
    GetFaces();

    // Allocate memory for our vertices and normals
    float(*vertices)[3] = new float[m_TotalFaces * 3][3];
    float(*normals)[3] = new float[m_TotalFaces * 3][3];
    float(*textures)[2] = new float[m_TotalFaces * 3][2];

    Lib3dsMesh ** meshes = m_model->meshes;
    unsigned int FinishedFaces = 0;
    // Loop through all the meshes
    for (int i = 0; i < m_model->nmeshes; i++)
    {
        lib3ds_mesh_calculate_face_normals(meshes[i], &normals[FinishedFaces * 3]);

        // Loop through every face
        for (unsigned int cur_face = 0; cur_face < meshes[i]->nfaces; cur_face++)
        {
            Lib3dsFace * face = &meshes[i]->faces[cur_face];
            for (unsigned int j = 0; j < 3; j++)
            {
                memcpy(&vertices[FinishedFaces * 3 + j], meshes[i]->vertices[face->index[j]], 3 * sizeof(float));
                memcpy(&textures[FinishedFaces * 3 + j], meshes[i]->texcos[face->index[j]], 2 * sizeof(float));
            }
            FinishedFaces++;
        }
    }

    // Generate a Vertex Buffer Object and store it with our vertices
    glGenBuffers(1, &m_VertexVBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_VertexVBO);
    glBufferData(GL_ARRAY_BUFFER, 3* sizeof(float) * 3 * m_TotalFaces, vertices, GL_STATIC_DRAW);

    // Generate another Vertex Buffer Object and store the normals in it
    glGenBuffers(1, &m_NormalVBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_NormalVBO);
    glBufferData(GL_ARRAY_BUFFER, 3* sizeof(float) * 3 * m_TotalFaces, normals, GL_STATIC_DRAW);

    // Generate Vertex Buffer Object and store texture coordinates in it
    glGenBuffers(1, &m_TexcoorVBO);
    glBindBuffer(GL_ARRAY_BUFFER, m_TexcoorVBO);
    glBufferData(GL_ARRAY_BUFFER, (sizeof(float)* 2) * 3 * m_TotalFaces, textures, GL_STATIC_DRAW);

    // Clean up our allocated memory
    delete[] vertices;
    delete[] normals;
    delete[] textures;

    // We no longer need lib3ds
    lib3ds_file_free(m_model);
    m_model = NULL;
}

And finally to load the tga textures I use an outside library so my code is simply:

for (int i = 0; i < m_model->nmaterials; i++)
    {
        char * aux = new char[strlen("tex/") + strlen(m_model->materials[i]->texture1_map.name) + 1];
        strcpy(aux, "tex/");
        strcat(aux, m_model->materials[i]->texture1_map.name);
        printf("Map[%d] = %s\n", i, aux);
        texturemap_IDs[i] = load_texture_TGA(aux, NULL, NULL, GL_REPEAT, GL_REPEAT);
        if (texturemap_IDs[i] == 0)
            printf("%s texture failed to load\n", aux);
        delete[] aux;
    }

My final result is a model with all the vertex drawn but no textures applied.

I am very new with OpenGL in general so I apologize in advance if it turns out to be a simple error.

affonseca
  • 1
  • 2
  • How does the resulting rendering look? Is it drawing black, or is lighting properly set up? One possible problem is that by default, the texture values are modulated with the color. If the color is black, you wouldn't see anything. You could try adding a `glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)` to see if things work if you only use the texture to determine the color. One thing I noticed is that in `CreateVBO()`, you only set the normal for the first vertex of each mesh. – Reto Koradi Jun 07 '14 at 14:29
  • I might be wrong but I though the function lib3ds_mesh_calculate_face_normals got the normals for every face of the mesh. I actually could see the lightning effects displayed on the model. I was only the texture that was missing. – affonseca Jun 07 '14 at 16:29
  • I'm not familiar with lib3ds, so that's very possible. If the lighting looks ok, you should be all good with that. At the risk of checking about the obvious: You double checked that the texture was successfully loaded? Which includes that `m_model->nmaterials` was at least 1 when your texture loading code was called? – Reto Koradi Jun 07 '14 at 17:06

1 Answers1

0

According to my knowledge, before binding the texture, you need to point, where do you want to bind it. Try adding

glActiveTexture(GL_TEXTURE0);

directly before

glBindTexture(GL_TEXTURE_2D, texturemap_IDs[0]);
Elvithari
  • 834
  • 1
  • 8
  • 13
  • GL is a state machine, there is always a currently active texture unit, `GL_TEXTURE0` is the default. It _might_ be the case that has been changed by some other code parts not presented in the question, but calling `glBindTexture()` without `glActiveTexture()` is not a problem in itself. – derhass Jun 07 '14 at 15:20
  • @derhass: Well, about 1 line ***after*** `glBindTexture (...)` in the code, the active (client) texture unit is set. If it is being set at all, I have to assume that is because multiple units are being used in the program (since the client active texture unit also defaults to `GL_TEXTURE0`). Thus it might make sense to put `glActiveTexture (GL_TEXTURE0)` immediately before `glEnable (GL_TEXTURE_2D)`. – Andon M. Coleman Jun 07 '14 at 16:33
  • @AndonM.Coleman: yes, I've seen that, too. But this is still all speculation. – derhass Jun 07 '14 at 16:43
  • I tried to change the order. The result was the same. This is really bugging me. – affonseca Jun 07 '14 at 17:05
  • @user3717793: Then this is really getting strange. The code seems to be ok. You should double check that the texture is really there. Do some simple test. Try drawing it on a simple triangle for example... – Elvithari Jun 07 '14 at 17:12
  • I found out what the problem was. It lied indeed in the fact that the textures were not initialized. All because I was creating them before openGL could start. I knew it had to be something simple. Thanks everyone for the help!! – affonseca Jun 07 '14 at 19:55