1.简介
本博客以.glb格式为例,加载glb格式的3d模型,网上找了一圈,基本上都是根据OpenGL官方示例,加载.obj格式的3d模型。
下面以.obj和.glb格式的3D模型简单介绍一下。
常见的.obj格式的3D模型如下所示:纹理都已经被剥离出来了。所以在使用Assimp库加载的时候,加载了指定的路径即可。
但是.glb格式的3D模型如下所示,就只有一个glb文件,纹理嵌入到模型当中,假如我们使用Assimp库去加载的时候,能够加载出模型,但是加载出来的效果全是黑的,加载不了纹理。
加载的效果如下图所示,黑的一片。
原因分析:找不到纹理路径。
2.解决方法
将纹理分离,保存到本地文件,加载本地纹理文件。
首先通过ReadFile,读取本地文件,返回aiScene。
获取纹理数量:scene->mNumTextures。
获取当前的纹理:aiTexture* texture = scene->mTextures[i]。
然后看一下aiTexture官网文档介绍。
/** Width of the texture, in pixels * * If mHeight is zero the texture is compressed in a format * like JPEG. In this case mWidth specifies the size of the * memory area pcData is pointing to, in bytes. */unsigned int mWidth;/** Height of the texture, in pixels * * If this value is zero, pcData points to an compressed texture * in any format (e.g. JPEG). */unsigned int mHeight;/** Data of the texture. * * Points to an array of mWidth * mHeight aiTexel's. * The format of the texture data is always ARGB8888 to * make the implementation for user of the library as easy * as possible. If mHeight = 0 this is a pointer to a memory * buffer of size mWidth containing the compressed texture * data. Good luck, have fun! */ C_STRUCT aiTexel* pcData; char achFormatHint[ HINTMAXTEXTURELEN ]
mWidth:纹理的像素宽,如果高度为0,mWidth指定pcData指向的内存区域,以字节为单位。
mHeigth:纹理的像素高,像jpeg类型,该值为0。
pcData:纹理数据,数据的rgba值保存到这个数据里面。
achFormatHint:图片的格式,png或者jpg或者别的。
再进去看一下aiTexel结构,结构如下:包含r、g、b、a值,代表每一个像素的r、g、b、a值。
struct aiTexel {unsigned char b,g,r,a;#ifdef __cplusplus//! Comparison operatorbool operator== (const aiTexel& other) const{return b == other.b && r == other.r && g == other.g && a == other.a;}//! Inverse comparison operatorbool operator!= (const aiTexel& other) const{return b != other.b || r != other.r || g != other.g || a != other.a;}//! Conversion to a floating-point 4d coloroperator aiColor4D() const{return aiColor4D(r/255.f,g/255.f,b/255.f,a/255.f);}#endif // __cplusplus} PACK_STRUCT;
根据上面的条件,将图片保存到本地。
const aiScene *scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {qDebug() << "ERROR::ASSIMP::" << import.GetErrorString();return;}directory = path.substr(0, path.find_last_of('/'));for (int i = 0; i mNumTextures; i++){aiTexture* texture = scene->mTextures[i];char fileName[100];sprintf(fileName, "%s/%s.%s", modelDirectory.c_str(), texture->mFilename.C_Str(), texture->achFormatHint);QFile file(fileName);if (file.exists()){m_mapPath.insert(i, QString(fileName));continue;}if (!file.open(QIODevice::WriteOnly))break;unsigned char* buffer = new unsigned char[texture->mWidth * 4];memset(buffer, 0, texture->mWidth * 4);for (int x = 0; x mWidth; ++x){//拷贝RGBA数据到缓冲区int index = x * 4;buffer[index] = texture->pcData[x].b; // Bluebuffer[index + 1] = texture->pcData[x].g; // Greenbuffer[index + 2] = texture->pcData[x].r; // Redbuffer[index + 3] = texture->pcData[x].a; // Alpha}file.write((char*)buffer, texture->mWidth * 4);file.close();m_mapPath.insert(i, QString(fileName));delete[]buffer;}
如下图所示,将glb格式的纹理图片剥离出来保存到了本地。
最后加载对应的纹理即可。
3.加载效果图
4.完整源码
https://download.csdn.net/download/wzz953200463/88746271