Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 140 additions & 70 deletions indra/newview/gltf/llgltfloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,9 @@ bool LLGLTFLoader::parseMeshes()

// Populate the joints from skins first.
// There's not many skins - and you can pretty easily iterate through the nodes from that.
for (auto& skin : mGLTFAsset.mSkins)
for (S32 i = 0; i < mGLTFAsset.mSkins.size(); i++)
{
populateJointFromSkin(skin);
populateJointFromSkin(i);
}

// Track how many times each mesh name has been used
Expand Down Expand Up @@ -293,6 +293,8 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
base_name = "mesh_" + std::to_string(mesh_index);
}

LL_INFOS("GLTF_DEBUG") << "Processing model " << base_name << LL_ENDL;

if (instance_count > 0)
{
pModel->mLabel = base_name + "_copy_" + std::to_string(instance_count);
Expand Down Expand Up @@ -672,16 +674,8 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx];
LLMeshSkinInfo& skin_info = pModel->mSkinInfo;

size_t jointCnt = gltf_skin.mJoints.size();
if (gltf_skin.mInverseBindMatrices >= 0 && jointCnt != gltf_skin.mInverseBindMatricesData.size())
{
LL_INFOS("GLTF_IMPORT") << "Bind matrices count mismatch joints count" << LL_ENDL;
LLSD args;
args["Message"] = "InvBindCountMismatch";
mWarningsArray.append(args);
}

std::vector<S32> gltfindex_to_joitindex_map;
size_t jointCnt = gltf_skin.mJoints.size();
gltfindex_to_joitindex_map.resize(jointCnt);

S32 replacement_index = 0;
Expand Down Expand Up @@ -711,44 +705,24 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
skin_info.mJointNames.push_back(legal_name);
skin_info.mJointNums.push_back(-1);

if (i < gltf_skin.mInverseBindMatricesData.size())
{
// Use pre-computed coord_system_rotation instead of recreating it
LL::GLTF::mat4 gltf_mat = gltf_skin.mInverseBindMatricesData[i];

glm::mat4 original_bind_matrix = glm::inverse(gltf_mat);
glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix;
glm::mat4 rotated_inverse_bind_matrix = glm::inverse(rotated_original);

LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(rotated_inverse_bind_matrix));
skin_info.mInvBindMatrix.push_back(LLMatrix4a(gltf_transform));

LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " val: " << gltf_transform << LL_ENDL;
// In scope of same skin multiple meshes reuse same bind matrices
skin_info.mInvBindMatrix.push_back(mInverseBindMatrices[skinIdx][i]);

// For alternate bind matrix, use the ORIGINAL joint transform (before rotation)
// Get the original joint node and use its matrix directly
S32 joint = gltf_skin.mJoints[i];
LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];
glm::mat4 joint_mat = jointNode.mMatrix;
S32 root_joint = findValidRootJoint(joint, gltf_skin); // skeleton can have multiple real roots
if (root_joint == joint)
{
// This is very likely incomplete in some way.
// Root shouldn't be the only one to need full coordinate fix
joint_mat = coord_system_rotation * joint_mat;
}
LLMatrix4 original_joint_transform(glm::value_ptr(joint_mat));

LL_INFOS("GLTF_DEBUG") << "mAlternateBindMatrix name: " << legal_name << " val: " << original_joint_transform << LL_ENDL;
skin_info.mAlternateBindMatrix.push_back(LLMatrix4a(original_joint_transform));
}
else
// For alternate bind matrix, use the ORIGINAL joint transform (before rotation)
// Get the original joint node and use its matrix directly
// Todo: this seems blatantly wrong, it should have been rotated
glm::mat4 joint_mat = jointNode.mMatrix;
S32 root_joint = findValidRootJointNode(joint, gltf_skin); // skeleton can have multiple real roots
if (root_joint == joint)
{
// For gltf mInverseBindMatrices are optional, but not for viewer
// todo: get a model that triggers this
skin_info.mInvBindMatrix.push_back(LLMatrix4a(mJointList[legal_name])); // might need to be an 'identity'
skin_info.mAlternateBindMatrix.push_back(LLMatrix4a(mJointList[legal_name]));
// This is very likely incomplete in some way.
// Root shouldn't be the only one to need full coordinate fix
joint_mat = coord_system_rotation * joint_mat;
}
LLMatrix4 original_joint_transform(glm::value_ptr(joint_mat));

LL_INFOS("GLTF_DEBUG") << "mAlternateBindMatrix name: " << legal_name << " val: " << original_joint_transform << LL_ENDL;
skin_info.mAlternateBindMatrix.push_back(LLMatrix4a(original_joint_transform));
}

// Remap indices for pModel->mSkinWeights
Expand All @@ -764,23 +738,71 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
return true;
}

void LLGLTFLoader::populateJointFromSkin(const LL::GLTF::Skin& skin)
void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
{
LL_INFOS("GLTF_DEBUG") << "populateJointFromSkin: Processing " << skin.mJoints.size() << " joints" << LL_ENDL;
const LL::GLTF::Skin& skin = mGLTFAsset.mSkins[skin_idx];

for (auto joint : skin.mJoints)
LL_INFOS("GLTF_DEBUG") << "populateJointFromSkin: Processing skin " << skin_idx << " with " << skin.mJoints.size() << " joints" << LL_ENDL;

if (skin.mInverseBindMatrices > 0 && skin.mJoints.size() != skin.mInverseBindMatricesData.size())
{
auto jointNode = mGLTFAsset.mNodes[joint];
LL_INFOS("GLTF_IMPORT") << "Bind matrices count mismatch joints count" << LL_ENDL;
LLSD args;
args["Message"] = "InvBindCountMismatch";
mWarningsArray.append(args);
}

S32 joint_count = (S32)skin.mJoints.size();
S32 inverse_count = (S32)skin.mInverseBindMatricesData.size();
if (mInverseBindMatrices.size() <= skin_idx)
{
mInverseBindMatrices.resize(skin_idx + 1);
}

for (S32 i = 0; i < joint_count; i++)
{
S32 joint = skin.mJoints[i];
LL::GLTF::Node jointNode = mGLTFAsset.mNodes[joint];
std::string legal_name(jointNode.mName);
bool legal_joint = false;
if (mJointMap.find(legal_name) != mJointMap.end())
{
legal_name = mJointMap[legal_name];
legal_joint = true;
}

if (!legal_joint)
{
// add placeholder to not break index
LLMatrix4 gltf_transform;
gltf_transform.setIdentity();
mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform));
}
else if (inverse_count > i)
{
LL::GLTF::mat4 gltf_mat = skin.mInverseBindMatricesData[i];

// Todo: there should be a simpler way
glm::mat4 original_bind_matrix = glm::inverse(gltf_mat);
glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix;
glm::mat4 rotated_inverse_bind_matrix = glm::inverse(rotated_original);
LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(rotated_inverse_bind_matrix));

LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " val: " << gltf_transform << LL_ENDL;
mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform));
}
else
{
// ignore unrecognized joint
LL_DEBUGS("GLTF") << "Ignoring joint: " << legal_name << LL_ENDL;
LLMatrix4 gltf_transform;
gltf_transform.setIdentity();
LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " val: " << gltf_transform << LL_ENDL;
mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform));
}
// todo: prepare mAlternateBindMatrix here

if (!legal_joint)
{
LL_DEBUGS("GLTF") << "Ignoring unrecognized joint: " << legal_name << LL_ENDL;
continue;
}

Expand Down Expand Up @@ -812,59 +834,107 @@ void LLGLTFLoader::populateJointFromSkin(const LL::GLTF::Skin& skin)
}
}

S32 LLGLTFLoader::findValidRootJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const

S32 LLGLTFLoader::findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const
{
S32 root_joint = 0;
S32 found_joint = source_joint;
S32 source_joint_node = gltf_skin.mJoints[source_joint];
S32 root_node = source_joint_node;
S32 found_node = source_joint_node;
S32 size = (S32)gltf_skin.mJoints.size();
do
{
root_joint = found_joint;
root_node = found_node;
for (S32 i = 0; i < size; i++)
{
S32 joint = gltf_skin.mJoints[i];
const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];
std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node);
if (it != jointNode.mChildren.end())
{
// Found node's parent
found_node = joint;
if (mJointMap.find(jointNode.mName) != mJointMap.end())
{
return i;
}
break;
}
}
} while (root_node != found_node);

return -1;
}

S32 LLGLTFLoader::findValidRootJointNode(S32 source_joint_node, const LL::GLTF::Skin& gltf_skin) const
{
S32 root_node = 0;
S32 found_node = source_joint_node;
S32 size = (S32)gltf_skin.mJoints.size();
do
{
root_node = found_node;
for (S32 i = 0; i < size; i++)
{
S32 joint = gltf_skin.mJoints[i];
const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];

if (mJointMap.find(jointNode.mName) != mJointMap.end())
{
std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_joint);
std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node);
if (it != jointNode.mChildren.end())
{
found_joint = joint;
// Found node's parent
found_node = joint;
break;
}
}
}
} while (root_joint != found_joint);
} while (root_node != found_node);

return root_joint;
return root_node;
}

S32 LLGLTFLoader::findGLTFRootJoint(const LL::GLTF::Skin& gltf_skin) const
S32 LLGLTFLoader::findGLTFRootJointNode(const LL::GLTF::Skin& gltf_skin) const
{
S32 root_joint = 0;
S32 found_joint = 0;
S32 root_node = 0;
S32 found_node = 0;
S32 size = (S32)gltf_skin.mJoints.size();
do
{
root_joint = found_joint;
root_node = found_node;
for (S32 i = 0; i < size; i++)
{
S32 joint = gltf_skin.mJoints[i];
const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];
std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_joint);
std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), root_node);
if (it != jointNode.mChildren.end())
{
found_joint = joint;
// Found node's parent
found_node = joint;
break;
}
}
} while (root_joint != found_joint);
} while (root_node != found_node);

LL_INFOS("GLTF_DEBUG") << "mJointList name: ";
const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[root_joint];
LL_CONT << jointNode.mName << " index: " << root_joint << LL_ENDL;
return root_joint;
const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[root_node];
LL_CONT << jointNode.mName << " index: " << root_node << LL_ENDL;
return root_node;
}

S32 LLGLTFLoader::findParentNode(S32 node) const
{
S32 size = (S32)mGLTFAsset.mNodes.size();
for (S32 i = 0; i < size; i++)
{
const LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[i];
std::vector<S32>::const_iterator it = std::find(jointNode.mChildren.begin(), jointNode.mChildren.end(), node);
if (it != jointNode.mChildren.end())
{
return i;
}
}
return -1;
}

bool LLGLTFLoader::parseMaterials()
Expand Down
14 changes: 11 additions & 3 deletions indra/newview/gltf/llgltfloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class LLGLTFLoader : public LLModelLoader
{
public:
typedef std::map<std::string, LLImportMaterial> material_map;
typedef std::map<std::string, LLVector3> joint_pos_map_t;

LLGLTFLoader(std::string filename,
S32 lod,
Expand Down Expand Up @@ -162,16 +163,23 @@ class LLGLTFLoader : public LLModelLoader
std::vector<gltf_image> mImages;
std::vector<gltf_sampler> mSamplers;


// vector of vectors because of a posibility of having more than one skin
typedef std::vector<LLMeshSkinInfo::matrix_list_t> bind_matrices_t;
bind_matrices_t mInverseBindMatrices;

private:
bool parseMeshes();
void uploadMeshes();
bool parseMaterials();
void uploadMaterials();
void computeCombinedNodeTransform(const LL::GLTF::Asset& asset, S32 node_index, glm::mat4& combined_transform) const;
bool populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh &mesh, const LL::GLTF::Node &node, material_map& mats, S32 instance_count);
void populateJointFromSkin(const LL::GLTF::Skin& skin);
S32 findValidRootJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const;
S32 findGLTFRootJoint(const LL::GLTF::Skin& gltf_skin) const; // if there are multiple roots, gltf stores them under one commor joint
void populateJointFromSkin(S32 skin_idx);
S32 findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const;
S32 findValidRootJointNode(S32 source_joint_node, const LL::GLTF::Skin& gltf_skin) const;
S32 findGLTFRootJointNode(const LL::GLTF::Skin& gltf_skin) const; // if there are multiple roots, gltf stores them under one commor joint
S32 findParentNode(S32 node) const;
LLUUID imageBufferToTextureUUID(const gltf_texture& tex);

void notifyUnsupportedExtension(bool unsupported);
Expand Down