Неправильная текстура при загрузке 3D-модели с использованием ASSIMP и OpenGL

#c #opengl #glut

#c #opengl #перенасыщение

Вопрос:

Я пытаюсь изменить пример кода для загрузки 3D-модели, включенный в пример кода ASSIMP, используя GLUT вместо WGL. Однако у меня возникла проблема с текстурой, как показано ниже:

загруженная 3d-модель

в то время как предполагается, что это будет так, как показано ниже:

исходная 3d-модель

и код для рисования 3D-модели, приведенный ниже:

 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*)amp;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 = amp;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(amp;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(amp;mesh->mNormals[vertexIndex].x);
                glVertex3fv(amp;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, почти точно такая же, как предоставленный ASSIMP образец

 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, amp;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, amp;diffuse))
    color4_to_float4(amp;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, amp;ambient))
    color4_to_float4(amp;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, amp;specular))
    color4_to_float4(amp;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, amp;emission)) 
    color4_to_float4(amp;emission, c);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c);

max = 1;
ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, amp;shininess, amp;max);
max = 1;
ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, amp;strength, amp;max);
if((ret1 == AI_SUCCESS) amp;amp; (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, amp;wireframe, amp;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, amp;two_sided, amp;max)) amp;amp; two_sided)
    glEnable(GL_CULL_FACE);
else
    glDisable(GL_CULL_FACE);
}
 

а также функция LoadGLTextures, я не думаю, что это связано с жесткой отбраковкой.

 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, amp;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, amp;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 %in", 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: %sn",filename.c_str());
    printf("Texture ID Map End: %in",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: %sn", 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 привел пример для этого, однако на данный момент я не могу реализовать GLSL и VAO в своей программе. Есть решение? Заранее спасибо.

Комментарии:

1. Возможно, я ошибаюсь, но, возможно, проблема не в текстуре, а в материалах.

2. есть ли у вас какие-либо идеи о том, что может вызвать проблемы с материалом? Спасибо..

3. Я пробовал учебник Lighthouse 3D, но я не могу заставить его загружать модель

Ответ №1:

Я нашел обходной путь. Я изменил способ доступа к текстурам в recursive_render функции, используя следующий код :

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

вместо:

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

Комментарии:

1. Я использую Assimp с GLSL, УФ-текстура из моделей, которые я предоставляю Assimp, работает только тогда, когда я использую glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x, 1-(mesh->mTextureCoords[0][vertexIndex].y)); Else, я получаю странное поведение с текстурами. Я думаю, что 1-y требуется только для нескольких моделей

Ответ №2:

Это не проблема с текстурами. Ваша проблема связана с отбраковкой задней поверхности (по крайней мере, так кажется, поскольку вы можете видеть внутри утки). Либо ваши полигоны намотаны в неправильном порядке, либо отбраковка задней поверхности настроена неправильно. Если вы опубликуете код, в котором вы задаете отбраковку задней поверхности, мы сможем точно увидеть, что не так.

Также может быть вероятность того, что некоторые из ваших нормалей обращены внутрь (что также может быть результатом намотки полигонов). Это объясняет, почему клюв вашей утки черный как смоль.

Комментарии:

1. Спасибо за ваш ответ. Включение / отключение отбраковки устанавливается в конце функции apply_material . Я не уверен, что проблема связана с отбраковкой, потому что, даже если я отключил отбраковку, текстура все равно не будет загружаться правильно. (CMIIW). Я отредактировал код.

2. Вы пробовали полностью отключить отбраковку? Т.е. удаление оператора if и просто добавление glDisable(GL_CULL_FACE)?

Ответ №3:

Я почти уверен, что проблема в том, что текстура «переворачивается» вдоль оси Y. Вот почему ваш ‘1-y’ работает. Это можно исправить, перевернув текстуру вдоль Y во время загрузки. Хотя я еще не уверен, почему, потому что наткнулся на эту проблему только сегодня.

Ответ №4:

Я не уверен, поможет ли это, но вы можете перевернуть UV-координаты при импорте модели const aiScene* scene = importer.ReadFile(path, aiProcess_FlipUVs);