Веса вершин рендерятся неверно в OpenGL
Так выглядят веса в моем приложении
Можно заметить, что мой куб имеет зеленые точки внизу, а в 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, чтобы в дальнейшем было проще проверять работу программы