Qt opengl assimp加载骨骼动画
时间: 2023-10-07 14:07:30 浏览: 84
Opengl骨骼动画
5星 · 资源好评率100%
加载骨骼动画的步骤可以分为以下几个:
1. 使用Assimp库加载包含骨骼动画的模型文件,并获取动画相关的信息,比如骨骼数、关键帧数、每个关键帧的变换信息等。
2. 创建OpenGL的顶点数组对象(VAO)和顶点缓冲对象(VBO),以及索引缓冲对象(IBO)。
3. 在顶点着色器中定义顶点属性,包括位置、法线、纹理坐标和骨骼权重。
4. 在顶点着色器中定义uniform变量,用于传递骨骼变换矩阵。
5. 在渲染循环中,计算每个关键帧的骨骼变换矩阵,并将其传递给顶点着色器中的uniform变量。
6. 在顶点着色器中,根据骨骼权重计算每个顶点的最终位置和法线。
7. 使用IBO和VAO绘制模型。
下面是一个简单的实现示例:
```cpp
// 加载模型
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(filename, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace | aiProcess_LimitBoneWeights);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
// 加载失败
}
// 获取动画相关信息
const aiAnimation* animation = scene->mAnimations[0];
int numBones = animation->mNumChannels;
// 创建VAO、VBO和IBO
GLuint vao, vbo, ibo;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCoord));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, boneWeights));
glEnableVertexAttribArray(4);
glVertexAttribIPointer(4, 4, GL_INT, sizeof(Vertex), (void*)offsetof(Vertex, boneIndices));
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), &indices[0], GL_STATIC_DRAW);
// 在顶点着色器中定义顶点属性和uniform变量
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aNormal;\n"
"layout (location = 2) in vec2 aTexCoord;\n"
"layout (location = 3) in vec4 aBoneWeights;\n"
"layout (location = 4) in int aBoneIndices[4];\n"
"uniform mat4 uBoneMatrices[" + std::to_string(numBones) + "];\n"
"out vec3 vNormal;\n"
"out vec2 vTexCoord;\n"
"void main()\n"
"{\n"
" vec4 position = vec4(aPos, 1.0);\n"
" vec4 normal = vec4(aNormal, 0.0);\n"
" for (int i = 0; i < 4; i++) {\n"
" position = uBoneMatrices[aBoneIndices[i]] * vec4(aPos, 1.0) * aBoneWeights[i] + position;\n"
" normal = uBoneMatrices[aBoneIndices[i]] * vec4(aNormal, 0.0) * aBoneWeights[i] + normal;\n"
" }\n"
" gl_Position = projection * view * model * position;\n"
" vNormal = normalize(normal.xyz);\n"
" vTexCoord = aTexCoord;\n"
"}\n";
// 在渲染循环中计算骨骼变换矩阵,并传递给顶点着色器
for (int i = 0; i < numBones; i++) {
aiNodeAnimation* nodeAnim = animation->mChannels[i];
std::string boneName = nodeAnim->mNodeName.C_Str();
aiMatrix4x4 boneOffset = m_BoneOffsets[boneName];
aiMatrix4x4 boneTransform = m_AnimatedTransforms[boneName];
aiMatrix4x4 globalTransform = m_GlobalInverseTransform * boneTransform * boneOffset;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, ("uBoneMatrices[" + std::to_string(i) + "]").c_str()), 1, GL_TRUE, (float*)&globalTransform);
}
// 在顶点着色器中根据骨骼权重计算每个顶点的最终位置和法线
const char* fragmentShaderSource =
"#version 330 core\n"
"in vec3 vNormal;\n"
"in vec2 vTexCoord;\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" vec3 diffuse = texture(diffuseMap, vTexCoord).rgb;\n"
" vec3 normal = normalize(vNormal);\n"
" FragColor = vec4(diffuse * (0.5 + 0.5 * max(dot(normal, lightDir), 0.0)), 1.0);\n"
"}\n";
```
阅读全文