Веса вершин рендерятся неверно в OpenGL

Рейтинг: 0Ответов: 0Опубликовано: 06.07.2023

Так выглядят веса в моем приложении Так выглядят веса в моем приложении

Так веса выглядят в Blender Так веса выглядят в Blender

Можно заметить, что мой куб имеет зеленые точки внизу, а в Blender — нет. Я хочу понять, в чем проблема с моими весами, может быть проблема с тем, как я храню свои данные. Помогите пожалуйста найти ошибку!

Ниже я приведу некоторые обязательные части кода и ссылку на весь проект, чтобы можно было четко понять и воспроизвести проблему.

Ссылка: https://github.com/theoldestsc/PyrhonScratch

Обязательные части кода:

Вот так я загружаю Mesh (у меня есть класс Model, который содержит vector<Mesh>, и у меня есть отдельный vector<Vertex> для каждого Mesh)

Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene)
{
    std::vector<Vertex> vertices;
    std::vector<unsigned int> indices;
    std::vector<Texture> textures;

    for(unsigned int vIdx = 0; vIdx < mesh->mNumVertices; vIdx++)
    {
        Vertex vertex;
        QVector3D vector;
        
        vector.setX(mesh->mVertices[vIdx].x);
        vector.setY(mesh->mVertices[vIdx].y);
        vector.setZ(mesh->mVertices[vIdx].z);
        vertex.position = vector;
        
        if (mesh->HasNormals())
        {
            vector.setX(mesh->mNormals[vIdx].x);
            vector.setY(mesh->mNormals[vIdx].y);
            vector.setZ(mesh->mNormals[vIdx].z);
            vertex.normal = vector;
        }
        if(mesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
        {
            QVector2D vec;
            vec.setX(mesh->mTextureCoords[0][vIdx].x);
            vec.setY(mesh->mTextureCoords[0][vIdx].y);
            vertex.texcoord = vec;
        }
        else
            vertex.texcoord = QVector2D(0.0f, 0.0f);

        vertices.push_back(vertex);
    }

    for(unsigned int fIdx = 0; fIdx < mesh->mNumFaces; fIdx++)
    {
        aiFace face = mesh->mFaces[fIdx];
        for(unsigned int j = 0; j < face.mNumIndices; j++)
        {
            indices.push_back(face.mIndices[j]);
        }
    }

    if(mesh->mMaterialIndex >= 0)
    {
        aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
        std::vector<Texture> diffuseMaps = loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse");
        textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
        std::vector<Texture> specularMaps = loadMaterialTextures(material, aiTextureType_SPECULAR, "texture_specular");
        textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
    }
    //TODO:Print status of mesh loading(Which mesh, path, number, sizes, bones)
    if(mesh->HasBones())
    {

        qDebug() << "Bones processing ...";
        for(int boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex)
        {
            auto bone = mesh->mBones[boneIndex];

            std::string name = bone->mName.C_Str();
            int index = -1;
            if (boneIndexMap.find(name) == boneIndexMap.end()) {
                index = bones.size();
                Bone newBone;
                newBone.name = name;
                newBone.offsetMatrix = aiToQt(bone->mOffsetMatrix);
                bones.push_back(newBone);
                boneIndexMap[name] = index;
            } else {
                index = boneIndexMap[name];
            }

            for(int i = 0; i < bone->mNumWeights; ++i)
            {
                auto weightInfo = bone->mWeights[i];
                auto vertexId = weightInfo.mVertexId;
                auto weight = weightInfo.mWeight;

                for(int k = 0; k < WEIGHTS_PER_VERTEX; ++k)
                {
                    if(vertices.at(vertexId).weight[k] == 0.0)
                    {
                        vertices.at(vertexId).id[k] = index;
                        vertices.at(vertexId).weight[k] = weight;
                        break;
                    }
                }

            }
        }

    }
    qDebug() << vertices.size() << " " << mesh->mNumFaces << " Bones data: " << boneIndexMap.size() << " " << bones.size() << "\n";
    return Mesh(vertices, indices, textures, bones);
}

Вот так я отправляю данные в OpenGL

void Mesh::setupMesh()
{
    auto functions = QOpenGLContext::currentContext()->functions();
    auto extraFunctions = QOpenGLContext::currentContext()->extraFunctions();
    
    VAO = std::shared_ptr<QOpenGLVertexArrayObject>(new QOpenGLVertexArrayObject());
    VBO = std::shared_ptr<QOpenGLBuffer>(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer));
    EBO = std::shared_ptr<QOpenGLBuffer>(new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer));

    VAO->create();
    VBO->create();
    EBO->create();

    VAO->bind();

    VBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
    EBO->setUsagePattern(QOpenGLBuffer::StaticDraw);
    VBO->bind();
    VBO->allocate(vertices.data(), vertices.size() * sizeof(Vertex));
    EBO->bind();
    EBO->allocate(indices.data(), indices.size() * sizeof(unsigned int));
    
    functions->glEnableVertexAttribArray(0);
    functions->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    
    functions->glEnableVertexAttribArray(1);
    functions->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
                                    (void*)offsetof(Vertex, normal));

    functions->glEnableVertexAttribArray(2);
    functions->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 
                                    (void*)offsetof(Vertex, texcoord));
    
    functions->glEnableVertexAttribArray(3);
    functions->glVertexAttribPointer(3, WEIGHTS_PER_VERTEX, GL_FLOAT, GL_TRUE, sizeof(Vertex), 
                                    (void*)offsetof(Vertex, weight));

    functions->glEnableVertexAttribArray(4);
    functions->glVertexAttribPointer(4, WEIGHTS_PER_VERTEX, GL_UNSIGNED_INT, GL_FALSE, sizeof(Vertex), 
                                    (void*)offsetof(Vertex, id));
                                    
    extraFunctions->glBindVertexArray(0);
}

В структуре Vertex я храню 4 веса для каждой вершины, затем отправляю вектор этих вершин в OpenGL.

#define WEIGHTS_PER_VERTEX  4
struct Vertex
{
    QVector3D position;
    QVector2D texcoord;
    QVector3D normal;

    float weight[WEIGHTS_PER_VERTEX] = {0.0f, 0.0f, 0.0f, 0.0f};
    unsigned int id[WEIGHTS_PER_VERTEX] = {0, 0, 0, 0};

};

Структура Bone

struct Bone {
    std::string name; //Only this field is used
    int parentIndex;

    QMatrix4x4 offsetMatrix; //Only this field is used
    QMatrix4x4 finalTransform;
};

Мой vertex shader:

#version 440

const int MAX_BONES = 100;

layout (location = 0) in vec3 vertex_position;
layout (location = 1) in vec3 vertex_normal;
layout (location = 2) in vec2 vertex_texcoord;



layout (location = 3) in vec4 weights;
layout (location = 4) in ivec4 s_vIDs;


uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;

uniform mat4 gBones[MAX_BONES];

out vec2 TexCoords;
out vec4 we;
out vec4 id;
out vec3 interpolatedNormal;

void main()
{
    TexCoords = vertex_texcoord;

    vec4 totalPosition = vec4(0.0f);
    for(int i = 0 ; i < 4 ; i++)
    {
        if(s_vIDs[i] == -1) 
            continue;
        if(s_vIDs[i] >= MAX_BONES) 
        {
            totalPosition = vec4(vertex_position, 1.0f);
            break;
        }
        vec4 localPosition = gBones[s_vIDs[i]] * vec4(vertex_position, 1.0f);
        totalPosition += localPosition * weights[i];
    }
    
    interpolatedNormal = normalize(mat3(transpose(inverse(ModelMatrix))) * vertex_normal);

    mat4 viewModel = ViewMatrix * ModelMatrix;
    gl_Position = ProjectionMatrix * viewModel * totalPosition;
    we = weights;
    id = s_vIDs;

}

Мой fragment shader:

#version 440
out vec4 FragColor;
in vec4 we;
in vec4 id;
in vec3 interpolatedNormal;
in vec2 TexCoords;

struct Material {
    sampler2D texture_diffuse1;
};

uniform Material material;

void main()
{    
    FragColor = we;
}

Просто хочу быть уверен, что моя анимация в будущем будет работать правильно, поэтому я хочу исправить эту ошибку, пока мой код не станет больше. Может быть проблема с моим пониманием того, как Blender и OpenGL визуализируют данные весов В общем, я бы хотел достичь аналогичного результата с Blender, чтобы в дальнейшем было проще проверять работу программы

Ответы

Ответов пока нет.