Incorrect texture in 3d model loading using ASSIMP & OpenGL
Asked Answered
C

4

7

I'm trying to modify the sample code for loading 3d model included in ASSIMP's sample code, by using GLUT instead of WGL. However, i got a problem with the texture, as illustrated below:

loaded 3d model

while it is supposed to be as illustrated below:

original 3d model

and the code for drawing the 3d model listed below:

void recursive_render (const struct aiScene *sc, const struct aiNode* nd, float scale){
unsigned int i;
unsigned int n=0, t;
struct aiMatrix4x4 m = nd->mTransformation;
m.Scaling(aiVector3D(scale, scale, scale), m);
// update transform
m.Transpose();
glPushMatrix();
glMultMatrixf((float*)&m);
// draw all meshes assigned to this node
for (; n < nd->mNumMeshes; ++n){
    const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]];
    apply_material(sc->mMaterials[mesh->mMaterialIndex]);
    if(mesh->mNormals == NULL){
        glDisable(GL_LIGHTING);
    }
    else {
        glEnable(GL_LIGHTING);
    }
    if(mesh->mColors[0] != NULL) {
        glEnable(GL_COLOR_MATERIAL);
    }
    else {
        glDisable(GL_COLOR_MATERIAL);
    }

    for (t = 0; t < mesh->mNumFaces; ++t) {
        const struct 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;
        }
        glBegin(face_mode);
        for(i = 0; i < face->mNumIndices; i++){
            int vertexIndex = face->mIndices[i];    // get group index for current index
            if(mesh->mColors[0] != NULL)
                Color4f(&mesh->mColors[0][vertexIndex]); 
            if(mesh->mNormals != NULL)
                if(mesh->HasTextureCoords(0)){  
                    glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x, 1- mesh->mTextureCoords[0][vertexIndex].y);                    
                }
                glNormal3fv(&mesh->mNormals[vertexIndex].x);
                glVertex3fv(&mesh->mVertices[vertexIndex].x);
        }
        glEnd();
    }
}
// draw all children
for (n = 0; n < nd->mNumChildren; ++n)  {
    recursive_render(sc, nd->mChildren[n], scale);
}
glPopMatrix();

}

apply_material function, almost exactly the same as ASSIMP provided sample

void apply_material(const struct aiMaterial *mtl)
{
float c[4];
GLenum fill_mode;
int ret1, ret2;
struct aiColor4D diffuse;
struct aiColor4D specular;
struct aiColor4D ambient;
struct aiColor4D emission;
float shininess, strength;
int two_sided;
int wireframe;
unsigned int max;   // changed: to unsigned
int texIndex = 0;
aiString texPath;   //contains filename of texture
if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath))    {
    unsigned int texId = textureIdMap[texPath.data];
    glBindTexture(GL_TEXTURE_2D, texId);
}

set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f);
if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse))
    color4_to_float4(&diffuse, c);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c);
set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f);
if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient))
    color4_to_float4(&ambient, c);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c);
set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular))
    color4_to_float4(&specular, c);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f);
if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) 
    color4_to_float4(&emission, c);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c);

max = 1;
ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max);
max = 1;
ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max);
if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS))
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);
else {
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);
    set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c);
}

max = 1;
if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max))
    fill_mode = wireframe ? GL_LINE : GL_FILL;
else
    fill_mode = GL_FILL;
glPolygonMode(GL_FRONT_AND_BACK, fill_mode);

max = 1;
if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)
    glEnable(GL_CULL_FACE);
else
    glDisable(GL_CULL_FACE);
}

and also loadGLtextures function, i don't think it is related with culling tough.

int LoadGLTextures(const aiScene* scene) {
ILboolean success;
/* initialization of DevIL */
ilInit(); 
/* scan scene's materials for textures */
for (unsigned int m=0; m<scene->mNumMaterials; ++m) {
    int texIndex = 0;
    aiString path;  // filename
    aiReturn texFound = scene->mMaterials[m]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path);
    while (texFound == AI_SUCCESS) {
        //fill map with textures, OpenGL image ids set to 0
        textureIdMap[path.data] = 0; 
        // more textures?
        texIndex++;
        texFound = scene->mMaterials[m]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path);
    }
}

int numTextures = textureIdMap.size();
/* create and fill array with DevIL texture ids */
ILuint* imageIds = new ILuint[numTextures];
ilGenImages(numTextures, imageIds); 
/* create and fill array with GL texture ids */
GLuint* textureIds = new GLuint[numTextures];
glGenTextures(numTextures, textureIds); /* Texture name generation */

/* get iterator */
std::map<std::string, GLuint>::iterator itr = textureIdMap.begin();
printf("TextureIDMap Begin %i\n", textureIdMap.begin());
int i=0;
for (; itr != textureIdMap.end(); ++i, ++itr) {
    //save IL image ID
    std::string filename = (*itr).first;  // get filename
    (*itr).second = textureIds[i];    // save texture id for filename in map
    printf("Texture loaded: %s\n",filename.c_str());
    printf("Texture ID Map End: %i\n",textureIdMap.end());
    ilBindImage(imageIds[i]); /* Binding of DevIL image name */
    ilEnable(IL_ORIGIN_SET);
    ilOriginFunc(IL_ORIGIN_LOWER_LEFT); 
    success = ilLoadImage((ILstring)filename.c_str());

    if (success) {
        /* Convert image to RGBA */
        ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); 

        /* Create and load textures to OpenGL */
        glBindTexture(GL_TEXTURE_2D, textureIds[i]); 
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ilGetInteger(IL_IMAGE_WIDTH),
            ilGetInteger(IL_IMAGE_HEIGHT), 0, GL_RGBA, GL_UNSIGNED_BYTE,
            ilGetData()); 
    }
    else 
        printf("Couldn't load Image: %s\n", filename.c_str());
}
/* Because we have already copied image data into texture data  we can release memory used by image. */
ilDeleteImages(numTextures, imageIds); 
//Cleanup
delete [] imageIds;
delete [] textureIds;
//return success;
return true;
}

Lighthouse 3D has given an example for doing this, however, at the moment i can not implement GLSL and VAO to my program. Any solution? Thanks in advance.

Cheyenne answered 30/10, 2011 at 3:26 Comment(3)
I might be wrong but maybe problem is not with texture but with materials.Portraiture
do you have any idea what might cause the material problematic? thanks..Cheyenne
I've tried Lighthouse 3D's tutorial, but I can't get it to load a modelAthenaathenaeum
C
9

I've found the workaround. I changed how to access textures in recursive_render function using the following code :

glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x,  mesh->mTextureCoords[0][vertexIndex].y);

instead of:

glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x,  1-mesh->mTextureCoords[0][vertexIndex].y);
Cheyenne answered 2/11, 2011 at 3:5 Comment(1)
I am using Assimp with GLSL, the UV texture from the models I supply to Assimp works only when I use glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x, 1-(mesh->mTextureCoords[0][vertexIndex].y)); Else I get the weird behavior with textures. I think 1-y is needed for only a few modelsTolkan
B
2

This is not a problem with textures. Your problem is coming from backface culling (at least it seems like it since you can kind of see inside the duck). Either your polygons are wound in the wrong order, or your backface culling is set up incorrectly. If you post the code where you set the backface culling, we can see exactly what is wrong.

There could also be the possibility that some of your normals are facing inwards (which can also result from polygon winding). That would explain why your duck's beak is pitch black.

Breaking answered 30/10, 2011 at 4:36 Comment(2)
Thanks for your answer. The enable/disable culling is set at the end of the function apply_material. I'm not sure if the problem is about the culling, because even if I have disabled the culling, still, the texture won't load up correctly. (CMIIW). I've edited the code.Cheyenne
Have you tried disabling culling completely? I.e. removing the if statement and just putting glDisable(GL_CULL_FACE)?Breaking
P
1

I'm pretty sure the problem is the texture is being 'flipped' along Y axis. That's why your '1-y' works. It can be fixed by flipping the texture along Y while loading. Though I'm not yet sure why 'cause only stumbled upon this problem today.

Phrenic answered 15/8, 2012 at 14:27 Comment(0)
T
1

I'm not sure if this helps but you can flip UV coordinates when importing a model const aiScene* scene = importer.ReadFile(path, aiProcess_FlipUVs);

Tiemannite answered 9/2, 2021 at 5:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.