qt opengl assimp 加载骨骼动画完整代码
时间: 2023-07-09 19:03:21 浏览: 52
以下是一个简单的示例代码,使用 Qt、OpenGL 和 Assimp 库加载带有骨骼动画的模型:
```cpp
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QMatrix4x4>
#include <QKeyEvent>
#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();
glEnable(GL_DEPTH_TEST);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
program.addShaderFromSourceFile(QOpenGLShader::Vertex, "vertex_shader.glsl");
program.addShaderFromSourceFile(QOpenGLShader::Fragment, "fragment_shader.glsl");
program.link();
program.bind();
positionAttr = program.attributeLocation("positionAttr");
normalAttr = program.attributeLocation("normalAttr");
matrixUniform = program.uniformLocation("matrixUniform");
boneMatricesUniform = program.uniformLocation("boneMatricesUniform");
loadModel("model.dae");
timer.start(16, this);
}
void resizeGL(int w, int h) override {
glViewport(0, 0, w, h);
projectionMatrix.setToIdentity();
projectionMatrix.perspective(45.0f, (float)w/h, 0.1f, 100.0f);
}
void paintGL() override {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
program.bind();
program.setUniformValue(matrixUniform, projectionMatrix * viewMatrix * modelMatrix);
program.setUniformValueArray(boneMatricesUniform, boneMatrices.data(), boneMatrices.size());
for (const auto &mesh : meshes) {
mesh.buffer.bind();
program.setAttributeBuffer(positionAttr, GL_FLOAT, 0, 3, sizeof(Vertex));
program.enableAttributeArray(positionAttr);
program.setAttributeBuffer(normalAttr, GL_FLOAT, sizeof(QVector3D), 3, sizeof(Vertex));
program.enableAttributeArray(normalAttr);
glDrawElements(GL_TRIANGLES, mesh.indices.count(), GL_UNSIGNED_INT, nullptr);
mesh.buffer.release();
}
}
void keyPressEvent(QKeyEvent *event) override {
switch (event->key()) {
case Qt::Key_W: viewMatrix.translate(0, 0, -0.1f); break;
case Qt::Key_S: viewMatrix.translate(0, 0, 0.1f); break;
case Qt::Key_A: viewMatrix.translate(-0.1f, 0, 0); break;
case Qt::Key_D: viewMatrix.translate(0.1f, 0, 0); break;
case Qt::Key_Q: viewMatrix.translate(0, -0.1f, 0); break;
case Qt::Key_E: viewMatrix.translate(0, 0.1f, 0); break;
case Qt::Key_R: viewMatrix.setToIdentity(); break;
}
update();
}
void timerEvent(QTimerEvent *event) override {
if (event->timerId() == timer.timerId()) {
float time = timer.elapsed() / 1000.0f;
updateBones(scene->mRootNode, time);
update();
}
}
private:
struct Vertex {
QVector3D position;
QVector3D normal;
};
struct Mesh {
QVector<Vertex> vertices;
QVector<uint> indices;
QOpenGLBuffer buffer;
};
void loadModel(const QString &filePath) {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(filePath.toUtf8().constData(), aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_LimitBoneWeights);
if (!scene) {
qCritical() << "Failed to load model:" << importer.GetErrorString();
return;
}
this->scene = scene;
loadBones(scene->mRootNode, QMatrix4x4());
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
const aiMesh *mesh = scene->mMeshes[i];
Mesh newMesh;
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);
newMesh.vertices.append(vertex);
}
for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
const aiFace &face = mesh->mFaces[j];
for (unsigned int k = 0; k < face.mNumIndices; ++k)
newMesh.indices.append(face.mIndices[k]);
}
newMesh.buffer.create();
newMesh.buffer.bind();
newMesh.buffer.allocate(newMesh.vertices.data(), newMesh.vertices.count() * sizeof(Vertex));
QOpenGLBuffer indexBuffer(QOpenGLBuffer::IndexBuffer);
indexBuffer.create();
indexBuffer.bind();
indexBuffer.allocate(newMesh.indices.data(), newMesh.indices.count() * sizeof(uint));
newMesh.buffer.release();
meshes.append(newMesh);
}
}
void loadBones(aiNode *node, const QMatrix4x4 &parentTransform) {
QMatrix4x4 nodeTransform(node->mTransformation[0], node->mTransformation[1], node->mTransformation[2], node->mTransformation[3],
node->mTransformation[4], node->mTransformation[5], node->mTransformation[6], node->mTransformation[7],
node->mTransformation[8], node->mTransformation[9], node->mTransformation[10], node->mTransformation[11],
node->mTransformation[12], node->mTransformation[13], node->mTransformation[14], node->mTransformation[15]);
QMatrix4x4 globalTransform = parentTransform * nodeTransform;
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
const aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
for (unsigned int j = 0; j < mesh->mNumBones; ++j) {
const aiBone *bone = mesh->mBones[j];
QString boneName(bone->mName.data);
if (!boneMapping.contains(boneName)) {
boneMapping.insert(boneName, boneMatrices.count());
boneMatrices.append(QMatrix4x4());
}
boneInfos.append({boneMapping[boneName], globalTransform * QMatrix4x4(bone->mOffsetMatrix[0], bone->mOffsetMatrix[1], bone->mOffsetMatrix[2], bone->mOffsetMatrix[3],
bone->mOffsetMatrix[4], bone->mOffsetMatrix[5], bone->mOffsetMatrix[6], bone->mOffsetMatrix[7],
bone->mOffsetMatrix[8], bone->mOffsetMatrix[9], bone->mOffsetMatrix[10], bone->mOffsetMatrix[11],
bone->mOffsetMatrix[12], bone->mOffsetMatrix[13], bone->mOffsetMatrix[14], bone->mOffsetMatrix[15])});
}
}
for (unsigned int i = 0; i < node->mNumChildren; ++i)
loadBones(node->mChildren[i], globalTransform);
}
void updateBones(aiNode *node, float time, const QMatrix4x4 &parentTransform = QMatrix4x4()) {
QString nodeName(node->mName.data);
QMatrix4x4 nodeTransform(node->mTransformation[0], node->mTransformation[1], node->mTransformation[2], node->mTransformation[3],
node->mTransformation[4], node->mTransformation[5], node->mTransformation[6], node->mTransformation[7],
node->mTransformation[8], node->mTransformation[9], node->mTransformation[10], node->mTransformation[11],
node->mTransformation[12], node->mTransformation[13], node->mTransformation[14], node->mTransformation[15]);
QMatrix4x4 globalTransform = parentTransform * nodeTransform;
if (boneMapping.contains(nodeName)) {
int boneIndex = boneMapping[nodeName];
boneMatrices[boneIndex] = globalTransform * boneInfos[boneIndex].offsetMatrix * boneInfos[boneIndex].finalMatrix;
}
for (unsigned int i = 0; i < node->mNumChildren; ++i)
updateBones(node->mChildren[i], time, globalTransform);
}
private:
QOpenGLShaderProgram program;
int positionAttr;
int normalAttr;
int matrixUniform;
int boneMatricesUniform;
QVector<Mesh> meshes;
QMatrix4x4 projectionMatrix;
QMatrix4x4 viewMatrix;
QMatrix4x4 modelMatrix;
QHash<QString, int> boneMapping;
QVector<QMatrix4x4> boneMatrices;
QVector<struct BoneInfo> boneInfos;
const aiScene *scene;
QTimer timer;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
GLWidget widget;
widget.resize(800, 600);
widget.show();
return app.exec();
}
```
其中,`loadModel` 函数加载模型,`loadBones` 函数加载骨骼信息,`updateBones` 函数在每一帧中更新骨骼变换矩阵。可以自行编写着色器文件 `vertex_shader.glsl` 和 `fragment_shader.glsl`。
相关推荐
![rar](https://img-home.csdnimg.cn/images/20210720083606.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![rar](https://img-home.csdnimg.cn/images/20210720083606.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)