Skip to content

Commit

Permalink
Merge pull request #2215 from ruyo/gltf_skinmesh
Browse files Browse the repository at this point in the history
glTF2 importer multiple primitives and 16-bit index buffer skinmesh support.
  • Loading branch information
kimkulling committed Nov 13, 2018
2 parents 3d57b86 + 9bf4425 commit e6905b6
Showing 1 changed file with 47 additions and 37 deletions.
84 changes: 47 additions & 37 deletions code/glTF2Importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,9 +732,9 @@ static void GetNodeTransform(aiMatrix4x4& matrix, const glTF2::Node& node) {
}
}

static void BuildVertexWeightMapping(Ref<Mesh>& mesh, std::vector<std::vector<aiVertexWeight>>& map)
static void BuildVertexWeightMapping(Mesh::Primitive& primitive, std::vector<std::vector<aiVertexWeight>>& map)
{
Mesh::Primitive::Attributes& attr = mesh->primitives[0].attributes;
Mesh::Primitive::Attributes& attr = primitive.attributes;
if (attr.weight.empty() || attr.joint.empty()) {
return;
}
Expand All @@ -745,15 +745,22 @@ static void BuildVertexWeightMapping(Ref<Mesh>& mesh, std::vector<std::vector<ai
const int num_vertices = attr.weight[0]->count;

struct Weights { float values[4]; };
struct Indices { uint8_t values[4]; };
Weights* weights = nullptr;
Indices* indices = nullptr;
attr.weight[0]->ExtractData(weights);
attr.joint[0]->ExtractData(indices);

struct Indices8 { uint8_t values[4]; };
struct Indices16 { uint16_t values[4]; };
Indices8* indices8 = nullptr;
Indices16* indices16 = nullptr;
if (attr.joint[0]->GetElementSize() == 4) {
attr.joint[0]->ExtractData(indices8);
}else {
attr.joint[0]->ExtractData(indices16);
}

for (int i = 0; i < num_vertices; ++i) {
for (int j = 0; j < 4; ++j) {
const unsigned int bone = indices[i].values[j];
const unsigned int bone = (indices8!=nullptr) ? indices8[i].values[j] : indices16[i].values[j];
const float weight = weights[i].values[j];
if (weight > 0 && bone < map.size()) {
map[bone].reserve(8);
Expand All @@ -763,7 +770,8 @@ static void BuildVertexWeightMapping(Ref<Mesh>& mesh, std::vector<std::vector<ai
}

delete[] weights;
delete[] indices;
delete[] indices8;
delete[] indices16;
}

aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector<unsigned int>& meshOffsets, glTF2::Ref<glTF2::Node>& ptr)
Expand Down Expand Up @@ -797,37 +805,39 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector<unsigned int>&
ainode->mMeshes = new unsigned int[count];

if (node.skin) {
aiMesh* mesh = pScene->mMeshes[meshOffsets[mesh_idx]];
mesh->mNumBones = node.skin->jointNames.size();
mesh->mBones = new aiBone*[mesh->mNumBones];

// GLTF and Assimp choose to store bone weights differently.
// GLTF has each vertex specify which bones influence the vertex.
// Assimp has each bone specify which vertices it has influence over.
// To convert this data, we first read over the vertex data and pull
// out the bone-to-vertex mapping. Then, when creating the aiBones,
// we copy the bone-to-vertex mapping into the bone. This is unfortunate
// both because it's somewhat slow and because, for many applications,
// we then need to reconvert the data back into the vertex-to-bone
// mapping which makes things doubly-slow.
std::vector<std::vector<aiVertexWeight>> weighting(mesh->mNumBones);
BuildVertexWeightMapping(node.meshes[0], weighting);

for (size_t i = 0; i < mesh->mNumBones; ++i) {
aiBone* bone = new aiBone();

Ref<Node> joint = node.skin->jointNames[i];
bone->mName = joint->name;
GetNodeTransform(bone->mOffsetMatrix, *joint);

std::vector<aiVertexWeight>& weights = weighting[i];

bone->mNumWeights = weights.size();
if (bone->mNumWeights > 0) {
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
aiMesh* mesh = pScene->mMeshes[meshOffsets[mesh_idx]+primitiveNo];
mesh->mNumBones = node.skin->jointNames.size();
mesh->mBones = new aiBone*[mesh->mNumBones];

// GLTF and Assimp choose to store bone weights differently.
// GLTF has each vertex specify which bones influence the vertex.
// Assimp has each bone specify which vertices it has influence over.
// To convert this data, we first read over the vertex data and pull
// out the bone-to-vertex mapping. Then, when creating the aiBones,
// we copy the bone-to-vertex mapping into the bone. This is unfortunate
// both because it's somewhat slow and because, for many applications,
// we then need to reconvert the data back into the vertex-to-bone
// mapping which makes things doubly-slow.
std::vector<std::vector<aiVertexWeight>> weighting(mesh->mNumBones);
BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);

for (size_t i = 0; i < mesh->mNumBones; ++i) {
aiBone* bone = new aiBone();

Ref<Node> joint = node.skin->jointNames[i];
bone->mName = joint->name;
GetNodeTransform(bone->mOffsetMatrix, *joint);

std::vector<aiVertexWeight>& weights = weighting[i];

bone->mNumWeights = weights.size();
if (bone->mNumWeights > 0) {
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
}
mesh->mBones[i] = bone;
}
mesh->mBones[i] = bone;
}
}

Expand Down

0 comments on commit e6905b6

Please sign in to comment.