Я скачал модель и экспортировал ее как .fbx
.Модель содержит несколько анимаций (6, если быть точным), и я хочу, чтобы одна из них отображалась.После книги Антона Герделана по openGL я написал импортер, который использует assimp для анализа модели, буферизует соответствующие данные вершин и извлекает матрицы смещения, необходимые для анимации.
Не имея большого опытасо скелетной анимацией, я думаю Я смог внести необходимые изменения в импортер антона, чтобы он мог работать на более сложной модели, которая мне нужна.Однако импортер предполагает, что на каждую вершину влияет только 1 кость, что, к сожалению, не так.
После некоторой обработки я выяснил, что на каждую вершину модели может влиять не более 14 костей ввремя.Так как я не уверен, как я мог бы передать 14 значений шейдеру, содержащему boneId
и соответствующий weight
, я попытался изменить код для размещения до 4 костей одновременно.Это код, который анализирует идентификатор кости и веса и буферизирует их:
*bone_count = (int)mesh->mNumBones;
char bone_names[256][64];
struct vertexdata {
int IDs[4];
float Weights[4];
int ptr;
};
vector<vertexdata> vdata;
vdata.resize(*point_count);
for (int i = 0; i < *point_count; i++) {
vdata[i].ptr = 0;
}
for (int b_i = 0; b_i < *bone_count; b_i++) {
const aiBone* bone = mesh->mBones[b_i];
strcpy(bone_names[b_i], bone->mName.data);
printf("bone_names[%i]=%s\n", b_i, bone_names[b_i]);
bone_offset_mats[b_i] = convert_assimp_matrix(bone->mOffsetMatrix);
//getting weights for each bone
int num_weights = (int)bone->mNumWeights;
for (int w_i = 0; w_i < num_weights; w_i++) {
aiVertexWeight weight = bone->mWeights[w_i];
int vid = weight.mVertexId;
float vweight = weight.mWeight;
if (vdata[vid].ptr < 4) {
vdata[vid].IDs[vdata[vid].ptr] = b_i;
vdata[vid].Weights[vdata[vid].ptr] = vweight;
vdata[vid].ptr++;
}
int vertex_id = (int)weight.mVertexId;
}
}
//buffering bone id data
GLuint vbo1;
glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER, sizeof(vdata[0]) * vdata.size(), &vdata[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(3);
glVertexAttribIPointer(3, 4, GL_INT, sizeof(vertexdata), (const GLvoid*)0);
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(vertexdata), (const GLvoid*)16);
и в шейдерах:
вершинный шейдер
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 norm;
layout (location = 2) in vec2 UV;
layout (location = 3) in ivec4 boneIDs;
layout (location = 4) in vec4 Weights;
uniform mat4 view, projection, model;
uniform mat4 bone_matrices[40];
out vec2 tCoords;
void main()
{
mat4 boneTransform = bone_matrices[boneIDs[0]] * Weights[0];
boneTransform += bone_matrices[boneIDs[1]] * Weights[1];
boneTransform += bone_matrices[boneIDs[2]] * Weights[2];
boneTransform += bone_matrices[boneIDs[3]] * Weights[3];
tCoords = UV;
gl_Position = projection * view * boneTransform * model * vec4(pos, 1.0);
}
фрагментный шейдер
#version 330 core
in vec2 tCoords;
out vec4 fragColour;
uniform sampler2D tex;
void main()
{
fragColour = texture(tex, tCoords);
}
Модель отображается правильно, но я не наблюдаю никаких движений.Опять же, не зная много о скелетной анимации, я могу предположить, что это потому, что я не включил каждую кость, которая влияет на каждую вершину, и соответствующий вес.Однако при буферизации данных шейдеры принимают только до vec4
или 4 значения на вершину.Как я могу пройти 14 ID и 14 весов?Может ли это быть причиной неработающей анимации?