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

相关推荐
我不是疯子是傻子40 分钟前
Qt CAN通信周期发送抖动?实测定时器精度校准与时间戳补偿方案
开发语言·数据库·qt
2023自学中2 小时前
Qt 简易聊天室(第二篇),单线程 改为 多线程,方便后续增加文件传输功能
c++·qt
进哥AI研习社3 小时前
从像素到3D开放世界:Kimi K3在游戏开发中的引擎级能力实测
3d
小宇的天下4 小时前
3D IC 与 TSV:设计挑战与需求
3d
丰锋ff7 小时前
1.7在Qt窗口中添加右键菜单
开发语言·qt
richard_yuu11 小时前
JSON vs XML vs 二进制:3种序列化终极选型
xml·c++·qt·学习·json
秋田君11 小时前
QT_实战TCP 聊天程序说明文档以及实现
数据库·qt·tcp/ip
byxdaz1 天前
QT中服务使用
开发语言·qt
杀生丸学AI1 天前
【稀疏重建】StructSplat:基于非校准稀疏视图的可泛化3DGS
深度学习·3d·音视频·transformer·三维重建·空间智能
蓝速科技1 天前
蓝速科技 3D 全息舱 AI 数字人一体机全尺寸选型实测指南
人工智能·科技·3d