Loading a 3D model from Qt Resources. Assimp Error: No suitable reader found for the file format of file "$$$___magic___$$$.".
-
Hello. I want to load a simple 3D model (just plane.dae) from Qt resources. But I get this error:
Assimp Error: No suitable reader found for the file format of file "$$$___magic___$$$.".
// Add these lines to .pro: // INCLUDEPATH += "E:\Libs\assimp-5.0.1-mingw-32bit\include" // LIBS += -L"E:\Libs\assimp-5.0.1-mingw-32bit\lib" // LIBS += -lopengl32 -lassimp -lIrrXML -lzlibstatic #ifdef _WIN32 #include <windows.h> extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; #endif #include <QtWidgets/QApplication> #include <QtWidgets/QOpenGLWidget> #include <QtCore/QResource> #include <QtCore/QDebug> #include "assimp/Importer.hpp" #include <assimp/scene.h> #include <assimp/postprocess.h> class OpenGLWidget : public QOpenGLWidget { public: OpenGLWidget(QWidget *parent = nullptr) : QOpenGLWidget (parent) {} private: void initializeGL() override { glClearColor(0.f, 0.f, 0.f, 1.f); glEnable(GL_DEPTH_TEST); Assimp::Importer importer; QResource r(":/Models/PlaneBlender8.dae"); // const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); const aiScene *scene = importer.ReadFileFromMemory(r.data(), r.size(), aiProcess_Triangulate | aiProcess_FlipUVs); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { qDebug() << "Assimp Error:" << importer.GetErrorString(); return; } } void resizeGL(int w, int h) override { glViewport(0, 0, w, h); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); OpenGLWidget w; w.show(); return a.exec(); }
-
How do you add PlaneBlender8.dae to your resource?
Is PlaneBlender8.dae a compressed file created by rcc?
Anyway that's not the right way to read from your resource.
Use QFile to open and read it, not QResource. -
-
I added it by Resource Editor like usual. Okay, you are right. I will use QFile. Yes, I know about Qt3D, and maybe I will continue to study it, but pure OpenGL has more power. Really I do not like Assimp because it require additional space and I do not know how to deploy it on Phones. I will study Assimp a little because it allow to make short examples for beginners and maybe some customers will prefere Assimp. The better solution is to use .dae (Collada) because it can contain materials and any kind of animations. I like to study linear algebra of skeletal animation.
Fuller version in WebGL: ch09/JointModel: https://jsfiddle.net/8Observer8/ygvk7odv/ (Click on Robot to control it by keys) I do not what to study deep engines like Qt3D, Unity, Unreal, Godot and so on because engines require a lot of power and space and some of them are not so fast and compact like Qt C++. I want to have three versions: Desktop, Mobile and Web. Yes, I know that some engines can build to WebGL. I tryed it with Unity, but build is havy for notebooks and does not works on mobile browsers. I do not require PBR in by 3D applications. But I study WebGL and OpenGL more than 3 years and I like it. Code in Qt C++ and WebGL is the same. I do not have time to learn something new from scratch. OpenGL and WebGL are fast, small and I have full control with shaders and math and I understand how it works. Simple games are just for practice and for fun. I want to make 3D interactive apps for non-game applications.
PlaneBlender8.dae
<?xml version="1.0" encoding="utf-8"?> <COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <asset> <contributor> <author>Blender User</author> <authoring_tool>Blender 2.83.5 commit date:2020-08-19, commit time:06:07, hash:c2b144df395f</authoring_tool> </contributor> <created>2020-11-27T14:01:41</created> <modified>2020-11-27T14:01:41</modified> <unit name="meter" meter="1"/> <up_axis>Z_UP</up_axis> </asset> <library_images/> <library_geometries> <geometry id="Plane-mesh" name="Plane"> <mesh> <source id="Plane-mesh-positions"> <float_array id="Plane-mesh-positions-array" count="12">-1 -1 0 1 -1 0 -1 1 0 1 1 0</float_array> <technique_common> <accessor source="#Plane-mesh-positions-array" count="4" stride="3"> <param name="X" type="float"/> <param name="Y" type="float"/> <param name="Z" type="float"/> </accessor> </technique_common> </source> <source id="Plane-mesh-normals"> <float_array id="Plane-mesh-normals-array" count="3">0 0 1</float_array> <technique_common> <accessor source="#Plane-mesh-normals-array" count="1" stride="3"> <param name="X" type="float"/> <param name="Y" type="float"/> <param name="Z" type="float"/> </accessor> </technique_common> </source> <source id="Plane-mesh-map-0"> <float_array id="Plane-mesh-map-0-array" count="12">1 0 0 1 0 0 1 0 1 1 0 1</float_array> <technique_common> <accessor source="#Plane-mesh-map-0-array" count="6" stride="2"> <param name="S" type="float"/> <param name="T" type="float"/> </accessor> </technique_common> </source> <vertices id="Plane-mesh-vertices"> <input semantic="POSITION" source="#Plane-mesh-positions"/> </vertices> <triangles count="2"> <input semantic="VERTEX" source="#Plane-mesh-vertices" offset="0"/> <input semantic="NORMAL" source="#Plane-mesh-normals" offset="1"/> <input semantic="TEXCOORD" source="#Plane-mesh-map-0" offset="2" set="0"/> <p>1 0 0 2 0 1 0 0 2 1 0 3 3 0 4 2 0 5</p> </triangles> </mesh> </geometry> </library_geometries> <library_visual_scenes> <visual_scene id="Scene" name="Scene"> <node id="Plane" name="Plane" type="NODE"> <matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix> <instance_geometry url="#Plane-mesh" name="Plane"/> </node> </visual_scene> </library_visual_scenes> <scene> <instance_visual_scene url="#Scene"/> </scene> </COLLADA>
-
Loading a plane from .dae using Assimp in Qt C++ and OpenGL
main.cpp
// Add these lines to .pro: // INCLUDEPATH += "E:\Libs\assimp-5.0.1-mingw-32bit\include" // LIBS += -L"E:\Libs\assimp-5.0.1-mingw-32bit\lib" // LIBS += -lopengl32 -lassimp -lIrrXML -lzlibstatic #ifdef _WIN32 #include <windows.h> extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; #endif #include <QtWidgets/QApplication> #include <QtWidgets/QOpenGLWidget> #include <QtWidgets/QMessageBox> #include <QtGui/QOpenGLBuffer> #include <QtGui/QOpenGLShaderProgram> #include <QtGui/QMatrix4x4> #include <QtGui/QVector3D> #include <QtCore/QDebug> #include "assimp/Importer.hpp" #include <assimp/scene.h> #include <assimp/postprocess.h> class OpenGLWidget : public QOpenGLWidget { public: OpenGLWidget(QWidget *parent = nullptr) : QOpenGLWidget (parent) { setWindowTitle("Qt C++, OpenGL"); resize(300, 300); } private: QOpenGLBuffer m_vertPosBuffer; QOpenGLShaderProgram m_program; int m_numVertices; void initializeGL() override { glClearColor(0.1f, 0.1f, 0.1f, 1.f); glEnable(GL_DEPTH_TEST); Assimp::Importer importer; const char *path = "Models/PlaneBlender8.dae"; const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { qDebug() << "Assimp Error:" << importer.GetErrorString(); QMessageBox::critical(this, "Assimp Error:", importer.GetErrorString()); return; } m_numVertices = scene->mMeshes[0]->mNumVertices; float vertPositions[m_numVertices * 3]; int vertPosIndex = 0; for (int i = 0; i < m_numVertices; i++) { vertPositions[vertPosIndex++] = scene->mMeshes[0]->mVertices[i].x; vertPositions[vertPosIndex++] = scene->mMeshes[0]->mVertices[i].y; vertPositions[vertPosIndex++] = scene->mMeshes[0]->mVertices[i].z; // qDebug() << scene->mMeshes[0]->mVertices[i].x << ", " // << scene->mMeshes[0]->mVertices[i].y << ", " // << scene->mMeshes[0]->mVertices[i].z; } m_vertPosBuffer.create(); m_vertPosBuffer.bind(); m_vertPosBuffer.allocate(vertPositions, sizeof(vertPositions)); const char *vertShaderSrc = "#version 330 core\n" "in vec3 aPosition;" "uniform mat4 uModelMatrix;" "void main()" "{" " gl_Position = uModelMatrix * vec4(aPosition, 1.0);" "}"; const char *fragShaderSrc = "#version 330 core\n" "out vec4 fragColor;" "void main()" "{" " fragColor = vec4(0.5, 0.2, 0.7, 1.0);" "}"; m_program.create(); m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vertShaderSrc); m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, fragShaderSrc); m_program.link(); QMatrix4x4 modelMatrix; modelMatrix.scale(0.5); m_program.bind(); m_program.setUniformValue("uModelMatrix", modelMatrix); m_program.setAttributeBuffer("aPosition", GL_FLOAT, 0, 3); m_program.enableAttributeArray("aPosition"); } void resizeGL(int w, int h) override { glViewport(0, 0, w, h); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDrawArrays(GL_TRIANGLES, 0, m_numVertices); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); OpenGLWidget w; w.show(); return a.exec(); }
-
I translated the example above from Qt5 to Qt6: https://github.com/8Observer8/load-with-assimp-opengl2-qt6-cpp
-
-
I'm having this same issue. I get the same $$magic$$ error as well. I tried passing a .stl hint to assimp importer, but that didn't work either.
I have a lot of stl files included using qresources, so it would be a pain to migrate away, but it is feasible. I was using Qt3D before, but am trying to get away from it since it's being deprecated. Hoping someone here has some hints.const auto qrc = QResource{filePath.string().c_str()}; auto qfile = QFile{qrc.fileName()}; qfile.open(QIODeviceBase::OpenModeFlag::ReadOnly); auto data = std::vector<char>{}; data.resize(qfile.size()); qfile.read(data.data(), data.size()); const auto ret = importer.ReadFileFromMemory( reinterpret_cast<const void*>(data.data()), static_cast<std::size_t>(data.size()), aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_FlipUVs); qWarning() << importer.GetErrorString(); return ret;