I am beating my head on making an attempt to get {hardware} skinning moving into my engine.
We’re utilizing OZZ Animation and TinyGLTF collectively to animate fashions.
The problem appears to both stem from how OZZ maps their joint id’s vs how I seize them out of the .gltf file utilizing TinyGLTF or how the inverse bind poses are mapped when loading the .gltf file.
When loading a mannequin, we map joint names to id’s and seize the bind poses:
for (size_t i = 0; i < mannequin.skins.measurement(); i++)
{
tinygltf::Pores and skin _Skin = mannequin.skins[i];
for (auto& JointID : _Skin.joints)
{
std::string NodeName = mannequin.nodes[JointID].identify;
Infos->JointMap_[NodeName] = JointID - _Skin.skeleton;
}
if (_Skin.inverseBindMatrices > -1)
{
const tinygltf::Accessor& acc = mannequin.accessors[_Skin.inverseBindMatrices];
const tinygltf::BufferView& bufview = mannequin.bufferViews[acc.bufferView];
const tinygltf::Buffer& buf = mannequin.buffers[bufview.buffer];
Infos->InverseBindMatrices.resize(acc.depend);
memcpy(Infos->InverseBindMatrices.information(), &buf.information[acc.byteOffset + bufview.byteOffset], acc.depend * sizeof(glm::mat4));
break;
}
}
Infos
is only a struct that holds our loaded mannequin information.
Infos->JointMap_
is std::map<std::string, uint16_t> JointMap_ = {};
Infos->InverseBindMatrices
is std::vector<glm::mat4> InverseBindMatrices = {};
We cross our Infos construction off and later when rendering the thing, we use the info to animate our mannequin:
auto joints = skeleton_.num_joints();
for (int i = 0; i < joints; i++)
{
const char* OZZ_JointName = skeleton_.joint_names()[i];
uint16_t GLFW_JointIndex = _GLTFJointMap[OZZ_JointName];
glm::mat4 OZZ_Matrix = to_mat4(models_[i]);
glm::mat4 GLFW_Matrix = InverseBindMatrices_[GLFW_JointIndex];
if (_Mesh->bAnimated && i < 32)
{
_Mesh->instanceData_Animation[instanceIndex].bones[GLFW_JointIndex] = OZZ_Matrix * GLFW_Matrix;
}
}
Iterate by means of all of the joints in our skeleton.
For every joint get the joint identify.
From this identify get the gltf joint index.
Take the ozz mannequin area animation matrix and multiply it with the gltf inverse bind pose, and replace every bone on our mannequin to carry the computed matrix.
The info is uploaded to our vertex shader and used to show the animated mannequin:
#model 450
structure(location = 0) in vec4 inPosition;
//structure(location = 1) in vec3 inColor;
structure(location = 2) in vec2 inTexCoord;
structure(location = 3) in vec3 inNormal;
structure(location = 4) in vec3 inTangent;
structure(location = 5) in vec4 inBones;
structure(location = 6) in vec4 inWeights;
structure(std140, binding = 0) readonly buffer InstanceData {
mat4 mannequin[];
} ssbo;
structure (binding = 1) uniform UBO {
mat4 view_proj;
} ubo;
structure(std140, binding = 2) readonly buffer InstanceData_Animated {
mat4 Matrices[32];
} Joint[];
structure(location = 0) out vec3 outNormal;
structure(location = 1) out vec2 outUV;
//structure(location = 2) out vec3 outColor;
structure(location = 3) out vec4 outWorldPos;
structure(location = 4) out vec3 outTangent;
void important() {
outWorldPos = ssbo.mannequin[gl_InstanceIndex] * inPosition;
outUV = inTexCoord;
//outColor = inColor;
mat4 skinMat =
inWeights.x * Joint[0].Matrices[int(inBones.x)] +
inWeights.y * Joint[0].Matrices[int(inBones.y)] +
inWeights.z * Joint[0].Matrices[int(inBones.z)] +
inWeights.w * Joint[0].Matrices[int(inBones.w)];
//gl_Position = ubo.view_proj * ssbo.mannequin[gl_InstanceIndex] * inPosition;
gl_Position = ubo.view_proj * ssbo.mannequin[gl_InstanceIndex] * skinMat * inPosition;
mat3 mNormal = transpose(inverse(mat3(ssbo.mannequin[gl_InstanceIndex])));
outNormal = mNormal * normalize(inNormal);
outTangent = mNormal * normalize(inTangent);
}
Which finally ends up giving us one thing like this:
When it ought to appear to be this:
(not my screenshots, used as an instance the problem).
My shader code ought to be high quality. If I painstakingly manually map the joint names to joint index by hand, I can get appropriate output. This guide mapping was high quality to assist determine the place the problem was in my program, however must be programmatically computed when loading the mannequin for apparent causes.
Any concepts what I’m doing improper right here??