使用 ASSIMP 和 OpenGL 加载 3D 模型时纹理不正确
Posted
技术标签:
【中文标题】使用 ASSIMP 和 OpenGL 加载 3D 模型时纹理不正确【英文标题】:Incorrect texture in 3d model loading using ASSIMP & OpenGL 【发布时间】:2011-10-30 03:26:48 【问题描述】:我正在尝试通过使用 GLUT 而不是 WGL 来修改用于加载 ASSIMP 的 sample code 中包含的 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*)&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函数,与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, &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);
还有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, &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 已经为此提供了an example,但是,目前我无法在我的程序中实现 GLSL 和 VAO。有什么解决办法吗?提前致谢。
【问题讨论】:
我可能错了,但问题可能不在于纹理,而在于材料。 您知道什么可能导致材料出现问题吗?谢谢.. 我尝试过 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);
【讨论】:
我将 Assimp 与 GLSL 一起使用,我提供给 Assimp 的模型中的 UV 纹理仅在我使用glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x, 1-(mesh->mTextureCoords[0][vertexIndex].y));
时才有效,否则我会得到纹理的奇怪行为。我认为只有少数模型需要 1-y【参考方案2】:
这不是纹理的问题。您的问题来自背面剔除(至少看起来是这样,因为您可以看到鸭子内部)。您的多边形以错误的顺序缠绕,或者您的背面剔除设置不正确。如果您发布设置背面剔除的代码,我们可以确切地看到问题所在。
您的一些法线也可能朝内(这也可能是多边形缠绕的结果)。这可以解释为什么你的鸭嘴是漆黑的。
【讨论】:
感谢您的回答。启用/禁用剔除设置在函数apply_material
的末尾。我不确定问题是否与剔除有关,因为即使我禁用了剔除,纹理仍然无法正确加载。 (CMIIW)。我已经编辑了代码。
您是否尝试过完全禁用剔除? IE。删除 if 语句,只放 glDisable(GL_CULL_FACE)?【参考方案3】:
我很确定问题是纹理正在沿 Y 轴“翻转”。这就是您的“1-y”有效的原因。它可以通过在加载时沿 Y 翻转纹理来修复。虽然我还不确定为什么今天才偶然发现这个问题。
【讨论】:
【参考方案4】:我不确定这是否有帮助,但您可以在导入模型时翻转 UV 坐标
const aiScene* scene = importer.ReadFile(path, aiProcess_FlipUVs);
【讨论】:
以上是关于使用 ASSIMP 和 OpenGL 加载 3D 模型时纹理不正确的主要内容,如果未能解决你的问题,请参考以下文章
我的OpenGL学习进阶之旅Assimp库支持哪些3D模型格式?
渲染在 OpenGL 中使用 Assimp 加载的动画模型时折叠的网格
我的OpenGL学习进阶之旅解决使用Assimp和OpenGL进行在屏渲染和离屏渲染FBO时绘制3D模型出现各种诡异的模型渲染画面问题,都是血和泪的教训啊!!!