From 471baf83c69eab1589ec2085b1a43dc52612f88f Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Tue, 25 Sep 2018 07:56:44 +0100 Subject: [PATCH 01/10] Support vertex colours and multiple unnamed mesh materials. # Conflicts: # libraries/fbx/src/GLTFSerializer.cpp --- libraries/fbx/src/GLTFSerializer.cpp | 167 ++++++++++++++++++--------- libraries/fbx/src/GLTFSerializer.h | 55 ++++++++- 2 files changed, 166 insertions(+), 56 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index 622fb92ce7..ff2ab8a6d4 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -261,6 +261,41 @@ bool GLTFSerializer::setAsset(const QJsonObject& object) { return isAssetDefined; } +GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices GLTFSerializer::createAccessorSparseIndices(const QJsonObject& object) { + GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices accessorSparseIndices; + + getIntVal(object, "bufferView", accessorSparseIndices.bufferView, accessorSparseIndices.defined); + getIntVal(object, "byteOffset", accessorSparseIndices.byteOffset, accessorSparseIndices.defined); + getIntVal(object, "componentType", accessorSparseIndices.componentType, accessorSparseIndices.defined); + + return accessorSparseIndices; +} + +GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues GLTFSerializer::createAccessorSparseValues(const QJsonObject& object) { + GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues accessorSparseValues; + + getIntVal(object, "bufferView", accessorSparseValues.bufferView, accessorSparseValues.defined); + getIntVal(object, "byteOffset", accessorSparseValues.byteOffset, accessorSparseValues.defined); + + return accessorSparseValues; +} + +GLTFAccessor::GLTFAccessorSparse GLTFSerializer::createAccessorSparse(const QJsonObject& object) { + GLTFAccessor::GLTFAccessorSparse accessorSparse; + + getIntVal(object, "count", accessorSparse.count, accessorSparse.defined); + QJsonObject sparseIndicesObject; + if (getObjectVal(object, "indices", sparseIndicesObject, accessorSparse.defined)) { + accessorSparse.indices = createAccessorSparseIndices(sparseIndicesObject); + } + QJsonObject sparseValuesObject; + if (getObjectVal(object, "values", sparseValuesObject, accessorSparse.defined)) { + accessorSparse.values = createAccessorSparseValues(sparseValuesObject); + } + + return accessorSparse; +} + bool GLTFSerializer::addAccessor(const QJsonObject& object) { GLTFAccessor accessor; @@ -273,6 +308,12 @@ bool GLTFSerializer::addAccessor(const QJsonObject& object) { if (getStringVal(object, "type", type, accessor.defined)) { accessor.type = getAccessorType(type); } + + QJsonObject sparseObject; + if (getObjectVal(object, "sparse", sparseObject, accessor.defined)) { + accessor.sparse = createAccessorSparse(sparseObject); + } + getDoubleArrayVal(object, "max", accessor.max, accessor.defined); getDoubleArrayVal(object, "min", accessor.min, accessor.defined); @@ -783,7 +824,7 @@ void GLTFSerializer::generateTargetData(int index, float weight, QVector<glm::ve bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mapping, const hifi::URL& url) { int numNodes = _file.nodes.size(); - // Build dependencies + //Build dependencies QVector<int> parents; QVector<int> sortedNodes; parents.fill(-1, numNodes); @@ -802,18 +843,18 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& nodecount = 0; foreach(auto &node, _file.nodes) { // collect node transform - _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); + _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); int parentIndex = parents[nodecount]; while (parentIndex != -1) { const auto& parentNode = _file.nodes[parentIndex]; // collect transforms for a node's parents, grandparents, etc. _file.nodes[nodecount].transforms.push_back(getModelTransform(parentNode)); parentIndex = parents[parentIndex]; - } + } nodecount++; } - + // since parent indices must exist in the sorted list before any of their children, sortedNodes might not be initialized in the correct order // therefore we need to re-initialize the order in which nodes will be parsed QVector<bool> hasBeenSorted; @@ -837,10 +878,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& sortedNodes[j] = currentNode; i++; currentNode = sortedNodes[i]; - } + } j++; - } - } + } + } } @@ -868,7 +909,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& joint.translation = extractTranslation(joint.transform); joint.rotation = glmExtractRotation(joint.transform); glm::vec3 scale = extractScale(joint.transform); - joint.postTransform = glm::scale(glm::mat4(), scale); + joint.postTransform = glm::scale(glm::mat4(), scale); joint.name = node.name; joint.isSkeletonJoint = false; @@ -914,12 +955,18 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } - // Build materials + //Build materials QVector<QString> materialIDs; QString unknown = "Default"; int ukcount = 0; foreach(auto material, _file.materials) { - QString mid = (material.defined["name"]) ? material.name : unknown + ukcount++; + if (!(material.defined["name"])) { + QString name = unknown + QString::number(ukcount++); + material.name = name; + material.defined.insert("name", true); + } + + QString mid = material.name; materialIDs.push_back(mid); } @@ -928,6 +975,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& hfmModel.materials[matid] = HFMMaterial(); HFMMaterial& hfmMaterial = hfmModel.materials[matid]; hfmMaterial._material = std::make_shared<graphics::Material>(); + hfmMaterial.name = hfmMaterial.materialID = matid; setHFMMaterial(hfmMaterial, _file.materials[i]); } @@ -938,30 +986,31 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& auto& node = _file.nodes[nodeIndex]; if (node.defined["mesh"]) { - foreach(auto &primitive, _file.meshes[node.mesh].primitives) { - hfmModel.meshes.append(HFMMesh()); - HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1]; - if (!hfmModel.hasSkeletonJoints) { - HFMCluster cluster; - cluster.jointIndex = nodecount; - cluster.inverseBindMatrix = glm::mat4(); - cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix); - mesh.clusters.append(cluster); + + hfmModel.meshes.append(HFMMesh()); + HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1]; + if (!hfmModel.hasSkeletonJoints) { + HFMCluster cluster; + cluster.jointIndex = nodecount; + cluster.inverseBindMatrix = glm::mat4(); + cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix); + mesh.clusters.append(cluster); } else { // skinned model for (int j = 0; j < numNodes; j++) { - HFMCluster cluster; - cluster.jointIndex = j; - cluster.inverseBindMatrix = jointInverseBindTransforms[j]; - cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix); - mesh.clusters.append(cluster); - } + HFMCluster cluster; + cluster.jointIndex = j; + cluster.inverseBindMatrix = jointInverseBindTransforms[j]; + cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix); + mesh.clusters.append(cluster); } - HFMCluster root; - root.jointIndex = 0; - root.inverseBindMatrix = jointInverseBindTransforms[root.jointIndex]; - root.inverseBindTransform = Transform(root.inverseBindMatrix); - mesh.clusters.append(root); + } + HFMCluster root; + root.jointIndex = 0; + root.inverseBindMatrix = jointInverseBindTransforms[root.jointIndex]; + root.inverseBindTransform = Transform(root.inverseBindMatrix); + mesh.clusters.append(root); + foreach(auto &primitive, _file.meshes[node.mesh].primitives) { HFMMeshPart part = HFMMeshPart(); int indicesAccessorIdx = primitive.indices; @@ -972,10 +1021,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int indicesAccBoffset = indicesAccessor.defined["byteOffset"] ? indicesAccessor.byteOffset : 0; - QVector<int> raw_indices; - QVector<glm::vec3> raw_vertices; - QVector<glm::vec3> raw_normals; - bool success = addArrayOfType(indicesBuffer.blob, indicesBufferview.byteOffset + indicesAccBoffset, indicesAccessor.count, @@ -988,6 +1033,14 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } + // Increment the triangle indices by the current mesh vertex count so each mesh part can all reference the same buffers within the mesh + int prevMeshVerticesCount = mesh.vertices.count(); + if (prevMeshVerticesCount > 0) { + for (int i = 0; i < part.triangleIndices.count(); i++) { + part.triangleIndices[i] += prevMeshVerticesCount; + } + } + QList<QString> keys = primitive.attributes.values.keys(); QVector<uint16_t> clusterJoints; QVector<float> clusterWeights; @@ -1029,22 +1082,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& for (int n = 0; n < normals.size(); n = n + 3) { mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2])); } - } else if (key == "COLOR_0") { - QVector<float> colors; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - colors, - accessor.type, - accessor.componentType); - if (!success) { - qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url; - continue; - } - int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3; - for (int n = 0; n < colors.size() - 3; n += stride) { - mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2])); - } } else if (key == "TANGENT") { QVector<float> tangents; success = addArrayOfType(buffer.blob, @@ -1093,7 +1130,23 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& for (int n = 0; n < texcoords.size(); n = n + 2) { mesh.texCoords1.push_back(glm::vec2(texcoords[n], texcoords[n + 1])); } - } else if (key == "JOINTS_0") { + } else if (key == "COLOR_0") { + QVector<float> colors; + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, + colors, + accessor.type, + accessor.componentType); + if (!success) { + qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url; + continue; + } + int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3; + for (int n = 0; n < colors.size() - 3; n += stride) { + mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2])); + } + } else if (key == "JOINTS_0") { QVector<uint16_t> joints; success = addArrayOfType(buffer.blob, bufferview.byteOffset + accBoffset, @@ -1251,6 +1304,14 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mesh.meshIndex = hfmModel.meshes.size(); } + + mesh.meshExtents.reset(); + foreach(const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + hfmModel.meshExtents.addPoint(vertex); + } + + mesh.meshIndex = hfmModel.meshes.size(); } nodecount++; } @@ -1404,10 +1465,6 @@ HFMTexture GLTFSerializer::getHFMTexture(const GLTFTexture& texture) { void GLTFSerializer::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material) { - if (material.defined["name"]) { - fbxmat.name = fbxmat.materialID = material.name; - } - if (material.defined["emissiveFactor"] && material.emissiveFactor.size() == 3) { glm::vec3 emissive = glm::vec3(material.emissiveFactor[0], material.emissiveFactor[1], diff --git a/libraries/fbx/src/GLTFSerializer.h b/libraries/fbx/src/GLTFSerializer.h index b1c1bc4e44..fa5a640fca 100755 --- a/libraries/fbx/src/GLTFSerializer.h +++ b/libraries/fbx/src/GLTFSerializer.h @@ -481,6 +481,49 @@ namespace GLTFAccessorComponentType { }; } struct GLTFAccessor { + struct GLTFAccessorSparse { + struct GLTFAccessorSparseIndices { + int bufferView; + int byteOffset{ 0 }; + int componentType; + + QMap<QString, bool> defined; + void dump() { + if (defined["bufferView"]) { + qCDebug(modelformat) << "bufferView: " << bufferView; + } + if (defined["byteOffset"]) { + qCDebug(modelformat) << "byteOffset: " << byteOffset; + } + if (defined["componentType"]) { + qCDebug(modelformat) << "componentType: " << componentType; + } + } + }; + struct GLTFAccessorSparseValues { + int bufferView; + int byteOffset{ 0 }; + + QMap<QString, bool> defined; + void dump() { + if (defined["bufferView"]) { + qCDebug(modelformat) << "bufferView: " << bufferView; + } + if (defined["byteOffset"]) { + qCDebug(modelformat) << "byteOffset: " << byteOffset; + } + } + }; + + int count; + GLTFAccessorSparseIndices indices; + GLTFAccessorSparseValues values; + + QMap<QString, bool> defined; + void dump() { + + } + }; int bufferView; int byteOffset { 0 }; int componentType; //required @@ -489,6 +532,7 @@ struct GLTFAccessor { bool normalized{ false }; QVector<double> max; QVector<double> min; + GLTFAccessorSparse sparse; QMap<QString, bool> defined; void dump() { if (defined["bufferView"]) { @@ -521,6 +565,10 @@ struct GLTFAccessor { qCDebug(modelformat) << m; } } + if (defined["sparse"]) { + qCDebug(modelformat) << "sparse: "; + sparse.dump(); + } } }; @@ -763,6 +811,11 @@ private: int& outidx, QMap<QString, bool>& defined); bool setAsset(const QJsonObject& object); + + GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseIndices createAccessorSparseIndices(const QJsonObject& object); + GLTFAccessor::GLTFAccessorSparse::GLTFAccessorSparseValues createAccessorSparseValues(const QJsonObject& object); + GLTFAccessor::GLTFAccessorSparse createAccessorSparse(const QJsonObject& object); + bool addAccessor(const QJsonObject& object); bool addAnimation(const QJsonObject& object); bool addBufferView(const QJsonObject& object); @@ -782,7 +835,7 @@ private: template<typename T, typename L> bool readArray(const hifi::ByteArray& bin, int byteOffset, int count, QVector<L>& outarray, int accessorType); - + template<typename T> bool addArrayOfType(const hifi::ByteArray& bin, int byteOffset, int count, QVector<T>& outarray, int accessorType, int componentType); From a4b3f02139b09d319833616a85acf860255e5047 Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Wed, 7 Nov 2018 20:43:42 +0000 Subject: [PATCH 02/10] Added support for automatic normals generation, sparse accessors, extra threshold for thin bounding boxes, and general refactoring. # Conflicts: # libraries/fbx/src/GLTFSerializer.cpp --- libraries/fbx/src/GLTFSerializer.cpp | 440 +++++++++++++++++++++------ libraries/fbx/src/GLTFSerializer.h | 3 + 2 files changed, 348 insertions(+), 95 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index ff2ab8a6d4..78569fa78f 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -37,6 +37,28 @@ #include "FBXSerializer.h" +#define GLTF_GET_INDICIES(acc_count) int index1 = (indices[n + 0] * acc_count); int index2 = (indices[n + 1] * acc_count); int index3 = (indices[n + 2] * acc_count); + +#define GLTF_APPEND_ARRAY_1(new_array, old_array) GLTF_GET_INDICIES(1) \ +new_array.append(old_array[index1]); \ +new_array.append(old_array[index2]); \ +new_array.append(old_array[index3]); + +#define GLTF_APPEND_ARRAY_2(new_array, old_array) GLTF_GET_INDICIES(2) \ +new_array.append(old_array[index1]); new_array.append(old_array[index1 + 1]); \ +new_array.append(old_array[index2]); new_array.append(old_array[index2 + 1]); \ +new_array.append(old_array[index3]); new_array.append(old_array[index3 + 1]); + +#define GLTF_APPEND_ARRAY_3(new_array, old_array) GLTF_GET_INDICIES(3) \ +new_array.append(old_array[index1]); new_array.append(old_array[index1 + 1]); new_array.append(old_array[index1 + 2]); \ +new_array.append(old_array[index2]); new_array.append(old_array[index2 + 1]); new_array.append(old_array[index2 + 2]); \ +new_array.append(old_array[index3]); new_array.append(old_array[index3 + 1]); new_array.append(old_array[index3 + 2]); + +#define GLTF_APPEND_ARRAY_4(new_array, old_array) GLTF_GET_INDICIES(4) \ +new_array.append(old_array[index1]); new_array.append(old_array[index1 + 1]); new_array.append(old_array[index1 + 2]); new_array.append(old_array[index1 + 3]); \ +new_array.append(old_array[index2]); new_array.append(old_array[index2 + 1]); new_array.append(old_array[index2 + 2]); new_array.append(old_array[index2 + 3]); \ +new_array.append(old_array[index3]); new_array.append(old_array[index3 + 1]); new_array.append(old_array[index3 + 2]); new_array.append(old_array[index3 + 3]); + bool GLTFSerializer::getStringVal(const QJsonObject& object, const QString& fieldname, QString& value, QMap<QString, bool>& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isString()); @@ -1016,17 +1038,23 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int indicesAccessorIdx = primitive.indices; GLTFAccessor& indicesAccessor = _file.accessors[indicesAccessorIdx]; - GLTFBufferView& indicesBufferview = _file.bufferviews[indicesAccessor.bufferView]; - GLTFBuffer& indicesBuffer = _file.buffers[indicesBufferview.buffer]; - int indicesAccBoffset = indicesAccessor.defined["byteOffset"] ? indicesAccessor.byteOffset : 0; + // Buffers + QVector<int> indices; + QVector<float> vertices; + QVector<float> normals; + QVector<float> tangents; + int tangent_stride = 0; + QVector<float> texcoords; + QVector<float> texcoords2; + QVector<float> colors; + int color_stride = 0; + QVector<uint16_t> joints; + int joint_stride = 0; + QVector<float> weights; + int weight_stride = 0; - bool success = addArrayOfType(indicesBuffer.blob, - indicesBufferview.byteOffset + indicesAccBoffset, - indicesAccessor.count, - part.triangleIndices, - indicesAccessor.type, - indicesAccessor.componentType); + bool success = addArrayOfFromAccessor(indicesAccessor, indices); if (!success) { qWarning(modelformat) << "There was a problem reading glTF INDICES data for model " << _url; @@ -1035,11 +1063,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // Increment the triangle indices by the current mesh vertex count so each mesh part can all reference the same buffers within the mesh int prevMeshVerticesCount = mesh.vertices.count(); - if (prevMeshVerticesCount > 0) { - for (int i = 0; i < part.triangleIndices.count(); i++) { - part.triangleIndices[i] += prevMeshVerticesCount; - } - } QList<QString> keys = primitive.attributes.values.keys(); QVector<uint16_t> clusterJoints; @@ -1049,136 +1072,290 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int accessorIdx = primitive.attributes.values[key]; GLTFAccessor& accessor = _file.accessors[accessorIdx]; - GLTFBufferView& bufferview = _file.bufferviews[accessor.bufferView]; - GLTFBuffer& buffer = _file.buffers[bufferview.buffer]; int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0; if (key == "POSITION") { - QVector<float> vertices; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, vertices, - accessor.type, - accessor.componentType); + success = addArrayOfFromAccessor(accessor, vertices); if (!success) { qWarning(modelformat) << "There was a problem reading glTF POSITION data for model " << _url; continue; } - for (int n = 0; n < vertices.size(); n = n + 3) { - mesh.vertices.push_back(glm::vec3(vertices[n], vertices[n + 1], vertices[n + 2])); + + if (accessor.type != GLTFAccessorType::VEC3) { + qWarning(modelformat) << "Invalid accessor type on glTF POSITION data for model " << _url; + continue; } } else if (key == "NORMAL") { - QVector<float> normals; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - normals, - accessor.type, - accessor.componentType); + success = addArrayOfFromAccessor(accessor, normals); if (!success) { qWarning(modelformat) << "There was a problem reading glTF NORMAL data for model " << _url; continue; } - for (int n = 0; n < normals.size(); n = n + 3) { - mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2])); + + if (accessor.type != GLTFAccessorType::VEC3) { + qWarning(modelformat) << "Invalid accessor type on glTF NORMAL data for model " << _url; + continue; } } else if (key == "TANGENT") { - QVector<float> tangents; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - tangents, - accessor.type, - accessor.componentType); + success = addArrayOfFromAccessor(accessor, tangents); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TANGENT data for model " << _url; continue; } - // tangents can be a vec3 or a vec4 which includes a w component (of -1 or 1) - int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3; - for (int n = 0; n < tangents.size() - 3; n += stride) { - float tanW = stride == 4 ? tangents[n + 3] : 1; - mesh.tangents.push_back(glm::vec3(tanW * tangents[n], tangents[n + 1], tanW * tangents[n + 2])); + + if (accessor.type == GLTFAccessorType::VEC4) { + tangent_stride = 4; + } else if (accessor.type == GLTFAccessorType::VEC3) { + tangent_stride = 3; + } else { + qWarning(modelformat) << "Invalid accessor type on glTF TANGENT data for model " << _url; + continue; } } else if (key == "TEXCOORD_0") { - QVector<float> texcoords; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - texcoords, - accessor.type, - accessor.componentType); + success = addArrayOfFromAccessor(accessor, texcoords); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_0 data for model " << _url; continue; } - for (int n = 0; n < texcoords.size(); n = n + 2) { - mesh.texCoords.push_back(glm::vec2(texcoords[n], texcoords[n + 1])); + + if (accessor.type != GLTFAccessorType::VEC2) { + qWarning(modelformat) << "Invalid accessor type on glTF TEXCOORD_0 data for model " << _url; + continue; } } else if (key == "TEXCOORD_1") { - QVector<float> texcoords; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - texcoords, - accessor.type, - accessor.componentType); + success = addArrayOfFromAccessor(accessor, texcoords2); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_1 data for model " << _url; continue; } - for (int n = 0; n < texcoords.size(); n = n + 2) { - mesh.texCoords1.push_back(glm::vec2(texcoords[n], texcoords[n + 1])); + + if (accessor.type != GLTFAccessorType::VEC2) { + qWarning(modelformat) << "Invalid accessor type on glTF TEXCOORD_1 data for model " << _url; + continue; } } else if (key == "COLOR_0") { - QVector<float> colors; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - colors, - accessor.type, - accessor.componentType); + success = addArrayOfFromAccessor(accessor, colors); if (!success) { qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url; continue; } - int stride = (accessor.type == GLTFAccessorType::VEC4) ? 4 : 3; - for (int n = 0; n < colors.size() - 3; n += stride) { - mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2])); + + if (accessor.type == GLTFAccessorType::VEC4) { + color_stride = 4; + } else if (accessor.type == GLTFAccessorType::VEC3) { + color_stride = 3; + } else { + qWarning(modelformat) << "Invalid accessor type on glTF COLOR_0 data for model " << _url; + continue; } - } else if (key == "JOINTS_0") { - QVector<uint16_t> joints; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - joints, - accessor.type, - accessor.componentType); + } else if (key == "JOINTS_0") { + success = addArrayOfFromAccessor(accessor, joints); if (!success) { qWarning(modelformat) << "There was a problem reading glTF JOINTS_0 data for model " << _url; continue; } - for (int n = 0; n < joints.size(); n++) { - clusterJoints.push_back(joints[n]); + + if (accessor.type == GLTFAccessorType::VEC4) { + joint_stride = 4; + } else if (accessor.type == GLTFAccessorType::VEC3) { + joint_stride = 3; + } else if (accessor.type == GLTFAccessorType::VEC2) { + joint_stride = 2; + } else if (accessor.type == GLTFAccessorType::SCALAR) { + joint_stride = 1; + } else { + qWarning(modelformat) << "Invalid accessor type on glTF JOINTS_0 data for model " << _url; + continue; } } else if (key == "WEIGHTS_0") { - QVector<float> weights; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - weights, - accessor.type, - accessor.componentType); + success = addArrayOfFromAccessor(accessor, weights); if (!success) { qWarning(modelformat) << "There was a problem reading glTF WEIGHTS_0 data for model " << _url; continue; } - for (int n = 0; n < weights.size(); n++) { - clusterWeights.push_back(weights[n]); + + if (accessor.type == GLTFAccessorType::VEC4) { + weight_stride = 4; + } else if (accessor.type == GLTFAccessorType::VEC3) { + weight_stride = 3; + } else if (accessor.type == GLTFAccessorType::VEC2) { + weight_stride = 2; + } else if (accessor.type == GLTFAccessorType::SCALAR) { + weight_stride = 1; + } else { + qWarning(modelformat) << "Invalid accessor type on glTF WEIGHTS_0 data for model " << _url; + continue; } } } - + + // generate the normals if they don't exist + if (normals.size() == 0) { + QVector<int> new_indices; + QVector<float> new_vertices; + QVector<float> new_normals; + QVector<float> new_tangents; + QVector<float> new_texcoords; + QVector<float> new_texcoords2; + QVector<float> new_colors; + QVector<uint16_t> new_joints; + QVector<float> new_weights; + + for (int n = 0; n < indices.size(); n = n + 3) { + int v1_index = (indices[n + 0] * 3); + int v2_index = (indices[n + 1] * 3); + int v3_index = (indices[n + 2] * 3); + + glm::vec3 v1 = glm::vec3(vertices[v1_index], vertices[v1_index + 1], vertices[v1_index + 2]); + glm::vec3 v2 = glm::vec3(vertices[v2_index], vertices[v2_index + 1], vertices[v2_index + 2]); + glm::vec3 v3 = glm::vec3(vertices[v3_index], vertices[v3_index + 1], vertices[v3_index + 2]); + + new_vertices.append(v1.x); new_vertices.append(v1.y); new_vertices.append(v1.z); + new_vertices.append(v2.x); new_vertices.append(v2.y); new_vertices.append(v2.z); + new_vertices.append(v3.x); new_vertices.append(v3.y); new_vertices.append(v3.z); + + glm::vec3 norm = glm::normalize(glm::cross(v2 - v1, v3 - v1)); + + new_normals.append(norm.x); new_normals.append(norm.y); new_normals.append(norm.z); + new_normals.append(norm.x); new_normals.append(norm.y); new_normals.append(norm.z); + new_normals.append(norm.x); new_normals.append(norm.y); new_normals.append(norm.z); + + if (tangents.size() > 0) { + if (tangent_stride == 4) { + GLTF_APPEND_ARRAY_4(new_tangents, tangents) + } else { + GLTF_APPEND_ARRAY_3(new_tangents, tangents) + } + } + + if (texcoords.size() > 0) { + GLTF_APPEND_ARRAY_2(new_texcoords, texcoords) + } + + if (texcoords2.size() > 0) { + GLTF_APPEND_ARRAY_2(new_texcoords2, texcoords2) + } + + if (colors.size() > 0) { + if (color_stride == 4) { + GLTF_APPEND_ARRAY_4(new_colors, colors) + } else { + GLTF_APPEND_ARRAY_3(new_colors, colors) + } + } + + if (joints.size() > 0) { + if (joint_stride == 4) { + GLTF_APPEND_ARRAY_4(new_joints, joints) + } else if (joint_stride == 3) { + GLTF_APPEND_ARRAY_3(new_joints, joints) + } else if (joint_stride == 2) { + GLTF_APPEND_ARRAY_2(new_joints, joints) + } else { + GLTF_APPEND_ARRAY_1(new_joints, joints) + } + } + + if (weights.size() > 0) { + if (weight_stride == 4) { + GLTF_APPEND_ARRAY_4(new_weights, weights) + } else if (weight_stride == 3) { + GLTF_APPEND_ARRAY_3(new_weights, weights) + } else if (weight_stride == 2) { + GLTF_APPEND_ARRAY_2(new_weights, weights) + } else { + GLTF_APPEND_ARRAY_1(new_weights, weights) + } + } + + new_indices.append(n); + new_indices.append(n + 1); + new_indices.append(n + 2); + } + + vertices = new_vertices; + normals = new_normals; + tangents = new_tangents; + indices = new_indices; + texcoords = new_texcoords; + texcoords2 = new_texcoords2; + colors = new_colors; + joints = new_joints; + weights = new_weights; + } + + for (int n = 0; n < indices.count(); n++) { + part.triangleIndices.push_back(indices[n] + prevMeshVerticesCount); + } + + for (int n = 0; n < vertices.size(); n = n + 3) { + mesh.vertices.push_back(glm::vec3(vertices[n], vertices[n + 1], vertices[n + 2])); + } + + for (int n = 0; n < normals.size(); n = n + 3) { + mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2])); + } + + for (int n = 0; n < tangents.size(); n += tangent_stride) { + float tanW = tangent_stride == 4 ? tangents[n + 3] : 1; + mesh.tangents.push_back(glm::vec3(tanW * tangents[n], tangents[n + 1], tanW * tangents[n + 2])); + } + + for (int n = 0; n < texcoords.size(); n = n + 2) { + mesh.texCoords.push_back(glm::vec2(texcoords[n], texcoords[n + 1])); + } + for (int n = 0; n < texcoords2.size(); n = n + 2) { + mesh.texCoords1.push_back(glm::vec2(texcoords2[n], texcoords2[n + 1])); + } + + for (int n = 0; n < colors.size(); n += color_stride) { + mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2])); + } + + for (int n = 0; n < joints.size(); n += joint_stride) { + clusterJoints.push_back(joints[n]); + if (joint_stride > 1) { + clusterJoints.push_back(joints[n + 1]); + if (joint_stride > 2) { + clusterJoints.push_back(joints[n + 2]); + if (joint_stride > 3) { + clusterJoints.push_back(joints[n + 3]); + } else { + clusterJoints.push_back(0); + } + } else { + clusterJoints.push_back(0); + clusterJoints.push_back(0); + } + } else { + clusterJoints.push_back(0); + clusterJoints.push_back(0); + clusterJoints.push_back(0); + } + } + + for (int n = 0; n < weights.size(); n += weight_stride) { + clusterWeights.push_back(weights[n]); + if (weight_stride > 1) { + clusterWeights.push_back(weights[n + 1]); + if (weight_stride > 2) { + clusterWeights.push_back(weights[n + 2]); + if (weight_stride > 3) { + clusterWeights.push_back(weights[n + 3]); + } else { + clusterWeights.push_back(0); + } + } else { + clusterWeights.push_back(0); + clusterWeights.push_back(0); + } + } else { + clusterWeights.push_back(0); + clusterWeights.push_back(0); + clusterWeights.push_back(0); + } + } + // Build weights (adapted from FBXSerializer.cpp) if (hfmModel.hasSkeletonJoints) { int numClusterIndices = clusterJoints.size(); @@ -1310,6 +1487,12 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mesh.meshExtents.addPoint(vertex); hfmModel.meshExtents.addPoint(vertex); } + + // Add epsilon to mesh extents to compensate for planar meshes + mesh.meshExtents.minimum -= glm::vec3(EPSILON, EPSILON, EPSILON); + mesh.meshExtents.maximum += glm::vec3(EPSILON, EPSILON, EPSILON); + hfmModel.meshExtents.minimum -= glm::vec3(EPSILON, EPSILON, EPSILON); + hfmModel.meshExtents.maximum += glm::vec3(EPSILON, EPSILON, EPSILON); mesh.meshIndex = hfmModel.meshes.size(); } @@ -1601,7 +1784,74 @@ bool GLTFSerializer::addArrayOfType(const hifi::ByteArray& bin, int byteOffset, return false; } -void GLTFSerializer::retriangulate(const QVector<int>& inIndices, const QVector<glm::vec3>& in_vertices, +template <typename T> +bool GLTFSerializer::addArrayOfFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray) { + bool success = true; + + if (accessor.defined["bufferView"]) { + GLTFBufferView& bufferview = _file.bufferviews[accessor.bufferView]; + GLTFBuffer& buffer = _file.buffers[bufferview.buffer]; + + int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0; + + success = addArrayOfType(buffer.blob, bufferview.byteOffset + accBoffset, accessor.count, outarray, accessor.type, + accessor.componentType); + } else { + 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); + } + } + + if (success) { + if (accessor.defined["sparse"]) { + QVector<int> out_sparse_indices_array; + + GLTFBufferView& sparseIndicesBufferview = _file.bufferviews[accessor.sparse.indices.bufferView]; + GLTFBuffer& sparseIndicesBuffer = _file.buffers[sparseIndicesBufferview.buffer]; + + int accSIBoffset = accessor.sparse.indices.defined["byteOffset"] ? accessor.sparse.indices.byteOffset : 0; + + success = addArrayOfType(sparseIndicesBuffer.blob, sparseIndicesBufferview.byteOffset + accSIBoffset, + accessor.sparse.count, out_sparse_indices_array, GLTFAccessorType::SCALAR, + accessor.sparse.indices.componentType); + if (success) { + QVector<T> out_sparse_values_array; + + GLTFBufferView& sparseValuesBufferview = _file.bufferviews[accessor.sparse.values.bufferView]; + GLTFBuffer& sparseValuesBuffer = _file.buffers[sparseValuesBufferview.buffer]; + + int accSVBoffset = accessor.sparse.values.defined["byteOffset"] ? accessor.sparse.values.byteOffset : 0; + + success = addArrayOfType(sparseValuesBuffer.blob, sparseValuesBufferview.byteOffset + accSVBoffset, + accessor.sparse.count, out_sparse_values_array, accessor.type, accessor.componentType); + + if (success) { + 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++) { + outarray[(out_sparse_indices_array[i] * 3) + j] = out_sparse_values_array[(i * 3) + j]; + } + } else { + success = false; + break; + } + } else { + success = false; + break; + } + } + } + } + } + } + + return success; +} + +void GLTFSerializer::retriangulate(const QVector<int>& inIndices, const QVector<glm::vec3>& in_vertices, const QVector<glm::vec3>& in_normals, QVector<int>& outIndices, QVector<glm::vec3>& out_vertices, QVector<glm::vec3>& out_normals) { for (int i = 0; i < inIndices.size(); i = i + 3) { @@ -1766,7 +2016,7 @@ void GLTFSerializer::hfmDebugDump(const HFMModel& hfmModel) { qCDebug(modelformat) << "---------------- Joints ----------------"; - foreach(HFMJoint joint, hfmModel.joints) { + foreach (HFMJoint joint, hfmModel.joints) { qCDebug(modelformat) << "\n"; qCDebug(modelformat) << " shapeInfo.avgPoint =" << joint.shapeInfo.avgPoint; qCDebug(modelformat) << " shapeInfo.debugLines =" << joint.shapeInfo.debugLines; diff --git a/libraries/fbx/src/GLTFSerializer.h b/libraries/fbx/src/GLTFSerializer.h index fa5a640fca..e7dc76e084 100755 --- a/libraries/fbx/src/GLTFSerializer.h +++ b/libraries/fbx/src/GLTFSerializer.h @@ -840,6 +840,9 @@ private: bool addArrayOfType(const hifi::ByteArray& bin, int byteOffset, int count, QVector<T>& outarray, int accessorType, int componentType); + template <typename T> + bool addArrayOfFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray); + void retriangulate(const QVector<int>& in_indices, const QVector<glm::vec3>& in_vertices, const QVector<glm::vec3>& in_normals, QVector<int>& out_indices, QVector<glm::vec3>& out_vertices, QVector<glm::vec3>& out_normals); From b00e0640c5169efacdef4e230fc0271deaa0d745 Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Thu, 11 Apr 2019 22:09:36 +0100 Subject: [PATCH 03/10] Convert to camel case, removed unused variable, replace tabs with spaces, remove deprecated normals generation. --- libraries/fbx/src/GLTFSerializer.cpp | 186 +++++++-------------------- 1 file changed, 45 insertions(+), 141 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index 78569fa78f..e7b9dd79f7 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -37,27 +37,27 @@ #include "FBXSerializer.h" -#define GLTF_GET_INDICIES(acc_count) int index1 = (indices[n + 0] * acc_count); int index2 = (indices[n + 1] * acc_count); int index3 = (indices[n + 2] * acc_count); +#define GLTF_GET_INDICIES(accCount) int index1 = (indices[n + 0] * accCount); int index2 = (indices[n + 1] * accCount); int index3 = (indices[n + 2] * accCount); -#define GLTF_APPEND_ARRAY_1(new_array, old_array) GLTF_GET_INDICIES(1) \ -new_array.append(old_array[index1]); \ -new_array.append(old_array[index2]); \ -new_array.append(old_array[index3]); +#define GLTF_APPEND_ARRAY_1(newArray, oldArray) GLTF_GET_INDICIES(1) \ +newArray.append(oldArray[index1]); \ +newArray.append(oldArray[index2]); \ +newArray.append(oldArray[index3]); -#define GLTF_APPEND_ARRAY_2(new_array, old_array) GLTF_GET_INDICIES(2) \ -new_array.append(old_array[index1]); new_array.append(old_array[index1 + 1]); \ -new_array.append(old_array[index2]); new_array.append(old_array[index2 + 1]); \ -new_array.append(old_array[index3]); new_array.append(old_array[index3 + 1]); +#define GLTF_APPEND_ARRAY_2(newArray, oldArray) GLTF_GET_INDICIES(2) \ +newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); \ +newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); \ +newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]); -#define GLTF_APPEND_ARRAY_3(new_array, old_array) GLTF_GET_INDICIES(3) \ -new_array.append(old_array[index1]); new_array.append(old_array[index1 + 1]); new_array.append(old_array[index1 + 2]); \ -new_array.append(old_array[index2]); new_array.append(old_array[index2 + 1]); new_array.append(old_array[index2 + 2]); \ -new_array.append(old_array[index3]); new_array.append(old_array[index3 + 1]); new_array.append(old_array[index3 + 2]); +#define GLTF_APPEND_ARRAY_3(newArray, oldArray) GLTF_GET_INDICIES(3) \ +newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); newArray.append(oldArray[index1 + 2]); \ +newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); newArray.append(oldArray[index2 + 2]); \ +newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]); newArray.append(oldArray[index3 + 2]); -#define GLTF_APPEND_ARRAY_4(new_array, old_array) GLTF_GET_INDICIES(4) \ -new_array.append(old_array[index1]); new_array.append(old_array[index1 + 1]); new_array.append(old_array[index1 + 2]); new_array.append(old_array[index1 + 3]); \ -new_array.append(old_array[index2]); new_array.append(old_array[index2 + 1]); new_array.append(old_array[index2 + 2]); new_array.append(old_array[index2 + 3]); \ -new_array.append(old_array[index3]); new_array.append(old_array[index3 + 1]); new_array.append(old_array[index3 + 2]); new_array.append(old_array[index3 + 3]); +#define GLTF_APPEND_ARRAY_4(newArray, oldArray) GLTF_GET_INDICIES(4) \ +newArray.append(oldArray[index1]); newArray.append(oldArray[index1 + 1]); newArray.append(oldArray[index1 + 2]); newArray.append(oldArray[index1 + 3]); \ +newArray.append(oldArray[index2]); newArray.append(oldArray[index2 + 1]); newArray.append(oldArray[index2 + 2]); newArray.append(oldArray[index2 + 3]); \ +newArray.append(oldArray[index3]); newArray.append(oldArray[index3 + 1]); newArray.append(oldArray[index3 + 2]); newArray.append(oldArray[index3 + 3]); bool GLTFSerializer::getStringVal(const QJsonObject& object, const QString& fieldname, QString& value, QMap<QString, bool>& defined) { @@ -997,7 +997,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& hfmModel.materials[matid] = HFMMaterial(); HFMMaterial& hfmMaterial = hfmModel.materials[matid]; hfmMaterial._material = std::make_shared<graphics::Material>(); - hfmMaterial.name = hfmMaterial.materialID = matid; + hfmMaterial.name = hfmMaterial.materialID = matid; setHFMMaterial(hfmMaterial, _file.materials[i]); } @@ -1044,15 +1044,15 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& QVector<float> vertices; QVector<float> normals; QVector<float> tangents; - int tangent_stride = 0; + int tangentStride = 0; QVector<float> texcoords; QVector<float> texcoords2; QVector<float> colors; - int color_stride = 0; + int colorStride = 0; QVector<uint16_t> joints; - int joint_stride = 0; + int jointStride = 0; QVector<float> weights; - int weight_stride = 0; + int weightStride = 0; bool success = addArrayOfFromAccessor(indicesAccessor, indices); @@ -1073,7 +1073,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& GLTFAccessor& accessor = _file.accessors[accessorIdx]; - int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0; if (key == "POSITION") { success = addArrayOfFromAccessor(accessor, vertices); if (!success) { @@ -1104,9 +1103,9 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } if (accessor.type == GLTFAccessorType::VEC4) { - tangent_stride = 4; + tangentStride = 4; } else if (accessor.type == GLTFAccessorType::VEC3) { - tangent_stride = 3; + tangentStride = 3; } else { qWarning(modelformat) << "Invalid accessor type on glTF TANGENT data for model " << _url; continue; @@ -1141,9 +1140,9 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } if (accessor.type == GLTFAccessorType::VEC4) { - color_stride = 4; + colorStride = 4; } else if (accessor.type == GLTFAccessorType::VEC3) { - color_stride = 3; + colorStride = 3; } else { qWarning(modelformat) << "Invalid accessor type on glTF COLOR_0 data for model " << _url; continue; @@ -1156,13 +1155,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } if (accessor.type == GLTFAccessorType::VEC4) { - joint_stride = 4; + jointStride = 4; } else if (accessor.type == GLTFAccessorType::VEC3) { - joint_stride = 3; + jointStride = 3; } else if (accessor.type == GLTFAccessorType::VEC2) { - joint_stride = 2; + jointStride = 2; } else if (accessor.type == GLTFAccessorType::SCALAR) { - joint_stride = 1; + jointStride = 1; } else { qWarning(modelformat) << "Invalid accessor type on glTF JOINTS_0 data for model " << _url; continue; @@ -1175,13 +1174,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } if (accessor.type == GLTFAccessorType::VEC4) { - weight_stride = 4; + weightStride = 4; } else if (accessor.type == GLTFAccessorType::VEC3) { - weight_stride = 3; + weightStride = 3; } else if (accessor.type == GLTFAccessorType::VEC2) { - weight_stride = 2; + weightStride = 2; } else if (accessor.type == GLTFAccessorType::SCALAR) { - weight_stride = 1; + weightStride = 1; } else { qWarning(modelformat) << "Invalid accessor type on glTF WEIGHTS_0 data for model " << _url; continue; @@ -1189,101 +1188,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } - // generate the normals if they don't exist - if (normals.size() == 0) { - QVector<int> new_indices; - QVector<float> new_vertices; - QVector<float> new_normals; - QVector<float> new_tangents; - QVector<float> new_texcoords; - QVector<float> new_texcoords2; - QVector<float> new_colors; - QVector<uint16_t> new_joints; - QVector<float> new_weights; - - for (int n = 0; n < indices.size(); n = n + 3) { - int v1_index = (indices[n + 0] * 3); - int v2_index = (indices[n + 1] * 3); - int v3_index = (indices[n + 2] * 3); - - glm::vec3 v1 = glm::vec3(vertices[v1_index], vertices[v1_index + 1], vertices[v1_index + 2]); - glm::vec3 v2 = glm::vec3(vertices[v2_index], vertices[v2_index + 1], vertices[v2_index + 2]); - glm::vec3 v3 = glm::vec3(vertices[v3_index], vertices[v3_index + 1], vertices[v3_index + 2]); - - new_vertices.append(v1.x); new_vertices.append(v1.y); new_vertices.append(v1.z); - new_vertices.append(v2.x); new_vertices.append(v2.y); new_vertices.append(v2.z); - new_vertices.append(v3.x); new_vertices.append(v3.y); new_vertices.append(v3.z); - - glm::vec3 norm = glm::normalize(glm::cross(v2 - v1, v3 - v1)); - - new_normals.append(norm.x); new_normals.append(norm.y); new_normals.append(norm.z); - new_normals.append(norm.x); new_normals.append(norm.y); new_normals.append(norm.z); - new_normals.append(norm.x); new_normals.append(norm.y); new_normals.append(norm.z); - - if (tangents.size() > 0) { - if (tangent_stride == 4) { - GLTF_APPEND_ARRAY_4(new_tangents, tangents) - } else { - GLTF_APPEND_ARRAY_3(new_tangents, tangents) - } - } - - if (texcoords.size() > 0) { - GLTF_APPEND_ARRAY_2(new_texcoords, texcoords) - } - - if (texcoords2.size() > 0) { - GLTF_APPEND_ARRAY_2(new_texcoords2, texcoords2) - } - - if (colors.size() > 0) { - if (color_stride == 4) { - GLTF_APPEND_ARRAY_4(new_colors, colors) - } else { - GLTF_APPEND_ARRAY_3(new_colors, colors) - } - } - - if (joints.size() > 0) { - if (joint_stride == 4) { - GLTF_APPEND_ARRAY_4(new_joints, joints) - } else if (joint_stride == 3) { - GLTF_APPEND_ARRAY_3(new_joints, joints) - } else if (joint_stride == 2) { - GLTF_APPEND_ARRAY_2(new_joints, joints) - } else { - GLTF_APPEND_ARRAY_1(new_joints, joints) - } - } - - if (weights.size() > 0) { - if (weight_stride == 4) { - GLTF_APPEND_ARRAY_4(new_weights, weights) - } else if (weight_stride == 3) { - GLTF_APPEND_ARRAY_3(new_weights, weights) - } else if (weight_stride == 2) { - GLTF_APPEND_ARRAY_2(new_weights, weights) - } else { - GLTF_APPEND_ARRAY_1(new_weights, weights) - } - } - - new_indices.append(n); - new_indices.append(n + 1); - new_indices.append(n + 2); - } - - vertices = new_vertices; - normals = new_normals; - tangents = new_tangents; - indices = new_indices; - texcoords = new_texcoords; - texcoords2 = new_texcoords2; - colors = new_colors; - joints = new_joints; - weights = new_weights; - } - for (int n = 0; n < indices.count(); n++) { part.triangleIndices.push_back(indices[n] + prevMeshVerticesCount); } @@ -1296,8 +1200,8 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2])); } - for (int n = 0; n < tangents.size(); n += tangent_stride) { - float tanW = tangent_stride == 4 ? tangents[n + 3] : 1; + for (int n = 0; n < tangents.size(); n += tangentStride) { + float tanW = tangentStride == 4 ? tangents[n + 3] : 1; mesh.tangents.push_back(glm::vec3(tanW * tangents[n], tangents[n + 1], tanW * tangents[n + 2])); } @@ -1308,17 +1212,17 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mesh.texCoords1.push_back(glm::vec2(texcoords2[n], texcoords2[n + 1])); } - for (int n = 0; n < colors.size(); n += color_stride) { + for (int n = 0; n < colors.size(); n += colorStride) { mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2])); } - for (int n = 0; n < joints.size(); n += joint_stride) { + for (int n = 0; n < joints.size(); n += jointStride) { clusterJoints.push_back(joints[n]); - if (joint_stride > 1) { + if (jointStride > 1) { clusterJoints.push_back(joints[n + 1]); - if (joint_stride > 2) { + if (jointStride > 2) { clusterJoints.push_back(joints[n + 2]); - if (joint_stride > 3) { + if (jointStride > 3) { clusterJoints.push_back(joints[n + 3]); } else { clusterJoints.push_back(0); @@ -1334,13 +1238,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } - for (int n = 0; n < weights.size(); n += weight_stride) { + for (int n = 0; n < weights.size(); n += weightStride) { clusterWeights.push_back(weights[n]); - if (weight_stride > 1) { + if (weightStride > 1) { clusterWeights.push_back(weights[n + 1]); - if (weight_stride > 2) { + if (weightStride > 2) { clusterWeights.push_back(weights[n + 2]); - if (weight_stride > 3) { + if (weightStride > 3) { clusterWeights.push_back(weights[n + 3]); } else { clusterWeights.push_back(0); From a1279fa0b16b1b608450aec074477e69b0ccf492 Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Mon, 22 Apr 2019 21:10:12 +0100 Subject: [PATCH 04/10] Fixed requested indentation issues. # Conflicts: # libraries/fbx/src/GLTFSerializer.cpp --- libraries/fbx/src/GLTFSerializer.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index e7b9dd79f7..3f569a3c3e 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -872,7 +872,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // collect transforms for a node's parents, grandparents, etc. _file.nodes[nodecount].transforms.push_back(getModelTransform(parentNode)); parentIndex = parents[parentIndex]; - } + } nodecount++; } @@ -900,10 +900,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& sortedNodes[j] = currentNode; i++; currentNode = sortedNodes[i]; - } + } j++; - } - } + } + } } @@ -931,7 +931,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& joint.translation = extractTranslation(joint.transform); joint.rotation = glmExtractRotation(joint.transform); glm::vec3 scale = extractScale(joint.transform); - joint.postTransform = glm::scale(glm::mat4(), scale); + joint.postTransform = glm::scale(glm::mat4(), scale); joint.name = node.name; joint.isSkeletonJoint = false; @@ -982,7 +982,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& QString unknown = "Default"; int ukcount = 0; foreach(auto material, _file.materials) { - if (!(material.defined["name"])) { + if (!material.defined["name"]) { QString name = unknown + QString::number(ukcount++); material.name = name; material.defined.insert("name", true); @@ -1017,8 +1017,8 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& cluster.inverseBindMatrix = glm::mat4(); cluster.inverseBindTransform = Transform(cluster.inverseBindMatrix); mesh.clusters.append(cluster); - } else { // skinned model - for (int j = 0; j < numNodes; j++) { + } else { // skinned model + for (int j = 0; j < numNodes; j++) { HFMCluster cluster; cluster.jointIndex = j; cluster.inverseBindMatrix = jointInverseBindTransforms[j]; @@ -1026,7 +1026,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& mesh.clusters.append(cluster); } } - HFMCluster root; + HFMCluster root; root.jointIndex = 0; root.inverseBindMatrix = jointInverseBindTransforms[root.jointIndex]; root.inverseBindTransform = Transform(root.inverseBindMatrix); From 9b7df26d9195ff00b5fb7dd6b961284e6ea594ba Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Sat, 27 Apr 2019 11:20:09 +0100 Subject: [PATCH 05/10] Fixed cluster weighting regression. --- libraries/fbx/src/GLTFSerializer.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index 3f569a3c3e..7c13d58968 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -1262,15 +1262,20 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // Build weights (adapted from FBXSerializer.cpp) if (hfmModel.hasSkeletonJoints) { - int numClusterIndices = clusterJoints.size(); + int prevMeshClusterIndexCount = mesh.clusterIndices.count(); + int prevMeshClusterWeightCount = mesh.clusterWeights.count(); const int WEIGHTS_PER_VERTEX = 4; const float ALMOST_HALF = 0.499f; - int numVertices = mesh.vertices.size(); - mesh.clusterIndices.fill(mesh.clusters.size() - 1, numClusterIndices); - mesh.clusterWeights.fill(0, numClusterIndices); + 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++) { + mesh.clusterIndices.push_back(mesh.clusters.size() - 1); + mesh.clusterWeights.push_back(0); + } for (int c = 0; c < clusterJoints.size(); c++) { - mesh.clusterIndices[c] = originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[c]]]; + mesh.clusterIndices[prevMeshClusterIndexCount+c] = originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[c]]]; } // normalize and compress to 16-bits @@ -1284,10 +1289,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& if (totalWeight > 0.0f) { float weightScalingFactor = (float)(UINT16_MAX) / totalWeight; for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) { - mesh.clusterWeights[k] = (uint16_t)(weightScalingFactor * clusterWeights[k] + ALMOST_HALF); + mesh.clusterWeights[prevMeshClusterWeightCount+k] = (uint16_t)(weightScalingFactor * clusterWeights[k] + ALMOST_HALF); } } else { - mesh.clusterWeights[j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF); + mesh.clusterWeights[prevMeshClusterWeightCount+j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF); } } } From 0bf216ab730c91fcc98bd02cf5e0db9f6aec11dc Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Sat, 27 Apr 2019 12:42:37 +0100 Subject: [PATCH 06/10] Sparse accessors support for skin inverse bind matrices and shapekey target data. --- libraries/fbx/src/GLTFSerializer.cpp | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index 7c13d58968..f5cc9ff03c 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -812,32 +812,16 @@ glm::mat4 GLTFSerializer::getModelTransform(const GLTFNode& node) { void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>& inverseBindMatrixValues) { for (auto &skin : _file.skins) { GLTFAccessor& indicesAccessor = _file.accessors[skin.inverseBindMatrices]; - GLTFBufferView& indicesBufferview = _file.bufferviews[indicesAccessor.bufferView]; - GLTFBuffer& indicesBuffer = _file.buffers[indicesBufferview.buffer]; - int accBoffset = indicesAccessor.defined["byteOffset"] ? indicesAccessor.byteOffset : 0; QVector<float> matrices; - addArrayOfType(indicesBuffer.blob, - indicesBufferview.byteOffset + accBoffset, - indicesAccessor.count, - matrices, - indicesAccessor.type, - indicesAccessor.componentType); + addArrayOfFromAccessor(indicesAccessor, matrices); inverseBindMatrixValues.push_back(matrices.toStdVector()); } } void GLTFSerializer::generateTargetData(int index, float weight, QVector<glm::vec3>& returnVector) { GLTFAccessor& accessor = _file.accessors[index]; - GLTFBufferView& bufferview = _file.bufferviews[accessor.bufferView]; - GLTFBuffer& buffer = _file.buffers[bufferview.buffer]; - int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0; QVector<float> storedValues; - addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - storedValues, - accessor.type, - accessor.componentType); + addArrayOfFromAccessor(accessor, storedValues); for (int n = 0; n < storedValues.size(); n = n + 3) { returnVector.push_back(glm::vec3(weight * storedValues[n], weight * storedValues[n + 1], weight * storedValues[n + 2])); } From 95ec51e37bb27b6d273433bb32f149285ac150d1 Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Mon, 29 Apr 2019 20:35:38 +0100 Subject: [PATCH 07/10] Formatting and naming changes. Tweak to structure of skinning code. --- libraries/fbx/src/GLTFSerializer.cpp | 49 ++++++++++++++-------------- libraries/fbx/src/GLTFSerializer.h | 2 +- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index f5cc9ff03c..99211fb6fa 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -813,7 +813,7 @@ void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>& for (auto &skin : _file.skins) { GLTFAccessor& indicesAccessor = _file.accessors[skin.inverseBindMatrices]; QVector<float> matrices; - addArrayOfFromAccessor(indicesAccessor, matrices); + addArrayFromAccessor(indicesAccessor, matrices); inverseBindMatrixValues.push_back(matrices.toStdVector()); } } @@ -821,7 +821,7 @@ void GLTFSerializer::getSkinInverseBindMatrices(std::vector<std::vector<float>>& void GLTFSerializer::generateTargetData(int index, float weight, QVector<glm::vec3>& returnVector) { GLTFAccessor& accessor = _file.accessors[index]; QVector<float> storedValues; - addArrayOfFromAccessor(accessor, storedValues); + addArrayFromAccessor(accessor, storedValues); for (int n = 0; n < storedValues.size(); n = n + 3) { returnVector.push_back(glm::vec3(weight * storedValues[n], weight * storedValues[n + 1], weight * storedValues[n + 2])); } @@ -849,7 +849,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& nodecount = 0; foreach(auto &node, _file.nodes) { // collect node transform - _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); + _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); int parentIndex = parents[nodecount]; while (parentIndex != -1) { const auto& parentNode = _file.nodes[parentIndex]; @@ -1038,7 +1038,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& QVector<float> weights; int weightStride = 0; - bool success = addArrayOfFromAccessor(indicesAccessor, indices); + bool success = addArrayFromAccessor(indicesAccessor, indices); if (!success) { qWarning(modelformat) << "There was a problem reading glTF INDICES data for model " << _url; @@ -1058,7 +1058,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& GLTFAccessor& accessor = _file.accessors[accessorIdx]; if (key == "POSITION") { - success = addArrayOfFromAccessor(accessor, vertices); + success = addArrayFromAccessor(accessor, vertices); if (!success) { qWarning(modelformat) << "There was a problem reading glTF POSITION data for model " << _url; continue; @@ -1069,7 +1069,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } } else if (key == "NORMAL") { - success = addArrayOfFromAccessor(accessor, normals); + success = addArrayFromAccessor(accessor, normals); if (!success) { qWarning(modelformat) << "There was a problem reading glTF NORMAL data for model " << _url; continue; @@ -1080,7 +1080,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } } else if (key == "TANGENT") { - success = addArrayOfFromAccessor(accessor, tangents); + success = addArrayFromAccessor(accessor, tangents); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TANGENT data for model " << _url; continue; @@ -1095,7 +1095,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } } else if (key == "TEXCOORD_0") { - success = addArrayOfFromAccessor(accessor, texcoords); + success = addArrayFromAccessor(accessor, texcoords); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_0 data for model " << _url; continue; @@ -1106,7 +1106,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } } else if (key == "TEXCOORD_1") { - success = addArrayOfFromAccessor(accessor, texcoords2); + success = addArrayFromAccessor(accessor, texcoords2); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_1 data for model " << _url; continue; @@ -1117,7 +1117,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } } else if (key == "COLOR_0") { - success = addArrayOfFromAccessor(accessor, colors); + success = addArrayFromAccessor(accessor, colors); if (!success) { qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url; continue; @@ -1132,7 +1132,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } } else if (key == "JOINTS_0") { - success = addArrayOfFromAccessor(accessor, joints); + success = addArrayFromAccessor(accessor, joints); if (!success) { qWarning(modelformat) << "There was a problem reading glTF JOINTS_0 data for model " << _url; continue; @@ -1151,7 +1151,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } } else if (key == "WEIGHTS_0") { - success = addArrayOfFromAccessor(accessor, weights); + success = addArrayFromAccessor(accessor, weights); if (!success) { qWarning(modelformat) << "There was a problem reading glTF WEIGHTS_0 data for model " << _url; continue; @@ -1252,15 +1252,10 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& const float ALMOST_HALF = 0.499f; 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++) { - mesh.clusterIndices.push_back(mesh.clusters.size() - 1); - mesh.clusterWeights.push_back(0); - } - - for (int c = 0; c < clusterJoints.size(); c++) { - mesh.clusterIndices[prevMeshClusterIndexCount+c] = originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[c]]]; - } + mesh.clusterIndices.resize(mesh.clusterIndices.size() + + numVertices * WEIGHTS_PER_VERTEX); + mesh.clusterWeights.resize(mesh.clusterWeights.size() + + numVertices * WEIGHTS_PER_VERTEX); // normalize and compress to 16-bits for (int i = 0; i < numVertices; ++i) { @@ -1268,15 +1263,21 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& float totalWeight = 0.0f; for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) { + mesh.clusterIndices[prevMeshClusterIndexCount + k] = + originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[k]]]; + totalWeight += clusterWeights[k]; } if (totalWeight > 0.0f) { float weightScalingFactor = (float)(UINT16_MAX) / totalWeight; for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) { - mesh.clusterWeights[prevMeshClusterWeightCount+k] = (uint16_t)(weightScalingFactor * clusterWeights[k] + ALMOST_HALF); + mesh.clusterWeights[prevMeshClusterWeightCount + k] = (uint16_t)(weightScalingFactor * clusterWeights[k] + ALMOST_HALF); } } else { - mesh.clusterWeights[prevMeshClusterWeightCount+j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF); + mesh.clusterWeights[prevMeshClusterWeightCount + j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF); + for (int k = j + 1; k < j + WEIGHTS_PER_VERTEX; ++k) { + mesh.clusterWeights[prevMeshClusterWeightCount + k] = 0; + } } } } @@ -1678,7 +1679,7 @@ bool GLTFSerializer::addArrayOfType(const hifi::ByteArray& bin, int byteOffset, } template <typename T> -bool GLTFSerializer::addArrayOfFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray) { +bool GLTFSerializer::addArrayFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray) { bool success = true; if (accessor.defined["bufferView"]) { diff --git a/libraries/fbx/src/GLTFSerializer.h b/libraries/fbx/src/GLTFSerializer.h index e7dc76e084..4d72805863 100755 --- a/libraries/fbx/src/GLTFSerializer.h +++ b/libraries/fbx/src/GLTFSerializer.h @@ -841,7 +841,7 @@ private: QVector<T>& outarray, int accessorType, int componentType); template <typename T> - bool addArrayOfFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray); + bool addArrayFromAccessor(GLTFAccessor& accessor, QVector<T>& outarray); void retriangulate(const QVector<int>& in_indices, const QVector<glm::vec3>& in_vertices, const QVector<glm::vec3>& in_normals, QVector<int>& out_indices, From a07507430335e47755dc5c1919350eb66f02c5ba Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Mon, 29 Apr 2019 21:26:13 +0100 Subject: [PATCH 08/10] Revert to previous clusterIndices and clusterWeight expansion implementation. --- libraries/fbx/src/GLTFSerializer.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index 99211fb6fa..85e55f226b 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -1252,10 +1252,16 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& const float ALMOST_HALF = 0.499f; int numVertices = mesh.vertices.size() - prevMeshVerticesCount; - mesh.clusterIndices.resize(mesh.clusterIndices.size() - + numVertices * WEIGHTS_PER_VERTEX); - mesh.clusterWeights.resize(mesh.clusterWeights.size() - + numVertices * WEIGHTS_PER_VERTEX); + // Append new cluster indices and weights for this mesh part + 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++) { + mesh.clusterIndices[prevMeshClusterIndexCount + c] = + originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[c]]]; + } // normalize and compress to 16-bits for (int i = 0; i < numVertices; ++i) { @@ -1263,9 +1269,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& float totalWeight = 0.0f; for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) { - mesh.clusterIndices[prevMeshClusterIndexCount + k] = - originalToNewNodeIndexMap[_file.skins[node.skin].joints[clusterJoints[k]]]; - totalWeight += clusterWeights[k]; } if (totalWeight > 0.0f) { @@ -1275,9 +1278,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } else { mesh.clusterWeights[prevMeshClusterWeightCount + j] = (uint16_t)((float)(UINT16_MAX) + ALMOST_HALF); - for (int k = j + 1; k < j + WEIGHTS_PER_VERTEX; ++k) { - mesh.clusterWeights[prevMeshClusterWeightCount + k] = 0; - } } } } From 7987ed14b09bf219f692e4677ccd2208c58ec26d Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Sat, 11 May 2019 04:30:14 +0100 Subject: [PATCH 09/10] Fix mismatched meshpart attributes (generates dummy buffers), re-added normals generation routine, buffer size checks, detect out-of-range indices, --- libraries/fbx/src/GLTFSerializer.cpp | 340 +++++++++++++++++++++------ 1 file changed, 267 insertions(+), 73 deletions(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index 85e55f226b..b06b8f1822 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -1016,6 +1016,16 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& root.inverseBindTransform = Transform(root.inverseBindMatrix); mesh.clusters.append(root); + QList<QString> meshAttributes; + foreach(auto &primitive, _file.meshes[node.mesh].primitives) { + QList<QString> keys = primitive.attributes.values.keys(); + foreach (auto &key, keys) { + if (!meshAttributes.contains(key)) { + meshAttributes.push_back(key); + } + } + } + foreach(auto &primitive, _file.meshes[node.mesh].primitives) { HFMMeshPart part = HFMMeshPart(); @@ -1026,17 +1036,21 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& // Buffers QVector<int> indices; QVector<float> vertices; + int verticesStride = 3; QVector<float> normals; + int normalStride = 3; QVector<float> tangents; - int tangentStride = 0; + int tangentStride = 4; QVector<float> texcoords; + int texCoordStride = 2; QVector<float> texcoords2; + int texCoord2Stride = 2; QVector<float> colors; - int colorStride = 0; + int colorStride = 3; QVector<uint16_t> joints; - int jointStride = 0; + int jointStride = 4; QVector<float> weights; - int weightStride = 0; + int weightStride = 4; bool success = addArrayFromAccessor(indicesAccessor, indices); @@ -1058,34 +1072,28 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& GLTFAccessor& accessor = _file.accessors[accessorIdx]; if (key == "POSITION") { + if (accessor.type != GLTFAccessorType::VEC3) { + qWarning(modelformat) << "Invalid accessor type on glTF POSITION data for model " << _url; + continue; + } + success = addArrayFromAccessor(accessor, vertices); if (!success) { qWarning(modelformat) << "There was a problem reading glTF POSITION data for model " << _url; continue; } - + } else if (key == "NORMAL") { if (accessor.type != GLTFAccessorType::VEC3) { - qWarning(modelformat) << "Invalid accessor type on glTF POSITION data for model " << _url; + qWarning(modelformat) << "Invalid accessor type on glTF NORMAL data for model " << _url; continue; } - } else if (key == "NORMAL") { + success = addArrayFromAccessor(accessor, normals); if (!success) { qWarning(modelformat) << "There was a problem reading glTF NORMAL data for model " << _url; continue; } - - if (accessor.type != GLTFAccessorType::VEC3) { - qWarning(modelformat) << "Invalid accessor type on glTF NORMAL data for model " << _url; - continue; - } } else if (key == "TANGENT") { - success = addArrayFromAccessor(accessor, tangents); - if (!success) { - qWarning(modelformat) << "There was a problem reading glTF TANGENT data for model " << _url; - continue; - } - if (accessor.type == GLTFAccessorType::VEC4) { tangentStride = 4; } else if (accessor.type == GLTFAccessorType::VEC3) { @@ -1094,6 +1102,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& qWarning(modelformat) << "Invalid accessor type on glTF TANGENT data for model " << _url; continue; } + + success = addArrayFromAccessor(accessor, tangents); + if (!success) { + qWarning(modelformat) << "There was a problem reading glTF TANGENT data for model " << _url; + tangentStride = 0; + continue; + } } else if (key == "TEXCOORD_0") { success = addArrayFromAccessor(accessor, texcoords); if (!success) { @@ -1117,12 +1132,6 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& continue; } } else if (key == "COLOR_0") { - success = addArrayFromAccessor(accessor, colors); - if (!success) { - qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url; - continue; - } - if (accessor.type == GLTFAccessorType::VEC4) { colorStride = 4; } else if (accessor.type == GLTFAccessorType::VEC3) { @@ -1131,13 +1140,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& qWarning(modelformat) << "Invalid accessor type on glTF COLOR_0 data for model " << _url; continue; } - } else if (key == "JOINTS_0") { - success = addArrayFromAccessor(accessor, joints); + + success = addArrayFromAccessor(accessor, colors); if (!success) { - qWarning(modelformat) << "There was a problem reading glTF JOINTS_0 data for model " << _url; + qWarning(modelformat) << "There was a problem reading glTF COLOR_0 data for model " << _url; continue; } - + } else if (key == "JOINTS_0") { if (accessor.type == GLTFAccessorType::VEC4) { jointStride = 4; } else if (accessor.type == GLTFAccessorType::VEC3) { @@ -1150,13 +1159,13 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& qWarning(modelformat) << "Invalid accessor type on glTF JOINTS_0 data for model " << _url; continue; } - } else if (key == "WEIGHTS_0") { - success = addArrayFromAccessor(accessor, weights); + + success = addArrayFromAccessor(accessor, joints); if (!success) { - qWarning(modelformat) << "There was a problem reading glTF WEIGHTS_0 data for model " << _url; + qWarning(modelformat) << "There was a problem reading glTF JOINTS_0 data for model " << _url; continue; } - + } else if (key == "WEIGHTS_0") { if (accessor.type == GLTFAccessorType::VEC4) { weightStride = 4; } else if (accessor.type == GLTFAccessorType::VEC3) { @@ -1169,78 +1178,263 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& qWarning(modelformat) << "Invalid accessor type on glTF WEIGHTS_0 data for model " << _url; continue; } + + success = addArrayFromAccessor(accessor, weights); + if (!success) { + qWarning(modelformat) << "There was a problem reading glTF WEIGHTS_0 data for model " << _url; + continue; + } } } - for (int n = 0; n < indices.count(); n++) { - part.triangleIndices.push_back(indices[n] + prevMeshVerticesCount); + // Validation stage + if (indices.count() == 0) { + qWarning(modelformat) << "Missing indices for model " << _url; + continue; + } + if (vertices.count() == 0) { + qWarning(modelformat) << "Missing vertices for model " << _url; + continue; } - for (int n = 0; n < vertices.size(); n = n + 3) { + int partVerticesCount = vertices.size() / 3; + + // generate the normals if they don't exist + if (normals.size() == 0) { + QVector<int> newIndices; + QVector<float> newVertices; + QVector<float> newNormals; + QVector<float> newTexcoords; + QVector<float> newTexcoords2; + QVector<float> newColors; + QVector<uint16_t> newJoints; + QVector<float> newWeights; + + for (int n = 0; n < indices.size(); n = n + 3) { + int v1_index = (indices[n + 0] * 3); + int v2_index = (indices[n + 1] * 3); + int v3_index = (indices[n + 2] * 3); + + glm::vec3 v1 = glm::vec3(vertices[v1_index], vertices[v1_index + 1], vertices[v1_index + 2]); + glm::vec3 v2 = glm::vec3(vertices[v2_index], vertices[v2_index + 1], vertices[v2_index + 2]); + glm::vec3 v3 = glm::vec3(vertices[v3_index], vertices[v3_index + 1], vertices[v3_index + 2]); + + newVertices.append(v1.x); + newVertices.append(v1.y); + newVertices.append(v1.z); + newVertices.append(v2.x); + newVertices.append(v2.y); + newVertices.append(v2.z); + newVertices.append(v3.x); + newVertices.append(v3.y); + newVertices.append(v3.z); + + glm::vec3 norm = glm::normalize(glm::cross(v2 - v1, v3 - v1)); + + newNormals.append(norm.x); + newNormals.append(norm.y); + newNormals.append(norm.z); + newNormals.append(norm.x); + newNormals.append(norm.y); + newNormals.append(norm.z); + newNormals.append(norm.x); + newNormals.append(norm.y); + newNormals.append(norm.z); + + if (texcoords.size() == partVerticesCount * texCoordStride) { + GLTF_APPEND_ARRAY_2(newTexcoords, texcoords) + } + + if (texcoords2.size() == partVerticesCount * texCoord2Stride) { + GLTF_APPEND_ARRAY_2(newTexcoords2, texcoords2) + } + + if (colors.size() == partVerticesCount * colorStride) { + if (colorStride == 4) { + GLTF_APPEND_ARRAY_4(newColors, colors) + } else { + GLTF_APPEND_ARRAY_3(newColors, colors) + } + } + + if (joints.size() == partVerticesCount * jointStride) { + if (jointStride == 4) { + GLTF_APPEND_ARRAY_4(newJoints, joints) + } else if (jointStride == 3) { + GLTF_APPEND_ARRAY_3(newJoints, joints) + } else if (jointStride == 2) { + GLTF_APPEND_ARRAY_2(newJoints, joints) + } else { + GLTF_APPEND_ARRAY_1(newJoints, joints) + } + } + + if (weights.size() == partVerticesCount * weightStride) { + if (weightStride == 4) { + GLTF_APPEND_ARRAY_4(newWeights, weights) + } else if (weightStride == 3) { + GLTF_APPEND_ARRAY_3(newWeights, weights) + } else if (weightStride == 2) { + GLTF_APPEND_ARRAY_2(newWeights, weights) + } else { + GLTF_APPEND_ARRAY_1(newWeights, weights) + } + } + newIndices.append(n); + newIndices.append(n + 1); + newIndices.append(n + 2); + } + + vertices = newVertices; + normals = newNormals; + tangents = QVector<float>(); + texcoords = newTexcoords; + texcoords2 = newTexcoords2; + colors = newColors; + joints = newJoints; + weights = newWeights; + indices = newIndices; + + partVerticesCount = vertices.size() / 3; + } + + QVector<int> validatedIndices; + for (int n = 0; n < indices.count(); n++) { + if (indices[n] < partVerticesCount) { + validatedIndices.push_back(indices[n] + prevMeshVerticesCount); + } else { + validatedIndices = QVector<int>(); + break; + } + } + + if (validatedIndices.size() == 0) { + qWarning(modelformat) << "Indices out of range for model " << _url; + continue; + } + + part.triangleIndices.append(validatedIndices); + + for (int n = 0; n < vertices.size(); n = n + verticesStride) { mesh.vertices.push_back(glm::vec3(vertices[n], vertices[n + 1], vertices[n + 2])); } - for (int n = 0; n < normals.size(); n = n + 3) { + for (int n = 0; n < normals.size(); n = n + normalStride) { mesh.normals.push_back(glm::vec3(normals[n], normals[n + 1], normals[n + 2])); } - for (int n = 0; n < tangents.size(); n += tangentStride) { - float tanW = tangentStride == 4 ? tangents[n + 3] : 1; - mesh.tangents.push_back(glm::vec3(tanW * tangents[n], tangents[n + 1], tanW * tangents[n + 2])); + // TODO: add correct tangent generation + if (tangents.size() == partVerticesCount * tangentStride) { + for (int n = 0; n < tangents.size(); n += tangentStride) { + float tanW = tangentStride == 4 ? tangents[n + 3] : 1; + mesh.tangents.push_back(glm::vec3(tanW * tangents[n], tangents[n + 1], tanW * tangents[n + 2])); + } + } else { + if (meshAttributes.contains("TANGENT")) { + for (int i = 0; i < partVerticesCount; i++) { + mesh.tangents.push_back(glm::vec3(0.0f, 0.0f, 0.0f)); + } + } } - for (int n = 0; n < texcoords.size(); n = n + 2) { - mesh.texCoords.push_back(glm::vec2(texcoords[n], texcoords[n + 1])); - } - for (int n = 0; n < texcoords2.size(); n = n + 2) { - mesh.texCoords1.push_back(glm::vec2(texcoords2[n], texcoords2[n + 1])); + if (texcoords.size() == partVerticesCount * texCoordStride) { + for (int n = 0; n < texcoords.size(); n = n + 2) { + mesh.texCoords.push_back(glm::vec2(texcoords[n], texcoords[n + 1])); + } + } else { + if (meshAttributes.contains("TEXCOORD_0")) { + for (int i = 0; i < partVerticesCount; i++) { + mesh.texCoords.push_back(glm::vec2(0.0f, 0.0f)); + } + } } - for (int n = 0; n < colors.size(); n += colorStride) { - mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2])); + if (texcoords.size() == partVerticesCount * texCoord2Stride) { + for (int n = 0; n < texcoords2.size(); n = n + 2) { + mesh.texCoords1.push_back(glm::vec2(texcoords2[n], texcoords2[n + 1])); + } + } else { + if (meshAttributes.contains("TEXCOORD_1")) { + for (int i = 0; i < partVerticesCount; i++) { + mesh.texCoords1.push_back(glm::vec2(0.0f, 0.0f)); + } + } } - for (int n = 0; n < joints.size(); n += jointStride) { - clusterJoints.push_back(joints[n]); - if (jointStride > 1) { - clusterJoints.push_back(joints[n + 1]); - if (jointStride > 2) { - clusterJoints.push_back(joints[n + 2]); - if (jointStride > 3) { - clusterJoints.push_back(joints[n + 3]); + if (colors.size() == partVerticesCount * colorStride) { + for (int n = 0; n < colors.size(); n += colorStride) { + mesh.colors.push_back(glm::vec3(colors[n], colors[n + 1], colors[n + 2])); + } + } else { + if (meshAttributes.contains("COLOR_0")) { + for (int i = 0; i < partVerticesCount; i++) { + mesh.colors.push_back(glm::vec3(1.0f, 1.0f, 1.0f)); + } + } + } + + if (joints.size() == partVerticesCount * jointStride) { + for (int n = 0; n < joints.size(); n += jointStride) { + clusterJoints.push_back(joints[n]); + if (jointStride > 1) { + clusterJoints.push_back(joints[n + 1]); + if (jointStride > 2) { + clusterJoints.push_back(joints[n + 2]); + if (jointStride > 3) { + clusterJoints.push_back(joints[n + 3]); + } else { + clusterJoints.push_back(0); + } } else { clusterJoints.push_back(0); + clusterJoints.push_back(0); } } else { clusterJoints.push_back(0); clusterJoints.push_back(0); + clusterJoints.push_back(0); + } + } + } else { + if (meshAttributes.contains("JOINTS_0")) { + for (int i = 0; i < partVerticesCount; i++) { + for (int j = 0; j < 4; j++) { + clusterJoints.push_back(0); + } } - } else { - clusterJoints.push_back(0); - clusterJoints.push_back(0); - clusterJoints.push_back(0); } } - for (int n = 0; n < weights.size(); n += weightStride) { - clusterWeights.push_back(weights[n]); - if (weightStride > 1) { - clusterWeights.push_back(weights[n + 1]); - if (weightStride > 2) { - clusterWeights.push_back(weights[n + 2]); - if (weightStride > 3) { - clusterWeights.push_back(weights[n + 3]); + if (weights.size() == partVerticesCount * weightStride) { + for (int n = 0; n < weights.size(); n += weightStride) { + clusterWeights.push_back(weights[n]); + if (weightStride > 1) { + clusterWeights.push_back(weights[n + 1]); + if (weightStride > 2) { + clusterWeights.push_back(weights[n + 2]); + if (weightStride > 3) { + clusterWeights.push_back(weights[n + 3]); + } else { + clusterWeights.push_back(0.0f); + } } else { - clusterWeights.push_back(0); + clusterWeights.push_back(0.0f); + clusterWeights.push_back(0.0f); } } else { - clusterWeights.push_back(0); - clusterWeights.push_back(0); + clusterWeights.push_back(0.0f); + clusterWeights.push_back(0.0f); + clusterWeights.push_back(0.0f); + } + } + } else { + if (meshAttributes.contains("WEIGHTS_0")) { + for (int i = 0; i < partVerticesCount; i++) { + clusterWeights.push_back(1.0f); + for (int j = 1; j < 4; j++) { + clusterWeights.push_back(0.0f); + } } - } else { - clusterWeights.push_back(0); - clusterWeights.push_back(0); - clusterWeights.push_back(0); } } From 9aadea81b3419dc6590ab8ad74e6f6ac39364e06 Mon Sep 17 00:00:00 2001 From: Saracen <SaracenOne@gmail.com> Date: Mon, 13 May 2019 19:13:24 +0100 Subject: [PATCH 10/10] Fix to use correct texcoord2 array. --- libraries/fbx/src/GLTFSerializer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index b06b8f1822..7650cf04f6 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -1349,7 +1349,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } } - if (texcoords.size() == partVerticesCount * texCoord2Stride) { + if (texcoords2.size() == partVerticesCount * texCoord2Stride) { for (int n = 0; n < texcoords2.size(); n = n + 2) { mesh.texCoords1.push_back(glm::vec2(texcoords2[n], texcoords2[n + 1])); }