2
votes

I'm trying to render a wolf model. I've got the model to render properly. However, the texture I haven't gotten to work yet. I'm using OpenGL and AssImp.

Here's what the wolf looks like:

what my model looks like

Here's what the wolf is supposed to look like:

properly textured

Here's the code that loads the Model:

IModel* ModelManager::loadModel(const std::string filename) {

    if (models_[filename] != 0) {
        BOOST_LOG_TRIVIAL(debug) << "Model found.";
        return models_[filename].get();
    }

    const aiScene* scene = aiImportFile(filename.c_str(), aiProcessPreset_TargetRealtime_MaxQuality);

    if (scene == 0) {
        BOOST_LOG_TRIVIAL(debug) << "Unable to load model...";
        return 0;       
    }

    models_[filename] = std::unique_ptr<Model>( new Model(scene) );

    aiReleaseImport(scene);

    BOOST_LOG_TRIVIAL(debug) << "Done loading model '" << filename << "'.";

    return models_[filename].get();
}

Here's the code that loads the mesh for the Model:

Mesh::Mesh(const aiMesh* mesh) {
uint32 currentIndex = 0;

    for (uint32 t = 0; t < mesh->mNumFaces; ++t) {
        const aiFace* face = &mesh->mFaces[t];
        GLenum face_mode;

        switch(face->mNumIndices) {
            case 1: face_mode = GL_POINTS; break;
            case 2: face_mode = GL_LINES; break;
            case 3: face_mode = GL_TRIANGLES; break;
            default: face_mode = GL_POLYGON; break;
        }

        uint32 numIndices = face->mNumIndices;

        vertices_.resize( currentIndex + numIndices );
        normals_.resize( currentIndex + numIndices );
        textureCoordinates_.resize( currentIndex + numIndices );
        colors_.resize( currentIndex + numIndices );

        for(uint32 i = 0; i < numIndices; i++) {
            // get group index for current index
            int vertexIndex = face->mIndices[i];

            if (mesh->mNormals != 0) {
                vertices_[currentIndex + i]     = glm::vec3( mesh->mVertices[vertexIndex].x, mesh->mVertices[vertexIndex].y, mesh->mVertices[vertexIndex].z );
                normals_[currentIndex + i]      = glm::vec3( mesh->mNormals[vertexIndex].x, mesh->mNormals[vertexIndex].y, mesh->mNormals[vertexIndex].z );
            }

            if (mesh->HasTextureCoords(0)) {
                textureCoordinates_[currentIndex + i] = glm::vec2( mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y );
            }

            //utilities::AssImpUtilities::color4_to_vec4(&mesh->mColors[0][vertexIndex], colors_[colors_.size() + i]);
            if (mesh->mColors[0] != 0) {
                colors_[currentIndex + i]           = glm::vec4(
                                                        (float)mesh->mColors[0][vertexIndex].a,
                                                        (float)mesh->mColors[0][vertexIndex].b,
                                                        (float)mesh->mColors[0][vertexIndex].g,
                                                        (float)mesh->mColors[0][vertexIndex].r
                                                    );
            }           
        }

        currentIndex += 3;
    }
}

Here's the code that loads the Texture:

void Texture::loadTexture(utilities::Image* image) {
glGenTextures(1, &textureId_);

    glBindTexture(GL_TEXTURE_2D, textureId_);

    //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    // i don't combine the color with the original surface color, use only the texture map.
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image->width, image->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}

Here's the render code for a model:

for (uint32 i=0; i < meshes_.size(); i++) {
        textures_[i]->bind();
        meshes_[i]->render();
    }
}

Here's the 'bind' code for a Texture:

void Texture::bind() {
glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable( GL_TEXTURE_2D );
    glBindTexture(GL_TEXTURE_2D, textureId_);
}

And finally, here's the render code for a Mesh:

void Mesh::render() {
glBegin( GL_TRIANGLES );

    for (uint32 i = 0; i < vertices_.size(); i++) {
        glTexCoord2fv( &textureCoordinates_[i].x );
        glVertex3fv( &vertices_[i].x );
        glNormal3fv( &normals_[i].x );
    }

    glEnd();
}

I don't see anything obvious I'm doing wrong. Does anyone see anything I'm doing wrong??

1
Can you tell us how the texture should look? Maybe upload an image of it when rendered correctly?Tommy
@Tommy certainly - added now.Jarrett
What does the texture look like before mapping it to the object?JohnD
Wow, that's way off. Umm, you definitely need to invert y — OpenGL is graph paper style, OBJ is English reading order style — but beyond that is it possible that effectively throwing away the mesh colours is to blame?Tommy
@JohnD, I'm not sure what the license is on the texture image, so I'd rather not post :\Jarrett

1 Answers

2
votes

GAH, I figured it out...problem was when loading the mesh:

for(uint32 i = 0; i < numIndices; i++) {
            // get group index for current index
            int vertexIndex = face->mIndices[i];

            ...

            if (mesh->HasTextureCoords(0)) {
                textureCoordinates_[currentIndex + i] = glm::vec2( mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y );
            }

            ...
            }           
        }

Should have used mesh->mTextureCoords[0][vertexIndex].x instead of mesh->mTextureCoords[0][i].x (and similarly for the y index)...

So, just used the wrong texture coordinate index each loop, and so the texture coordinates were the same 3 coordinates for each triangle being rendered :S

Thanks everyone who looked at this issue!