diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index d6fcfaba36..dca9e9fefa 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -841,7 +841,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& parents[child] = nodecount; } sortedNodes.push_back(nodecount); - nodecount++; + ++nodecount; } @@ -857,7 +857,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& _file.nodes[nodecount].transforms.push_back(getModelTransform(parentNode)); parentIndex = parents[parentIndex]; } - nodecount++; + ++nodecount; } @@ -871,7 +871,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int parentIndex = parents[currentNode]; if (parentIndex == -1 || hasBeenSorted[parentIndex]) { hasBeenSorted[currentNode] = true; - i++; + ++i; } else { int j = i + 1; // index of node to be sorted while (j < numNodes) { @@ -882,10 +882,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& hasBeenSorted[nextNode] = true; sortedNodes[i] = nextNode; sortedNodes[j] = currentNode; - i++; + ++i; currentNode = sortedNodes[i]; } - j++; + ++j; } } } @@ -894,7 +894,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // Build map from original to new indices QVector originalToNewNodeIndexMap; originalToNewNodeIndexMap.fill(-1, numNodes); - for (int i = 0; i < numNodes; i++) { + for (int i = 0; i < numNodes; ++i) { originalToNewNodeIndexMap[sortedNodes[i]] = i; } @@ -903,6 +903,8 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& HFMJoint joint; joint.distanceToParent = 0; hfmModel.jointIndices["x"] = numNodes; + QVector globalTransforms; + globalTransforms.resize(numNodes); for (int nodeIndex : sortedNodes) { auto& node = _file.nodes[nodeIndex]; @@ -917,6 +919,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& glm::vec3 scale = extractScale(joint.transform); joint.postTransform = glm::scale(glm::mat4(), scale); + joint.parentIndex = parents[nodeIndex]; + globalTransforms[nodeIndex] = joint.transform; + if (joint.parentIndex != -1) { + globalTransforms[nodeIndex] = globalTransforms[joint.parentIndex] * globalTransforms[nodeIndex]; + joint.parentIndex = originalToNewNodeIndexMap[joint.parentIndex]; + } + joint.name = node.name; joint.isSkeletonJoint = false; hfmModel.joints.push_back(joint); @@ -924,20 +933,30 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& hfmModel.shapeVertices.resize(hfmModel.joints.size()); + // get offset transform from mapping + float unitScaleFactor = 1.0f; + float offsetScale = mapping.value("scale", 1.0f).toFloat() * unitScaleFactor; + glm::quat offsetRotation = glm::quat(glm::radians(glm::vec3(mapping.value("rx").toFloat(), mapping.value("ry").toFloat(), mapping.value("rz").toFloat()))); + hfmModel.offset = glm::translate(glm::mat4(), glm::vec3(mapping.value("tx").toFloat(), mapping.value("ty").toFloat(), mapping.value("tz").toFloat())) * + glm::mat4_cast(offsetRotation) * glm::scale(glm::mat4(), glm::vec3(offsetScale, offsetScale, offsetScale)); + + // Build skeleton std::vector jointInverseBindTransforms; + std::vector globalBindTransforms; jointInverseBindTransforms.resize(numNodes); + globalBindTransforms.resize(numNodes); + hfmModel.hasSkeletonJoints = !_file.skins.isEmpty(); if (hfmModel.hasSkeletonJoints) { - hfmModel.hasSkeletonJoints = true; std::vector> inverseBindValues; getSkinInverseBindMatrices(inverseBindValues); - for (int jointIndex = 0; jointIndex < numNodes; jointIndex++) { + for (int jointIndex = 0; jointIndex < numNodes; ++jointIndex) { int nodeIndex = sortedNodes[jointIndex]; auto joint = hfmModel.joints[jointIndex]; - for (int s = 0; s < _file.skins.size(); s++) { + for (int s = 0; s < _file.skins.size(); ++s) { const auto& skin = _file.skins[s]; int matrixIndex = skin.joints.indexOf(nodeIndex); joint.isSkeletonJoint = skin.joints.contains(nodeIndex); @@ -954,6 +973,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } else { jointInverseBindTransforms[jointIndex] = glm::mat4(); } + globalBindTransforms[jointIndex] = jointInverseBindTransforms[jointIndex]; + if (joint.parentIndex != -1) { + globalBindTransforms[jointIndex] = globalBindTransforms[joint.parentIndex] * globalBindTransforms[jointIndex]; + } glm::vec3 bindTranslation = extractTranslation(hfmModel.offset * glm::inverse(jointInverseBindTransforms[jointIndex])); hfmModel.bindExtents.addPoint(bindTranslation); } @@ -962,13 +985,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } - //Build materials + // Build materials QVector materialIDs; QString unknown = "Default"; int ukcount = 0; foreach(auto material, _file.materials) { if (!material.defined["name"]) { - QString name = unknown + QString::number(ukcount++); + QString name = unknown + QString::number(++ukcount); material.name = name; material.defined.insert("name", true); } @@ -977,7 +1000,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& materialIDs.push_back(mid); } - for (int i = 0; i < materialIDs.size(); i++) { + for (int i = 0; i < materialIDs.size(); ++i) { QString& matid = materialIDs[i]; hfmModel.materials[matid] = HFMMaterial(); HFMMaterial& hfmMaterial = hfmModel.materials[matid]; @@ -989,6 +1012,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // Build meshes nodecount = 0; + hfmModel.meshExtents.reset(); for (int nodeIndex : sortedNodes) { auto& node = _file.nodes[nodeIndex]; @@ -1003,7 +1027,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix); mesh.clusters.append(cluster); } else { // skinned model - for (int j = 0; j < numNodes; j++) { + for (int j = 0; j < numNodes; ++j) { HFMCluster cluster; cluster.jointIndex = j; cluster.inverseBindMatrix = jointInverseBindTransforms[j]; @@ -1300,7 +1324,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } QVector validatedIndices; - for (int n = 0; n < indices.count(); n++) { + for (int n = 0; n < indices.count(); ++n) { if (indices[n] < partVerticesCount) { validatedIndices.push_back(indices[n] + prevMeshVerticesCount); } else { @@ -1332,7 +1356,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } else { if (meshAttributes.contains("TANGENT")) { - for (int i = 0; i < partVerticesCount; i++) { + for (int i = 0; i < partVerticesCount; ++i) { mesh.tangents.push_back(glm::vec3(0.0f, 0.0f, 0.0f)); } } @@ -1344,7 +1368,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } else { if (meshAttributes.contains("TEXCOORD_0")) { - for (int i = 0; i < partVerticesCount; i++) { + for (int i = 0; i < partVerticesCount; ++i) { mesh.texCoords.push_back(glm::vec2(0.0f, 0.0f)); } } @@ -1356,7 +1380,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } else { if (meshAttributes.contains("TEXCOORD_1")) { - for (int i = 0; i < partVerticesCount; i++) { + for (int i = 0; i < partVerticesCount; ++i) { mesh.texCoords1.push_back(glm::vec2(0.0f, 0.0f)); } } @@ -1368,7 +1392,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } else { if (meshAttributes.contains("COLOR_0")) { - for (int i = 0; i < partVerticesCount; i++) { + for (int i = 0; i < partVerticesCount; ++i) { mesh.colors.push_back(glm::vec3(1.0f, 1.0f, 1.0f)); } } @@ -1398,8 +1422,8 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } else { if (meshAttributes.contains("JOINTS_0")) { - for (int i = 0; i < partVerticesCount; i++) { - for (int j = 0; j < 4; j++) { + for (int i = 0; i < partVerticesCount; ++i) { + for (int j = 0; j < 4; ++j) { clusterJoints.push_back(0); } } @@ -1430,9 +1454,9 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } else { if (meshAttributes.contains("WEIGHTS_0")) { - for (int i = 0; i < partVerticesCount; i++) { + for (int i = 0; i < partVerticesCount; ++i) { clusterWeights.push_back(1.0f); - for (int j = 1; j < 4; j++) { + for (int j = 1; j < 4; ++j) { clusterWeights.push_back(0.0f); } } @@ -1448,12 +1472,12 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int numVertices = mesh.vertices.size() - prevMeshVerticesCount; // Append new cluster indices and weights for this mesh part - for (int i = 0; i < numVertices * WEIGHTS_PER_VERTEX; i++) { + for (int i = 0; i < numVertices * WEIGHTS_PER_VERTEX; ++i) { mesh.clusterIndices.push_back(mesh.clusters.size() - 1); mesh.clusterWeights.push_back(0); } - for (int c = 0; c < clusterJoints.size(); c++) { + for (int c = 0; c < clusterJoints.size(); ++c) { mesh.clusterIndices[prevMeshClusterIndexCount + c] = originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[c]]]; } @@ -1474,6 +1498,20 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } else { mesh.clusterWeights[prevMeshClusterWeightCount + j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF); } + for (int clusterIndex = 0; clusterIndex < mesh.clusters.size() - 1; ++clusterIndex) { + ShapeVertices& points = hfmModel.shapeVertices.at(clusterIndex); + glm::vec3 globalMeshScale = extractScale(globalTransforms[nodeIndex]); + const glm::mat4 meshToJoint = glm::scale(glm::mat4(), globalMeshScale) * jointInverseBindTransforms[clusterIndex]; + + const float EXPANSION_WEIGHT_THRESHOLD = 0.25f; + if (mesh.clusterWeights[j] >= EXPANSION_WEIGHT_THRESHOLD) { + // TODO: fix transformed vertices being pushed back + auto& vertex = mesh.vertices[i]; + const glm::mat4 vertexTransform = meshToJoint * (glm::translate(glm::mat4(), vertex)); + glm::vec3 transformedVertex = hfmModel.joints[clusterIndex].translation * (extractTranslation(vertexTransform)); + points.push_back(transformedVertex); + } + } } } @@ -1484,7 +1522,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // populate the texture coordinates if they don't exist if (mesh.texCoords.size() == 0 && !hfmModel.hasSkeletonJoints) { - for (int i = 0; i < part.triangleIndices.size(); i++) { mesh.texCoords.push_back(glm::vec2(0.0, 1.0)); } + for (int i = 0; i < part.triangleIndices.size(); ++i) { mesh.texCoords.push_back(glm::vec2(0.0, 1.0)); } } // Build morph targets (blend shapes) @@ -1495,7 +1533,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& hifi::VariantHash blendshapeMappings = mapping.value("bs").toHash(); QMultiHash blendshapeIndices; - for (int i = 0;; i++) { + for (int i = 0;; ++i) { hifi::ByteArray blendshapeName = FACESHIFT_BLENDSHAPES[i]; if (blendshapeName.isEmpty()) { break; @@ -1515,7 +1553,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& auto names = _file.meshes[node.mesh].extras.targetNames; QVector weights = _file.meshes[node.mesh].weights; - for (int weightedIndex = 0; weightedIndex < values.size(); weightedIndex++) { + for (int weightedIndex = 0; weightedIndex < values.size(); ++weightedIndex) { float weight = 0.1f; int indexFromMapping = weightedIndex; int targetIndex = weightedIndex; @@ -1556,32 +1594,17 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } else { blendshape.vertices[count] = blendshape.vertices[count] + vertices[i]; blendshape.normals[count] = blendshape.normals[count] + normals[i]; - count++; + ++count; } } } } - for (int clusterIndex = 0; clusterIndex < mesh.clusters.size() - 1; clusterIndex++) { - ShapeVertices& points = hfmModel.shapeVertices.at(clusterIndex); - for (glm::vec3 vertex : mesh.vertices) { - points.push_back(vertex); - } - } - - mesh.meshExtents.reset(); foreach(const glm::vec3& vertex, mesh.vertices) { - mesh.meshExtents.addPoint(vertex); - hfmModel.meshExtents.addPoint(vertex); - } - - mesh.meshIndex = hfmModel.meshes.size(); - } - - mesh.meshExtents.reset(); - foreach(const glm::vec3& vertex, mesh.vertices) { - mesh.meshExtents.addPoint(vertex); - hfmModel.meshExtents.addPoint(vertex); + glm::vec3 transformedVertex = glm::vec3(globalTransforms[nodeIndex] * glm::vec4(vertex, 1.0f)); + mesh.meshExtents.addPoint(transformedVertex); + hfmModel.meshExtents.addPoint(transformedVertex); + } } // Add epsilon to mesh extents to compensate for planar meshes @@ -1592,7 +1615,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mesh.meshIndex = hfmModel.meshes.size(); } - nodecount++; + ++nodecount; } return true; @@ -1839,8 +1862,8 @@ bool GLTFSerializer::readArray(const hifi::ByteArray& bin, int byteOffset, int c blobstream.unsetDevice(); return false; } - for (int i = 0; i < count; i++) { - for (int j = 0; j < bufferCount; j++) { + for (int i = 0; i < count; ++i) { + for (int j = 0; j < bufferCount; ++j) { if (!blobstream.atEnd()) { T value; blobstream >> value; @@ -1893,7 +1916,7 @@ bool GLTFSerializer::addArrayFromAccessor(GLTFAccessor& accessor, QVector& ou success = addArrayOfType(buffer.blob, bufferview.byteOffset + accBoffset, accessor.count, outarray, accessor.type, accessor.componentType); } else { - for (int i = 0; i < accessor.count; i++) { + for (int i = 0; i < accessor.count; ++i) { T value; memset(&value, 0, sizeof(T)); // Make sure the dummy array is initalised to zero. outarray.push_back(value); @@ -1924,10 +1947,10 @@ bool GLTFSerializer::addArrayFromAccessor(GLTFAccessor& accessor, QVector& ou accessor.sparse.count, out_sparse_values_array, accessor.type, accessor.componentType); if (success) { - for (int i = 0; i < accessor.sparse.count; i++) { + for (int i = 0; i < accessor.sparse.count; ++i) { if ((i * 3) + 2 < out_sparse_values_array.size()) { if ((out_sparse_indices_array[i] * 3) + 2 < outarray.length()) { - for (int j = 0; j < 3; j++) { + for (int j = 0; j < 3; ++j) { outarray[(out_sparse_indices_array[i] * 3) + j] = out_sparse_values_array[(i * 3) + j]; } } else {