qt opengl assimp 加载骨骼动画完整代码

时间: 2023-07-09 18:03:22 浏览: 232
下面是使用 Qt、OpenGL 和 Assimp 库加载骨骼动画的完整代码示例。在这个示例中,我们使用 Assimp 库加载一个包含骨骼动画的模型,并在 OpenGL 中渲染它。 ```c++ #include <QOpenGLWidget> #include <QOpenGLFunctions> #include <QOpenGLShaderProgram> #include <QMatrix4x4> #include <assimp/Importer.hpp> #include <assimp/scene.h> #include <assimp/postprocess.h> class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: GLWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {} protected: void initializeGL() override { initializeOpenGLFunctions(); // 编译顶点着色器和片段着色器 m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader.vert"); m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader.frag"); m_program.link(); // 加载模型 Assimp::Importer importer; const aiScene* scene = importer.ReadFile("model.dae", aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_JoinIdenticalVertices | aiProcess_CalcTangentSpace | aiProcess_LimitBoneWeights); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { qWarning() << "Failed to load model:" << importer.GetErrorString(); return; } // 初始化骨骼动画 m_boneMatrices.resize(scene->mNumMeshes); m_boneOffsets.resize(scene->mNumMeshes); m_boneMapping.resize(scene->mNumMeshes); for (unsigned int i = 0; i < scene->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[i]; // 计算骨骼权重 QVector<QVector<QPair<int, float>>> boneWeights(mesh->mNumVertices); for (unsigned int j = 0; j < mesh->mNumBones; j++) { aiBone* bone = mesh->mBones[j]; int boneIndex = m_boneMapping[i].value(QString::fromUtf8(bone->mName.C_Str()), -1); if (boneIndex == -1) { boneIndex = m_boneOffsets[i].size(); m_boneOffsets[i].append(QMatrix4x4()); m_boneMapping[i].insert(QString::fromUtf8(bone->mName.C_Str()), boneIndex); } m_boneOffsets[i][boneIndex] = QMatrix4x4((float*)bone->mOffsetMatrix.Transpose().a1); for (unsigned int k = 0; k < bone->mNumWeights; k++) { aiVertexWeight weight = bone->mWeights[k]; boneWeights[weight.mVertexId].append(qMakePair(boneIndex, weight.mWeight)); } } // 计算每个顶点的骨骼矩阵 QVector<QVector<QMatrix4x4>> boneMatrices(mesh->mNumVertices); for (int j = 0; j < mesh->mNumVertices; j++) { QVector<QPair<int, float>> weights = boneWeights[j]; for (int k = 0; k < weights.size(); k++) { int boneIndex = weights[k].first; float weight = weights[k].second; boneMatrices[j].append(weight * m_boneOffsets[i][boneIndex]); } } // 上传骨骼矩阵到 GPU int boneMatrixLocation = m_program.attributeLocation(QString("boneMatrix[%1]").arg(i)); for (int j = 0; j < boneMatrices.size(); j++) { for (int k = 0; k < 4; k++) { for (int l = 0; l < 4; l++) { m_boneMatrices[i][j].data()[k * 4 + l] = boneMatrices[j][k][l]; } } } m_program.setAttributeArray(boneMatrixLocation, GL_FLOAT_MAT4, m_boneMatrices[i].constData(), 4); m_program.enableAttributeArray(boneMatrixLocation); } // 上传顶点数据到 GPU glGenVertexArrays(1, &m_vao); glBindVertexArray(m_vao); for (unsigned int i = 0; i < scene->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[i]; GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (3 + 3 + 2 + 4 * 4) * mesh->mNumVertices, nullptr, GL_STATIC_DRAW); float* data = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); for (unsigned int j = 0; j < mesh->mNumVertices; j++) { aiVector3D position = mesh->mVertices[j]; aiVector3D normal = mesh->mNormals[j]; aiVector3D texcoord = mesh->mTextureCoords[0][j]; for (int k = 0; k < 3; k++) { *data++ = position[k]; } for (int k = 0; k < 3; k++) { *data++ = normal[k]; } for (int k = 0; k < 2; k++) { *data++ = texcoord[k]; } for (int k = 0; k < m_boneMatrices[i][j].size(); k++) { for (int l = 0; l < 4; l++) { for (int m = 0; m < 4; m++) { *data++ = m_boneMatrices[i][j](l, m); } } } } glUnmapBuffer(GL_ARRAY_BUFFER); int positionLocation = m_program.attributeLocation("position"); glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * (3 + 3 + 2 + 4 * 4), (void*)0); glEnableVertexAttribArray(positionLocation); int normalLocation = m_program.attributeLocation("normal"); glVertexAttribPointer(normalLocation, 3, GL_FLOAT, GL_FALSE, sizeof(float) * (3 + 3 + 2 + 4 * 4), (void*)(sizeof(float) * 3)); glEnableVertexAttribArray(normalLocation); int texcoordLocation = m_program.attributeLocation("texcoord"); glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(float) * (3 + 3 + 2 + 4 * 4), (void*)(sizeof(float) * 6)); glEnableVertexAttribArray(texcoordLocation); int boneMatrixLocation = m_program.attributeLocation(QString("boneMatrix[%1]").arg(i)); for (int j = 0; j < 4; j++) { glVertexAttribPointer(boneMatrixLocation + j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * (3 + 3 + 2 + 4 * 4), (void*)(sizeof(float) * (8 + j * 4))); glEnableVertexAttribArray(boneMatrixLocation + j); glVertexAttribDivisor(boneMatrixLocation + j, 1); } } // 加载纹理 QImage image("texture.png"); glGenTextures(1, &m_texture); glBindTexture(GL_TEXTURE_2D, m_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); // 开启深度测试和面剔除 glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 计算相机矩阵和投影矩阵 QMatrix4x4 cameraMatrix; cameraMatrix.translate(0, 0, -10); QMatrix4x4 projectionMatrix; projectionMatrix.perspective(45, (float)width() / height(), 0.1f, 100.0f); // 绘制模型 m_program.bind(); m_program.setUniformValue("cameraMatrix", cameraMatrix); m_program.setUniformValue("projectionMatrix", projectionMatrix); glBindTexture(GL_TEXTURE_2D, m_texture); glBindVertexArray(m_vao); for (unsigned int i = 0; i < m_boneMatrices.size(); i++) { m_program.setUniformValue(QString("boneMatrix[%1]").arg(i), m_boneMatrices[i]); } for (unsigned int i = 0; i < m_boneMatrices.size(); i++) { aiMesh* mesh = scene->mMeshes[i]; glDrawArrays(GL_TRIANGLES, 0, mesh->mNumVertices); } } private: QOpenGLShaderProgram m_program; GLuint m_vao; GLuint m_texture; QVector<QMatrix4x4> m_boneMatrices; QVector<QVector<QMatrix4x4>> m_boneOffsets; QVector<QHash<QString, int>> m_boneMapping; }; ``` 注:这个代码示例中使用 `m_program` 对象表示 OpenGL 着色器程序,`m_vao` 表示 OpenGL 顶点数组对象,`m_texture` 表示 OpenGL 纹理对象,`m_boneMatrices` 表示骨骼矩阵,`m_boneOffsets` 表示骨骼偏移矩阵,`m_boneMapping` 表示骨骼名称到骨骼索引的映射。其中 `:/shader.vert` 和 `:/shader.frag` 是着色器程序的代码文件,`model.dae` 是包含骨骼动画的模型文件,`texture.png` 是纹理文件。

相关推荐

zip
This directory contains the Qt3D project for Qt5: * Qt3D QML bindings and * Qt3D C++ APIs Building Qt3D ================== Qt5 is a rapidly changing bleeding edge environment. This branch is our initial support for it and thus is also rapidly changing and bleeding edge. This branch is experimental, and unsupported. This information is provided for advanced use only. No guarantees about API stability or even if this works at all are supplied, use at your own risk. First fetch the Qt5 source tree and Qt3D master branch: cd ~/depot git clone ssh://codereview.qt-project.org:29418/qt/qt5.git cd qt5 ./init-repository --codereview-username \ --module-subset=qtbase,qtsvg,qtdeclarative,qttools,qtxmlpatterns,qtdoc,qlalr,qtrepotools,qtqa,qtlocation,qt3d git submodule foreach "git fetch gerrit && git reset --hard gerrit/master" cd qt3d scp -p -P 29418 codereview.qt-project.org:hooks/commit-msg .git/hooks/ git fetch gerrit git checkout --track -b master gerrit/master If you are reading this file then somehow you probably already got this far anyway. Now build Qt5, which will also build Qt3D as a module: cd ~/build mkdir qt5 cd qt5 ~/depot/qt5/configure -developer-build -opensource -confirm-license -no-webkit -no-phonon -nomake tests \ -nomake examples -declarative -opengl -svg && make -j 4 What's in Qt3D ================== Directory structure: src/threed/ This is the main library of the Qt3D project, containing abstractions for cross-platform GL, shaders, lighting models, and so on. src/plugins/ Scene format loading plugins. src/imports/ QML import plugins. util/ Various utilities that are useful when working with Qt3D. examples/ Some examples of using Qt3D QML bindings and Qt3D C++ API. demos/ Some more complex demos of using Qt3D QML bindings and Qt3D C++ API. tests/auto/qml3d/ Unit tests for the QML bindings. tests/auto/threed/ Unit tests for the C++ API doc/ Documentation. devices/symbian/ Symbian deployment file Documentation ============= The documentation can be generated with "make docs". It will be placed into "doc/html" in the build directory. Packages ======== This section is only for those developing Qt3D. Read on to discover how the building of packages works. This section is also important if you want to change how the structure of the Qt3D pro files work. To build Qt3D, run: qmake && make The .pro files will cause the toolchain to place the libraries, QML files and meshes of Qt3D directly into place, as part of the compile process. The files go into the bin/ directory, and the executables can be run directly from there. If you are doing a developer build, plugins will be installed in such a way that Qt will find them. After building the tree the install step is invoked using the INSTALL_ROOT environment export to cause the installation rules to place all the files into a sandboxed install tree, ready for packaging: INSTALL_ROOT=tmp make install Examples ======== Some examples require assimp library to parse the content. Go to http://assimp.sourceforge.net/ and build and install the assimp library. Then configure Qt3D to include assimp and run qmake && make.

最新推荐

recommend-type

什么是mysql安装配置教程以及学习mysql安装配置教程的意义

mysql安装配置教程
recommend-type

【光伏预测】基于BP神经网络实现光伏发电功率预测附Matlab代码.zip

1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
recommend-type

onlyoffice搭建及与alist使用的view.html

onlyoffice搭建及与alist使用的view.html
recommend-type

android-support-v7-recyclerview 添加错误

1.Project Structure中添加依赖时,容易添加不进去,所以使用本地添加,将android-support-v7-recyclerview放在对应项目的lib文件中,并add as library。如果在build.gradle中出现implementation files('libs\\android-support-v7-recyclerview.jar')就算是添加成功。 2.在布局文件中使用 androidx 的布局控件,在逻辑代码文件中导入androidx相关包。(取代android.support.v7) 3.在gradle.properties文件中,注释android.enableJetifier=true。(# android.enableJetifier=true) 最新way2:
recommend-type

3款正射影像DOM导入CASS插件(测试通过).rar

3款正射影像DOM导入CASS插件(测试通过),带坐标导入,超实用!
recommend-type

zigbee-cluster-library-specification

最新的zigbee-cluster-library-specification说明文档。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

【实战演练】增量式PID的simulink仿真实现

# 2.1 Simulink仿真环境简介 Simulink是MATLAB中用于建模、仿真和分析动态系统的图形化环境。它提供了一个直观的用户界面,允许用户使用块和连接线来创建系统模型。Simulink模型由以下元素组成: - **子系统:**将复杂系统分解成更小的、可管理的模块。 - **块:**代表系统中的组件,如传感器、执行器和控制器。 - **连接线:**表示信号在块之间的流动。 Simulink仿真环境提供了广泛的块库,涵盖了各种工程学科,包括控制系统、电子和机械工程。它还支持用户自定义块的创建,以满足特定仿真需求。 # 2. Simulink仿真环境的搭建和建模 ### 2.
recommend-type

训练集和测试集的准确率都99%,但是预测效果不好

即使训练集和测试集的准确率都很高,但是在实际的预测中表现不佳,可能会有以下几个原因: 1. 数据质量问题:模型训练和测试的数据可能存在问题,比如数据标签错误、数据集采样不均衡、数据集中存在异常值等问题,这些问题可能会导致模型在实际预测中表现不佳。 2. 特征工程问题:模型的特征工程可能存在问题,导致模型无法很好地捕捉数据的特征,从而影响预测效果。 3. 模型选择问题:模型的选择可能不合适,比如选择的模型太简单,无法很好地拟合数据,或者选择的模型太复杂,导致过拟合等问题。 4. 超参数调整问题:模型的超参数可能没有调整到最佳状态,需要进行调整。 针对以上可能的原因,可以采取相应的措施进
recommend-type

JSBSim Reference Manual

JSBSim参考手册,其中包含JSBSim简介,JSBSim配置文件xml的编写语法,编程手册以及一些应用实例等。其中有部分内容还没有写完,估计有生之年很难看到完整版了,但是内容还是很有参考价值的。