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

时间: 2023-07-09 08:03:22 浏览: 57
这里是一个简单的使用Qt、OpenGL和Assimp库加载带有骨骼动画的模型的示例代码: ```cpp #include <QOpenGLFunctions> #include <QOpenGLWidget> #include <QOpenGLShaderProgram> #include <QOpenGLBuffer> #include <QOpenGLTexture> #include <QMouseEvent> #include <QWheelEvent> #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) { setFocusPolicy(Qt::StrongFocus); } ~GLWidget() { makeCurrent(); m_shaderProgram.release(); m_vbo.destroy(); m_ibo.destroy(); m_vao.destroy(); doneCurrent(); } protected: void initializeGL() override { initializeOpenGLFunctions(); m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vertex.glsl"); m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fragment.glsl"); m_shaderProgram.link(); loadModel(":/models/model.dae"); glEnable(GL_DEPTH_TEST); glClearColor(0.2f, 0.2f, 0.2f, 1.0f); } void resizeGL(int width, int height) override { glViewport(0, 0, width, height); } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_shaderProgram.bind(); m_shaderProgram.setUniformValue("mvpMatrix", m_projMatrix * m_cameraMatrix * m_modelMatrix); m_vao.bind(); glDrawElements(GL_TRIANGLES, m_indices.size(), GL_UNSIGNED_INT, nullptr); m_vao.release(); } void mousePressEvent(QMouseEvent *event) override { m_lastPos = event->pos(); } void mouseMoveEvent(QMouseEvent *event) override { if (event->buttons() & Qt::LeftButton) { int dx = event->x() - m_lastPos.x(); int dy = event->y() - m_lastPos.y(); m_cameraYaw += dx * 0.01f; m_cameraPitch += dy * 0.01f; if (m_cameraPitch > 1.5f) m_cameraPitch = 1.5f; else if (m_cameraPitch < -1.5f) m_cameraPitch = -1.5f; updateCameraMatrix(); m_lastPos = event->pos(); update(); } } void wheelEvent(QWheelEvent *event) override { m_cameraDistance -= event->delta() * 0.01f; if (m_cameraDistance < 0.1f) m_cameraDistance = 0.1f; updateCameraMatrix(); update(); } private: void loadModel(const QString &filePath) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(filePath.toStdString(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_LimitBoneWeights); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { qDebug() << "Error: " << importer.GetErrorString(); return; } m_boneMatrices.resize(scene->mNumMeshes); aiMatrix4x4 globalTransform = scene->mRootNode->mTransformation; globalTransform.Inverse(); loadNode(scene->mRootNode, scene, globalTransform); m_vao.create(); m_vao.bind(); m_vbo.create(); m_vbo.bind(); m_vbo.allocate(m_vertices.data(), m_vertices.size() * sizeof(Vertex)); m_shaderProgram.enableAttributeArray("position"); m_shaderProgram.setAttributeBuffer("position", GL_FLOAT, offsetof(Vertex, position), 3, sizeof(Vertex)); m_shaderProgram.enableAttributeArray("normal"); m_shaderProgram.setAttributeBuffer("normal", GL_FLOAT, offsetof(Vertex, normal), 3, sizeof(Vertex)); m_shaderProgram.enableAttributeArray("texcoord"); m_shaderProgram.setAttributeBuffer("texcoord", GL_FLOAT, offsetof(Vertex, texcoord), 2, sizeof(Vertex)); m_shaderProgram.enableAttributeArray("boneIndices"); m_shaderProgram.setAttributeBuffer("boneIndices", GL_FLOAT, offsetof(Vertex, boneIndices), 4, sizeof(Vertex)); m_shaderProgram.enableAttributeArray("boneWeights"); m_shaderProgram.setAttributeBuffer("boneWeights", GL_FLOAT, offsetof(Vertex, boneWeights), 4, sizeof(Vertex)); m_ibo.create(); m_ibo.bind(); m_ibo.allocate(m_indices.data(), m_indices.size() * sizeof(unsigned int)); m_vao.release(); } void loadNode(aiNode *node, const aiScene *scene, const aiMatrix4x4 &parentTransform) { aiMatrix4x4 transform = parentTransform * node->mTransformation; for (unsigned int i = 0; i < node->mNumMeshes; ++i) { aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; for (unsigned int j = 0; j < mesh->mNumBones; ++j) { aiBone *bone = mesh->mBones[j]; QString boneName = QString::fromStdString(bone->mName.C_Str()); if (m_boneMapping.find(boneName) == m_boneMapping.end()) { int boneIndex = m_boneMapping.size(); m_boneMapping[boneName] = boneIndex; m_boneInfo.push_back(BoneInfo{transform * bone->mOffsetMatrix, QMatrix4x4()}); } } for (unsigned int j = 0; j < mesh->mNumFaces; ++j) { aiFace &face = mesh->mFaces[j]; for (unsigned int k = 0; k < face.mNumIndices; ++k) m_indices.push_back(face.mIndices[k]); } for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { Vertex vertex; vertex.position = QVector3D(mesh->mVertices[j].x, mesh->mVertices[j].y, mesh->mVertices[j].z); vertex.normal = QVector3D(mesh->mNormals[j].x, mesh->mNormals[j].y, mesh->mNormals[j].z); if (mesh->mTextureCoords[0]) { vertex.texcoord = QVector2D(mesh->mTextureCoords[0][j].x, mesh->mTextureCoords[0][j].y); } else { vertex.texcoord = QVector2D(0.0f, 0.0f); } for (unsigned int k = 0; k < 4; ++k) { vertex.boneIndices[k] = -1; vertex.boneWeights[k] = 0.0f; } for (unsigned int k = 0; k < mesh->mNumBones; ++k) { aiBone *bone = mesh->mBones[k]; QString boneName = QString::fromStdString(bone->mName.C_Str()); if (m_boneMapping.find(boneName) != m_boneMapping.end()) { int boneIndex = m_boneMapping[boneName]; vertex.boneIndices[k] = boneIndex; vertex.boneWeights[k] = bone->mWeights[j].mWeight; } } m_vertices.push_back(vertex); } } for (unsigned int i = 0; i < node->mNumChildren; ++i) { loadNode(node->mChildren[i], scene, transform); } } void updateBoneMatrices(aiNode *node, const QMatrix4x4 &parentMatrix) { QString nodeName = QString::fromStdString(node->mName.C_Str()); if (m_boneMapping.find(nodeName) != m_boneMapping.end()) { int boneIndex = m_boneMapping[nodeName]; m_boneInfo[boneIndex].finalTransform = parentMatrix * m_boneInfo[boneIndex].offsetMatrix * m_boneInfo[boneIndex].boneTransform; m_boneMatrices[boneIndex] = m_boneInfo[boneIndex].finalTransform * m_boneInfo[boneIndex].boneOffset; } QMatrix4x4 transform; transform(0, 0) = node->mTransformation.a1; transform(1, 0) = node->mTransformation.a2; transform(2, 0) = node->mTransformation.a3; transform(3, 0) = node->mTransformation.a4; transform(0, 1) = node->mTransformation.b1; transform(1, 1) = node->mTransformation.b2; transform(2, 1) = node->mTransformation.b3; transform(3, 1) = node->mTransformation.b4; transform(0, 2) = node->mTransformation.c1; transform(1, 2) = node->mTransformation.c2; transform(2, 2) = node->mTransformation.c3; transform(3, 2) = node->mTransformation.c4; transform(0, 3) = node->mTransformation.d1; transform(1, 3) = node->mTransformation.d2; transform(2, 3) = node->mTransformation.d3; transform(3, 3) = node->mTransformation.d4; QMatrix4x4 combinedTransform = parentMatrix * transform; for (unsigned int i = 0; i < node->mNumChildren; ++i) { updateBoneMatrices(node->mChildren[i], combinedTransform); } } void updateCameraMatrix() { m_cameraMatrix.setToIdentity(); m_cameraMatrix.translate(0.0f, 0.0f, -m_cameraDistance); m_cameraMatrix.rotate(m_cameraPitch, QVector3D(1.0f, 0.0f, 0.0f)); m_cameraMatrix.rotate(m_cameraYaw, QVector3D(0.0f, 1.0f, 0.0f)); } void updateAnimation(float deltaTime) { m_animationTime += deltaTime; if (m_animationTime > m_animationDuration) m_animationTime -= m_animationDuration; aiMatrix4x4 identity; identity.SetIdentity(); updateBoneMatrices(m_scene->mRootNode, identity); for (int i = 0; i < m_boneMatrices.size(); ++i) { m_shaderProgram.setUniformValue(QString("boneMatrices[%1]").arg(i), m_boneMatrices[i]); } } QOpenGLShaderProgram m_shaderProgram; QOpenGLBuffer m_vbo; QOpenGLBuffer m_ibo; QOpenGLVertexArrayObject m_vao; QVector<Vertex> m_vertices; QVector<unsigned int> m_indices; QMap<QString, int> m_boneMapping; QVector<BoneInfo> m_boneInfo; QVector<QMatrix4x4> m_boneMatrices; const aiScene *m_scene = nullptr; float m_animationTime = 0.0f; float m_animationDuration = 0.0f; float m_cameraYaw = 0.0f; float m_cameraPitch = 0.0f; float m_cameraDistance = 5.0f; QVector3D m_cameraPosition; QMatrix4x4 m_cameraMatrix; QMatrix4x4 m_modelMatrix; QMatrix4x4 m_projMatrix; QPoint m_lastPos; struct Vertex { QVector3D position; QVector3D normal; QVector2D texcoord; QVector4D boneIndices; QVector4D boneWeights; }; struct BoneInfo { aiMatrix4x4 offsetMatrix; QMatrix4x4 boneTransform; QMatrix4x4 finalTransform; QMatrix4x4 boneOffset; }; }; ``` 其中,`loadModel`函数用于加载模型,`loadNode`函数用于递归加载节点和骨骼信息,`updateBoneMatrices`函数用于更新骨骼变换矩阵,`updateAnimation`函数用于更新动画播放进度和骨骼变换矩阵,`updateCameraMatrix`函数用于更新摄像机变换矩阵。在`initializeGL`函数中调用`loadModel`函数进行模型加载,在`paintGL`函数中进行渲染。 需要注意的是,这里使用了Assimp库来加载带有骨骼动画的模型,并且使用了Qt的OpenGL相关类来进行渲染。如果要使用这段代码,请确保已经正确安装了Qt和Assimp库,并且已经将模型文件和着色器文件添加到了项目中。

相关推荐

最新推荐

recommend-type

node-v0.8.10-sunos-x64.tar.gz

Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
recommend-type

【课程设计】实现的金融风控贷款违约预测python源码.zip

【课程设计】实现的金融风控贷款违约预测python源码.zip
recommend-type

node-v0.10.27-x86.msi

Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
recommend-type

课设毕设基于SSM的高校二手交易平台-LW+PPT+源码可运行.zip

课设毕设基于SSM的高校二手交易平台--LW+PPT+源码可运行
recommend-type

c++,冒险游戏,可供学习

冒险游戏,可供学习
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

实现实时数据湖架构:Kafka与Hive集成

![实现实时数据湖架构:Kafka与Hive集成](https://img-blog.csdnimg.cn/img_convert/10eb2e6972b3b6086286fc64c0b3ee41.jpeg) # 1. 实时数据湖架构概述** 实时数据湖是一种现代数据管理架构,它允许企业以低延迟的方式收集、存储和处理大量数据。与传统数据仓库不同,实时数据湖不依赖于预先定义的模式,而是采用灵活的架构,可以处理各种数据类型和格式。这种架构为企业提供了以下优势: - **实时洞察:**实时数据湖允许企业访问最新的数据,从而做出更明智的决策。 - **数据民主化:**实时数据湖使各种利益相关者都可
recommend-type

SPDK_NVMF_DISCOVERY_NQN是什么 有什么作用

SPDK_NVMF_DISCOVERY_NQN 是 SPDK (Storage Performance Development Kit) 中用于查询 NVMf (Non-Volatile Memory express over Fabrics) 存储设备名称的协议。NVMf 是一种基于网络的存储协议,可用于连接远程非易失性内存存储器。 SPDK_NVMF_DISCOVERY_NQN 的作用是让存储应用程序能够通过 SPDK 查询 NVMf 存储设备的名称,以便能够访问这些存储设备。通过查询 NVMf 存储设备名称,存储应用程序可以获取必要的信息,例如存储设备的IP地址、端口号、名称等,以便能
recommend-type

JSBSim Reference Manual

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