Как предоставить 14 значений с плавающей точкой на вершину шейдеру? - PullRequest
0 голосов
/ 15 февраля 2019

Я скачал модель и экспортировал ее как .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 весов?Может ли это быть причиной неработающей анимации?

...