summaryrefslogtreecommitdiff
path: root/indra/newview/gltf/llgltfloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/gltf/llgltfloader.cpp')
-rw-r--r--indra/newview/gltf/llgltfloader.cpp271
1 files changed, 198 insertions, 73 deletions
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index 7a1ebf0610..bd3c1a3833 100644
--- a/indra/newview/gltf/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -86,20 +86,20 @@ static const glm::mat4 coord_system_rotationxy(
0.f, 0.f, 0.f, 1.f
);
-LLGLTFLoader::LLGLTFLoader(std::string filename,
- S32 lod,
- LLModelLoader::load_callback_t load_cb,
- LLModelLoader::joint_lookup_func_t joint_lookup_func,
- LLModelLoader::texture_load_func_t texture_load_func,
- LLModelLoader::state_callback_t state_cb,
- void * opaque_userdata,
- JointTransformMap & jointTransformMap,
- JointNameSet & jointsFromNodes,
- std::map<std::string, std::string> &jointAliasMap,
- U32 maxJointsPerMesh,
- U32 modelLimit,
- std::vector<LLJointData> viewer_skeleton) //,
- //bool preprocess)
+LLGLTFLoader::LLGLTFLoader(std::string filename,
+ S32 lod,
+ LLModelLoader::load_callback_t load_cb,
+ LLModelLoader::joint_lookup_func_t joint_lookup_func,
+ LLModelLoader::texture_load_func_t texture_load_func,
+ LLModelLoader::state_callback_t state_cb,
+ void * opaque_userdata,
+ JointTransformMap & jointTransformMap,
+ JointNameSet & jointsFromNodes,
+ std::map<std::string, std::string, std::less<>> & jointAliasMap,
+ U32 maxJointsPerMesh,
+ U32 modelLimit,
+ std::vector<LLJointData> viewer_skeleton) //,
+ //bool preprocess)
: LLModelLoader( filename,
lod,
load_cb,
@@ -129,6 +129,20 @@ bool LLGLTFLoader::OpenFile(const std::string &filename)
if (!mGltfLoaded)
{
notifyUnsupportedExtension(true);
+
+ for (const auto& buffer : mGLTFAsset.mBuffers)
+ {
+ if (buffer.mByteLength > 0 && buffer.mData.empty())
+ {
+ bool bin_file = buffer.mUri.ends_with(".bin");
+ LLSD args;
+ args["Message"] = bin_file ? "ParsingErrorMissingBufferBin" : "ParsingErrorMissingBuffer";
+ args["BUFFER_NAME"] = buffer.mName;
+ args["BUFFER_URI"] = buffer.mUri;
+ mWarningsArray.append(args);
+ }
+ }
+ setLoadState(ERROR_PARSING);
return false;
}
@@ -258,13 +272,14 @@ bool LLGLTFLoader::parseMeshes()
if (mGLTFAsset.mSkins.size() > 0)
{
checkForXYrotation(mGLTFAsset.mSkins[0]);
+ populateJointGroups();
}
// Populate the joints from skins first.
// There's not many skins - and you can pretty easily iterate through the nodes from that.
for (S32 i = 0; i < mGLTFAsset.mSkins.size(); i++)
{
- populateJointFromSkin(i);
+ populateJointsFromSkin(i);
}
// Track how many times each mesh name has been used
@@ -463,8 +478,29 @@ void LLGLTFLoader::computeCombinedNodeTransform(const LL::GLTF::Asset& asset, S3
}
}
+bool LLGLTFLoader::addJointToModelSkin(LLMeshSkinInfo& skin_info, S32 gltf_skin_idx, size_t gltf_joint_idx) const
+{
+ const std::string& legal_name = mJointNames[gltf_skin_idx][gltf_joint_idx];
+ if (legal_name.empty())
+ {
+ llassert(false); // should have been stopped by gltf_joint_index_use[i] == -1
+ return false;
+ }
+ skin_info.mJointNames.push_back(legal_name);
+ skin_info.mJointNums.push_back(-1);
+
+ // In scope of same skin multiple meshes reuse same bind matrices
+ skin_info.mInvBindMatrix.push_back(mInverseBindMatrices[gltf_skin_idx][gltf_joint_idx]);
+ skin_info.mAlternateBindMatrix.push_back(mAlternateBindMatrices[gltf_skin_idx][gltf_joint_idx]);
+
+ return true;
+}
+
bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& mesh, const LL::GLTF::Node& nodeno, material_map& mats, S32 instance_count)
{
+ // Set the requested label for the floater display and uploading
+ pModel->mRequestedLabel = gDirUtilp->getBaseFileName(mFilename, true);
+
// Create unique model name
std::string base_name = mesh.mName;
if (base_name.empty())
@@ -516,15 +552,9 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
size_t jointCnt = gltf_skin.mJoints.size();
gltf_joint_index_use.resize(jointCnt);
- S32 replacement_index = 0;
for (size_t i = 0; i < jointCnt; ++i)
{
- // Process joint name and idnex
- S32 joint = gltf_skin.mJoints[i];
- LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];
-
- std::string legal_name(jointNode.mName);
- if (mJointMap.find(legal_name) == mJointMap.end())
+ if (mJointNames[i].empty())
{
// This might need to hold a substitute index
gltf_joint_index_use[i] = -1; // mark as unsupported
@@ -956,65 +986,106 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
// Call normalizeVolumeFacesAndWeights to compute proper extents
pModel->normalizeVolumeFacesAndWeights();
- // Fill joint names, bind matrices and prepare to remap weight indices
+ // Fill joint names, bind matrices and remap weight indices
if (skinIdx >= 0)
{
LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx];
LLMeshSkinInfo& skin_info = pModel->mSkinInfo;
S32 valid_joints_count = mValidJointsCount[skinIdx];
+ S32 replacement_index = 0;
std::vector<S32> gltfindex_to_joitindex_map;
size_t jointCnt = gltf_skin.mJoints.size();
gltfindex_to_joitindex_map.resize(jointCnt);
- S32 replacement_index = 0;
- S32 stripped_valid_joints = 0;
- for (size_t i = 0; i < jointCnt; ++i)
+ if (valid_joints_count > LL_MAX_JOINTS_PER_MESH_OBJECT)
{
- // Process joint name and idnex
- S32 joint = gltf_skin.mJoints[i];
- if (gltf_joint_index_use[i] < 0)
+ std::map<std::string, S32> goup_use_count;
+ // Assume that 'Torso' group is always in use since that's what everything else is attached to
+ goup_use_count["Torso"] = 1;
+ // Note that Collisions and Extra groups are all over the place, might want to include them from the start
+ // or add individual when parents are added
+
+ // Check which groups are in use
+ for (size_t i = 0; i < jointCnt; ++i)
{
- // unsupported (-1) joint, drop it
- continue;
+ std::string& joint_name = mJointNames[skinIdx][i];
+ if (!joint_name.empty())
+ {
+ if (gltf_joint_index_use[i] > 0)
+ {
+ const JointGroups &group = mJointGroups[joint_name];
+ // Joint in use, increment it's groups
+ goup_use_count[group.mGroup]++;
+ goup_use_count[group.mParentGroup]++;
+ }
+ }
}
- LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];
- std::string legal_name(jointNode.mName);
- if (mJointMap.find(legal_name) != mJointMap.end())
+ // 1. add joints that are in use directly
+ for (size_t i = 0; i < jointCnt; ++i)
{
- legal_name = mJointMap[legal_name];
- }
- else
- {
- llassert(false); // should have been stopped by gltf_joint_index_use[i] == -1
- continue;
+ // Process joint name and idnex
+ S32 joint = gltf_skin.mJoints[i];
+ if (gltf_joint_index_use[i] <= 0)
+ {
+ // unsupported (-1) joint, drop it
+ // unused (0) joint, drop it
+ continue;
+ }
+
+ if (addJointToModelSkin(skin_info, skinIdx, i))
+ {
+ gltfindex_to_joitindex_map[i] = replacement_index++;
+ }
}
- if (valid_joints_count > LL_MAX_JOINTS_PER_MESH_OBJECT
- && gltf_joint_index_use[i] == 0
- && legal_name != "mPelvis")
+ // 2. add joints from groups that this model's joints belong to
+ // It's perfectly valid to have more joints than is in use
+ // Ex: sandals that make your legs digitigrade despite not skining to
+ // knees or the like.
+ // Todo: sort and add by usecount
+ for (size_t i = 0; i < jointCnt; ++i)
{
- // Unused (0) joint
- // It's perfectly valid to have more joints than is in use
- // Ex: sandals that make your legs digitigrade despite not skining to
- // knees or the like.
- // But if model is over limid, drop extras sans pelvis.
- // Keeping 'pelvis' is a workaround to keep preview whole.
- // Todo: consider improving this, either take as much as possible or
- // ensure common parents/roots are included
- continue;
+ S32 joint = gltf_skin.mJoints[i];
+ if (gltf_joint_index_use[i] != 0)
+ {
+ // this step needs only joints that have zero uses
+ continue;
+ }
+ if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT)
+ {
+ break;
+ }
+ const std::string& legal_name = mJointNames[skinIdx][i];
+ std::string group_name = mJointGroups[legal_name].mGroup;
+ if (goup_use_count[group_name] > 0)
+ {
+ if (addJointToModelSkin(skin_info, skinIdx, i))
+ {
+ gltfindex_to_joitindex_map[i] = replacement_index++;
+ }
+ }
}
+ }
+ else
+ {
+ // Less than 110, just add every valid joint
+ for (size_t i = 0; i < jointCnt; ++i)
+ {
+ // Process joint name and idnex
+ S32 joint = gltf_skin.mJoints[i];
+ if (gltf_joint_index_use[i] < 0)
+ {
+ // unsupported (-1) joint, drop it
+ continue;
+ }
- gltfindex_to_joitindex_map[i] = replacement_index++;
-
- skin_info.mJointNames.push_back(legal_name);
- skin_info.mJointNums.push_back(-1);
-
- // In scope of same skin multiple meshes reuse same bind matrices
- skin_info.mInvBindMatrix.push_back(mInverseBindMatrices[skinIdx][i]);
-
- skin_info.mAlternateBindMatrix.push_back(mAlternateBindMatrices[skinIdx][i]);
+ if (addJointToModelSkin(skin_info, skinIdx, i))
+ {
+ gltfindex_to_joitindex_map[i] = replacement_index++;
+ }
+ }
}
if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT)
@@ -1043,7 +1114,7 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
return true;
}
-void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
+void LLGLTFLoader::populateJointsFromSkin(S32 skin_idx)
{
const LL::GLTF::Skin& skin = mGLTFAsset.mSkins[skin_idx];
@@ -1063,6 +1134,7 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
{
mInverseBindMatrices.resize(skin_idx + 1);
mAlternateBindMatrices.resize(skin_idx + 1);
+ mJointNames.resize(skin_idx + 1);
mValidJointsCount.resize(skin_idx + 1, 0);
}
@@ -1119,7 +1191,7 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
glm::mat4 ident(1.0);
for (auto &viewer_data : mViewerJointData)
{
- buildOverrideMatrix(viewer_data, joints_data, names_to_nodes, ident);
+ buildOverrideMatrix(viewer_data, joints_data, names_to_nodes, ident, ident);
}
for (S32 i = 0; i < joint_count; i++)
@@ -1132,6 +1204,11 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
{
legal_name = mJointMap[legal_name];
legal_joint = true;
+ mJointNames[skin_idx].push_back(legal_name);
+ }
+ else
+ {
+ mJointNames[skin_idx].emplace_back();
}
// Compute bind matrices
@@ -1193,6 +1270,15 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
}
}
+void LLGLTFLoader::populateJointGroups()
+{
+ std::string parent;
+ for (auto& viewer_data : mViewerJointData)
+ {
+ buildJointGroup(viewer_data, parent);
+ }
+}
+
S32 LLGLTFLoader::findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const
{
@@ -1296,7 +1382,19 @@ S32 LLGLTFLoader::findParentNode(S32 node) const
return -1;
}
-void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map_t &gltf_nodes, joints_name_to_node_map_t &names_to_nodes, glm::mat4& parent_rest) const
+void LLGLTFLoader::buildJointGroup(LLJointData& viewer_data, const std::string &parent_group)
+{
+ JointGroups& jount_group_data = mJointGroups[viewer_data.mName];
+ jount_group_data.mGroup = viewer_data.mGroup;
+ jount_group_data.mParentGroup = parent_group;
+
+ for (LLJointData& child_data : viewer_data.mChildren)
+ {
+ buildJointGroup(child_data, viewer_data.mGroup);
+ }
+}
+
+void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map_t &gltf_nodes, joints_name_to_node_map_t &names_to_nodes, glm::mat4& parent_rest, glm::mat4& parent_support_rest) const
{
glm::mat4 new_lefover(1.f);
glm::mat4 rest(1.f);
@@ -1306,26 +1404,42 @@ void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map
S32 gltf_node_idx = found_node->second;
JointNodeData& node = gltf_nodes[gltf_node_idx];
node.mIsOverrideValid = true;
+ node.mViewerRestMatrix = viewer_data.mRestMatrix;
glm::mat4 gltf_joint_rest_pose = coord_system_rotation * node.mGltfRestMatrix;
if (mApplyXYRotation)
{
gltf_joint_rest_pose = coord_system_rotationxy * gltf_joint_rest_pose;
}
- node.mOverrideMatrix = glm::inverse(parent_rest) * gltf_joint_rest_pose;
- glm::vec3 override;
+ glm::mat4 translated_joint;
+ // Example:
+ // Viewer has pelvis->spine1->spine2->torso.
+ // gltf example model has pelvis->torso
+ // By doing glm::inverse(transalted_rest_spine2) * gltf_rest_torso
+ // We get what torso would have looked like if gltf had a spine2
+ if (viewer_data.mIsJoint)
+ {
+ translated_joint = glm::inverse(parent_rest) * gltf_joint_rest_pose;
+ }
+ else
+ {
+ translated_joint = glm::inverse(parent_support_rest) * gltf_joint_rest_pose;
+ }
+
+ glm::vec3 translation_override;
glm::vec3 skew;
glm::vec3 scale;
glm::vec4 perspective;
glm::quat rotation;
- glm::decompose(node.mOverrideMatrix, scale, rotation, override, skew, perspective);
- glm::vec3 translate;
- glm::decompose(viewer_data.mJointMatrix, scale, rotation, translate, skew, perspective);
- glm::mat4 viewer_joint = glm::recompose(scale, rotation, override, skew, perspective);
+ glm::decompose(translated_joint, scale, rotation, translation_override, skew, perspective);
+
+ node.mOverrideMatrix = glm::recompose(glm::vec3(1, 1, 1), glm::identity<glm::quat>(), translation_override, glm::vec3(0, 0, 0), glm::vec4(0, 0, 0, 1));
+
+ glm::mat4 override_joint = node.mOverrideMatrix;
+ override_joint = glm::scale(override_joint, viewer_data.mScale);
- node.mOverrideMatrix = viewer_joint;
- rest = parent_rest * node.mOverrideMatrix;
+ rest = parent_rest * override_joint;
node.mOverrideRestMatrix = rest;
}
else
@@ -1333,9 +1447,20 @@ void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map
// No override for this joint
rest = parent_rest * viewer_data.mJointMatrix;
}
+
+ glm::mat4 support_rest(1.f);
+ if (viewer_data.mSupport == LLJointData::SUPPORT_BASE)
+ {
+ support_rest = rest;
+ }
+ else
+ {
+ support_rest = parent_support_rest;
+ }
+
for (LLJointData& child_data : viewer_data.mChildren)
{
- buildOverrideMatrix(child_data, gltf_nodes, names_to_nodes, rest);
+ buildOverrideMatrix(child_data, gltf_nodes, names_to_nodes, rest, support_rest);
}
}