OpenGL Assimp加载各类型模型(.obj、.fbx、.glb、.3ds)

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->mTexturesi

然后看一下aiTexture官网文档介绍。

cpp 复制代码
    /** 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值。

cpp 复制代码
struct aiTexel {
    unsigned char b,g,r,a;

#ifdef __cplusplus
    //! Comparison operator
    bool operator== (const aiTexel& other) const
    {
        return b == other.b && r == other.r &&
               g == other.g && a == other.a;
    }

    //! Inverse comparison operator
    bool operator!= (const aiTexel& other) const
    {
        return b != other.b || r != other.r ||
               g != other.g || a != other.a;
    }

    //! Conversion to a floating-point 4d color
    operator aiColor4D() const
    {
        return aiColor4D(r/255.f,g/255.f,b/255.f,a/255.f);
    }
#endif // __cplusplus

} PACK_STRUCT;

根据上面的条件,将图片保存到本地。

cpp 复制代码
   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 < scene->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 < texture->mWidth; ++x)
        {
            //拷贝RGBA数据到缓冲区
            int index = x * 4;

            buffer[index] = texture->pcData[x].b; // Blue
            buffer[index + 1] = texture->pcData[x].g; // Green
            buffer[index + 2] = texture->pcData[x].r;         // Red
            buffer[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

相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner13 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能15 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G15 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt