From 7987ed14b09bf219f692e4677ccd2208c58ec26d Mon Sep 17 00:00:00 2001 From: Saracen Date: Sat, 11 May 2019 04:30:14 +0100 Subject: [PATCH] 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 meshAttributes; + foreach(auto &primitive, _file.meshes[node.mesh].primitives) { + QList 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 indices; QVector vertices; + int verticesStride = 3; QVector normals; + int normalStride = 3; QVector tangents; - int tangentStride = 0; + int tangentStride = 4; QVector texcoords; + int texCoordStride = 2; QVector texcoords2; + int texCoord2Stride = 2; QVector colors; - int colorStride = 0; + int colorStride = 3; QVector joints; - int jointStride = 0; + int jointStride = 4; QVector 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 newIndices; + QVector newVertices; + QVector newNormals; + QVector newTexcoords; + QVector newTexcoords2; + QVector newColors; + QVector newJoints; + QVector 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(); + texcoords = newTexcoords; + texcoords2 = newTexcoords2; + colors = newColors; + joints = newJoints; + weights = newWeights; + indices = newIndices; + + partVerticesCount = vertices.size() / 3; + } + + QVector validatedIndices; + for (int n = 0; n < indices.count(); n++) { + if (indices[n] < partVerticesCount) { + validatedIndices.push_back(indices[n] + prevMeshVerticesCount); + } else { + validatedIndices = QVector(); + 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); } }