From 2d0fac794e739150d91edd30d7428d15f8ea80fc Mon Sep 17 00:00:00 2001 From: trent Date: Tue, 28 Mar 2017 18:41:38 -0400 Subject: [PATCH 1/9] Committing this work-in-progress loader as an example of how not to do this. --- libraries/fbx/src/OBJReader.cpp | 198 +++++++++++++++++--------------- libraries/fbx/src/OBJReader.h | 2 +- 2 files changed, 104 insertions(+), 96 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c1bb72dff8..6d23be0a9f 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -302,9 +302,10 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) { } -bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess) { +bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess, int index) { FaceGroup faces; - FBXMesh& mesh = geometry.meshes[0]; + geometry.meshes.append(FBXMesh()); + FBXMesh& mesh = geometry.meshes.last(); mesh.parts.append(FBXMeshPart()); FBXMeshPart& meshPart = mesh.parts.last(); bool sawG = false; @@ -433,111 +434,118 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, _url = url; geometry.meshExtents.reset(); - geometry.meshes.append(FBXMesh()); +// geometry.meshes.append(FBXMesh()); try { // call parseOBJGroup as long as it's returning true. Each successful call will // add a new meshPart to the geometry's single mesh. - while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess)) {} + int i = 0; + while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess, i)) { + ++i; + } - FBXMesh& mesh = geometry.meshes[0]; - mesh.meshIndex = 0; + geometry.joints.resize(1); + geometry.joints[0].isFree = false; + geometry.joints[0].parentIndex = -1; + geometry.joints[0].distanceToParent = 0; + geometry.joints[0].translation = glm::vec3(0, 0, 0); + geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[0].name = "OBJ"; + geometry.joints[0].isSkeletonJoint = true; - geometry.joints.resize(1); - geometry.joints[0].isFree = false; - geometry.joints[0].parentIndex = -1; - geometry.joints[0].distanceToParent = 0; - geometry.joints[0].translation = glm::vec3(0, 0, 0); - geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); - geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[0].name = "OBJ"; - geometry.joints[0].isSkeletonJoint = true; + geometry.jointIndices["x"] = 1; - geometry.jointIndices["x"] = 1; + for (int i = 0; i < geometry.meshes.count(); i++) { + FBXMesh& mesh = geometry.meshes[i]; + mesh.meshIndex = i; - FBXCluster cluster; - cluster.jointIndex = 0; - cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - mesh.clusters.append(cluster); + FBXCluster cluster; + cluster.jointIndex = 0; + cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + mesh.clusters.append(cluster); - for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) { - FBXMeshPart& meshPart = mesh.parts[i]; - FaceGroup faceGroup = faceGroups[meshPartCount]; - bool specifiesUV = false; - foreach(OBJFace face, faceGroup) { - glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]); - glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]); - glm::vec3 v2 = checked_at(vertices, face.vertexIndices[2]); - meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices - mesh.vertices << v0; - meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices << v1; - meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices << v2; + for (int meshPartCount = 0; meshPartCount < mesh.parts.count( ); ++meshPartCount) { + FBXMeshPart& meshPart = mesh.parts[meshPartCount]; + FaceGroup faceGroup = faceGroups[meshPartCount]; + bool specifiesUV = false; - glm::vec3 n0, n1, n2; - if (face.normalIndices.count()) { - n0 = checked_at(normals, face.normalIndices[0]); - n1 = checked_at(normals, face.normalIndices[1]); - n2 = checked_at(normals, face.normalIndices[2]); - } else { // generate normals from triangle plane if not provided - n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); - } - mesh.normals << n0 << n1 << n2; - if (face.textureUVIndices.count()) { - specifiesUV = true; - mesh.texCoords << - checked_at(textureUVs, face.textureUVIndices[0]) << - checked_at(textureUVs, face.textureUVIndices[1]) << - checked_at(textureUVs, face.textureUVIndices[2]); - } else { - glm::vec2 corner(0.0f, 1.0f); - mesh.texCoords << corner << corner << corner; - } - } - // All the faces in the same group will have the same name and material. - OBJFace leadFace = faceGroup[0]; - QString groupMaterialName = leadFace.materialName; - if (groupMaterialName.isEmpty() && specifiesUV) { - #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader WARNING: " << url - << " needs a texture that isn't specified. Using default mechanism."; - #endif - groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; - } - if (!groupMaterialName.isEmpty()) { - OBJMaterial& material = materials[groupMaterialName]; - if (specifiesUV) { - material.userSpecifiesUV = true; // Note might not be true in a later usage. - } - if (specifiesUV || (0 != groupMaterialName.compare("none", Qt::CaseInsensitive))) { - // Blender has a convention that a material named "None" isn't really used (or defined). - material.used = true; - needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; - } - materials[groupMaterialName] = material; - meshPart.materialID = groupMaterialName; - } + foreach(OBJFace face, faceGroup) { + glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]); + glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]); + glm::vec3 v2 = checked_at(vertices, face.vertexIndices[2]); + meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices + mesh.vertices << v0; + meshPart.triangleIndices.append(mesh.vertices.count()); + mesh.vertices << v1; + meshPart.triangleIndices.append(mesh.vertices.count()); + mesh.vertices << v2; + glm::vec3 n0, n1, n2; + if (face.normalIndices.count()) { + n0 = checked_at(normals, face.normalIndices[0]); + n1 = checked_at(normals, face.normalIndices[1]); + n2 = checked_at(normals, face.normalIndices[2]); + } + else { // generate normals from triangle plane if not provided + n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); + } + mesh.normals << n0 << n1 << n2; + if (face.textureUVIndices.count()) { + specifiesUV = true; + mesh.texCoords << + checked_at(textureUVs, face.textureUVIndices[0]) << + checked_at(textureUVs, face.textureUVIndices[1]) << + checked_at(textureUVs, face.textureUVIndices[2]); + } + else { + glm::vec2 corner(0.0f, 1.0f); + mesh.texCoords << corner << corner << corner; + } + } + // All the faces in the same group will have the same name and material. + OBJFace leadFace = faceGroup[0]; + QString groupMaterialName = leadFace.materialName; + if (groupMaterialName.isEmpty() && specifiesUV) { +#ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: " << url + << " needs a texture that isn't specified. Using default mechanism."; +#endif + groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; + } + if (!groupMaterialName.isEmpty()) { + OBJMaterial& material = materials[groupMaterialName]; + if (specifiesUV) { + material.userSpecifiesUV = true; // Note might not be true in a later usage. + } + if (specifiesUV || (0 != groupMaterialName.compare("none", Qt::CaseInsensitive))) { + // Blender has a convention that a material named "None" isn't really used (or defined). + material.used = true; + needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; + } + materials[groupMaterialName] = material; + meshPart.materialID = groupMaterialName; + } + } + + // if we got a hint about units, scale all the points + if (scaleGuess != 1.0f) { + for (int i = 0; i < mesh.vertices.size(); i++) { + mesh.vertices[i] *= scaleGuess; + } + } + + mesh.meshExtents.reset(); + foreach(const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + geometry.meshExtents.addPoint(vertex); + } + + FBXReader::buildModelMesh(mesh, url.toString()); } - - // if we got a hint about units, scale all the points - if (scaleGuess != 1.0f) { - for (int i = 0; i < mesh.vertices.size(); i++) { - mesh.vertices[i] *= scaleGuess; - } - } - - mesh.meshExtents.reset(); - foreach (const glm::vec3& vertex, mesh.vertices) { - mesh.meshExtents.addPoint(vertex); - geometry.meshExtents.addPoint(vertex); - } - - FBXReader::buildModelMesh(mesh, url.toString()); // fbxDebugDump(geometry); } catch(const std::exception& e) { qCDebug(modelformat) << "OBJ reader fail: " << e.what(); diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index b4a48c570e..e75b1900e9 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -79,7 +79,7 @@ private: QUrl _url; QHash librariesSeen; - bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess); + bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess, int index); void parseMaterialLibrary(QIODevice* device); bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format. }; From 5bf3da9a7f438b74c2acaf6b65acd41cb39e12f6 Mon Sep 17 00:00:00 2001 From: trent Date: Thu, 30 Mar 2017 16:14:42 -0400 Subject: [PATCH 2/9] Restoring hifi version of the OBJ files to get rid of my debug nonsense. --- libraries/fbx/src/OBJReader.cpp | 198 +++++++++++++++----------------- libraries/fbx/src/OBJReader.h | 2 +- 2 files changed, 96 insertions(+), 104 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 6d23be0a9f..c1bb72dff8 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -302,10 +302,9 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) { } -bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess, int index) { +bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess) { FaceGroup faces; - geometry.meshes.append(FBXMesh()); - FBXMesh& mesh = geometry.meshes.last(); + FBXMesh& mesh = geometry.meshes[0]; mesh.parts.append(FBXMeshPart()); FBXMeshPart& meshPart = mesh.parts.last(); bool sawG = false; @@ -434,118 +433,111 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, _url = url; geometry.meshExtents.reset(); -// geometry.meshes.append(FBXMesh()); + geometry.meshes.append(FBXMesh()); try { // call parseOBJGroup as long as it's returning true. Each successful call will // add a new meshPart to the geometry's single mesh. - int i = 0; - while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess, i)) { - ++i; - } + while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess)) {} - geometry.joints.resize(1); - geometry.joints[0].isFree = false; - geometry.joints[0].parentIndex = -1; - geometry.joints[0].distanceToParent = 0; - geometry.joints[0].translation = glm::vec3(0, 0, 0); - geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); - geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[0].name = "OBJ"; - geometry.joints[0].isSkeletonJoint = true; + FBXMesh& mesh = geometry.meshes[0]; + mesh.meshIndex = 0; - geometry.jointIndices["x"] = 1; + geometry.joints.resize(1); + geometry.joints[0].isFree = false; + geometry.joints[0].parentIndex = -1; + geometry.joints[0].distanceToParent = 0; + geometry.joints[0].translation = glm::vec3(0, 0, 0); + geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[0].name = "OBJ"; + geometry.joints[0].isSkeletonJoint = true; - for (int i = 0; i < geometry.meshes.count(); i++) { - FBXMesh& mesh = geometry.meshes[i]; - mesh.meshIndex = i; + geometry.jointIndices["x"] = 1; - FBXCluster cluster; - cluster.jointIndex = 0; - cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - mesh.clusters.append(cluster); + FBXCluster cluster; + cluster.jointIndex = 0; + cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + mesh.clusters.append(cluster); - for (int meshPartCount = 0; meshPartCount < mesh.parts.count( ); ++meshPartCount) { - FBXMeshPart& meshPart = mesh.parts[meshPartCount]; - FaceGroup faceGroup = faceGroups[meshPartCount]; - bool specifiesUV = false; + for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) { + FBXMeshPart& meshPart = mesh.parts[i]; + FaceGroup faceGroup = faceGroups[meshPartCount]; + bool specifiesUV = false; + foreach(OBJFace face, faceGroup) { + glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]); + glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]); + glm::vec3 v2 = checked_at(vertices, face.vertexIndices[2]); + meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices + mesh.vertices << v0; + meshPart.triangleIndices.append(mesh.vertices.count()); + mesh.vertices << v1; + meshPart.triangleIndices.append(mesh.vertices.count()); + mesh.vertices << v2; - foreach(OBJFace face, faceGroup) { - glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]); - glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]); - glm::vec3 v2 = checked_at(vertices, face.vertexIndices[2]); - meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices - mesh.vertices << v0; - meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices << v1; - meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices << v2; + glm::vec3 n0, n1, n2; + if (face.normalIndices.count()) { + n0 = checked_at(normals, face.normalIndices[0]); + n1 = checked_at(normals, face.normalIndices[1]); + n2 = checked_at(normals, face.normalIndices[2]); + } else { // generate normals from triangle plane if not provided + n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); + } + mesh.normals << n0 << n1 << n2; + if (face.textureUVIndices.count()) { + specifiesUV = true; + mesh.texCoords << + checked_at(textureUVs, face.textureUVIndices[0]) << + checked_at(textureUVs, face.textureUVIndices[1]) << + checked_at(textureUVs, face.textureUVIndices[2]); + } else { + glm::vec2 corner(0.0f, 1.0f); + mesh.texCoords << corner << corner << corner; + } + } + // All the faces in the same group will have the same name and material. + OBJFace leadFace = faceGroup[0]; + QString groupMaterialName = leadFace.materialName; + if (groupMaterialName.isEmpty() && specifiesUV) { + #ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: " << url + << " needs a texture that isn't specified. Using default mechanism."; + #endif + groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; + } + if (!groupMaterialName.isEmpty()) { + OBJMaterial& material = materials[groupMaterialName]; + if (specifiesUV) { + material.userSpecifiesUV = true; // Note might not be true in a later usage. + } + if (specifiesUV || (0 != groupMaterialName.compare("none", Qt::CaseInsensitive))) { + // Blender has a convention that a material named "None" isn't really used (or defined). + material.used = true; + needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; + } + materials[groupMaterialName] = material; + meshPart.materialID = groupMaterialName; + } - glm::vec3 n0, n1, n2; - if (face.normalIndices.count()) { - n0 = checked_at(normals, face.normalIndices[0]); - n1 = checked_at(normals, face.normalIndices[1]); - n2 = checked_at(normals, face.normalIndices[2]); - } - else { // generate normals from triangle plane if not provided - n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); - } - mesh.normals << n0 << n1 << n2; - if (face.textureUVIndices.count()) { - specifiesUV = true; - mesh.texCoords << - checked_at(textureUVs, face.textureUVIndices[0]) << - checked_at(textureUVs, face.textureUVIndices[1]) << - checked_at(textureUVs, face.textureUVIndices[2]); - } - else { - glm::vec2 corner(0.0f, 1.0f); - mesh.texCoords << corner << corner << corner; - } - } - // All the faces in the same group will have the same name and material. - OBJFace leadFace = faceGroup[0]; - QString groupMaterialName = leadFace.materialName; - if (groupMaterialName.isEmpty() && specifiesUV) { -#ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader WARNING: " << url - << " needs a texture that isn't specified. Using default mechanism."; -#endif - groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; - } - if (!groupMaterialName.isEmpty()) { - OBJMaterial& material = materials[groupMaterialName]; - if (specifiesUV) { - material.userSpecifiesUV = true; // Note might not be true in a later usage. - } - if (specifiesUV || (0 != groupMaterialName.compare("none", Qt::CaseInsensitive))) { - // Blender has a convention that a material named "None" isn't really used (or defined). - material.used = true; - needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; - } - materials[groupMaterialName] = material; - meshPart.materialID = groupMaterialName; - } - } - - // if we got a hint about units, scale all the points - if (scaleGuess != 1.0f) { - for (int i = 0; i < mesh.vertices.size(); i++) { - mesh.vertices[i] *= scaleGuess; - } - } - - mesh.meshExtents.reset(); - foreach(const glm::vec3& vertex, mesh.vertices) { - mesh.meshExtents.addPoint(vertex); - geometry.meshExtents.addPoint(vertex); - } - - FBXReader::buildModelMesh(mesh, url.toString()); } + + // if we got a hint about units, scale all the points + if (scaleGuess != 1.0f) { + for (int i = 0; i < mesh.vertices.size(); i++) { + mesh.vertices[i] *= scaleGuess; + } + } + + mesh.meshExtents.reset(); + foreach (const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + geometry.meshExtents.addPoint(vertex); + } + + FBXReader::buildModelMesh(mesh, url.toString()); // fbxDebugDump(geometry); } catch(const std::exception& e) { qCDebug(modelformat) << "OBJ reader fail: " << e.what(); diff --git a/libraries/fbx/src/OBJReader.h b/libraries/fbx/src/OBJReader.h index e75b1900e9..b4a48c570e 100644 --- a/libraries/fbx/src/OBJReader.h +++ b/libraries/fbx/src/OBJReader.h @@ -79,7 +79,7 @@ private: QUrl _url; QHash librariesSeen; - bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess, int index); + bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess); void parseMaterialLibrary(QIODevice* device); bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format. }; From 864184a107c8b063e1d13fb8a6bc520a4ffaea98 Mon Sep 17 00:00:00 2001 From: trent Date: Thu, 30 Mar 2017 17:11:40 -0400 Subject: [PATCH 3/9] wip OBJ loader rewrite; wip because it crashes. --- libraries/fbx/src/OBJReader.cpp | 209 ++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 88 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c1bb72dff8..16562c4fdb 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -440,105 +440,138 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // add a new meshPart to the geometry's single mesh. while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess)) {} - FBXMesh& mesh = geometry.meshes[0]; - mesh.meshIndex = 0; +// FBXMesh& mesh = geometry.meshes[0]; + geometry.joints.resize(1); + geometry.joints[0].isFree = false; + geometry.joints[0].parentIndex = -1; + geometry.joints[0].distanceToParent = 0; + geometry.joints[0].translation = glm::vec3(0, 0, 0); + geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); + geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); + geometry.joints[0].name = "OBJ"; + geometry.joints[0].isSkeletonJoint = true; - geometry.joints.resize(1); - geometry.joints[0].isFree = false; - geometry.joints[0].parentIndex = -1; - geometry.joints[0].distanceToParent = 0; - geometry.joints[0].translation = glm::vec3(0, 0, 0); - geometry.joints[0].rotationMin = glm::vec3(0, 0, 0); - geometry.joints[0].rotationMax = glm::vec3(0, 0, 0); - geometry.joints[0].name = "OBJ"; - geometry.joints[0].isSkeletonJoint = true; + geometry.jointIndices["x"] = 1; - geometry.jointIndices["x"] = 1; + FBXCluster cluster; + cluster.jointIndex = 0; + cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); - FBXCluster cluster; - cluster.jointIndex = 0; - cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - mesh.clusters.append(cluster); - - for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) { - FBXMeshPart& meshPart = mesh.parts[i]; + QMap materialMeshIdMap; + QVector fbxMeshes; + for (int i = 0, meshPartCount = 0; i < geometry.meshes[0].parts.count(); i++, meshPartCount++) { + FBXMeshPart& meshPart = geometry.meshes[0].parts[i]; FaceGroup faceGroup = faceGroups[meshPartCount]; bool specifiesUV = false; - foreach(OBJFace face, faceGroup) { - glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]); - glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]); - glm::vec3 v2 = checked_at(vertices, face.vertexIndices[2]); - meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices - mesh.vertices << v0; - meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices << v1; - meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices << v2; + foreach(OBJFace face, faceGroup) { + // Go through all of the OBJ faces and determine the number of different materials necessary (each different material will be a unique mesh). + // NOTE (trent/mittens 3/30/17): this seems hardcore wasteful and is slowed down a bit by iterating through the face group twice, but it's the best way I've thought of to hack multi-material support in an OBJ into this pipeline. + if (!materialMeshIdMap.contains(face.materialName)) { + // Create a new FBXMesh for this material mapping. + materialMeshIdMap.insert(face.materialName, materialMeshIdMap.count()); - glm::vec3 n0, n1, n2; - if (face.normalIndices.count()) { - n0 = checked_at(normals, face.normalIndices[0]); - n1 = checked_at(normals, face.normalIndices[1]); - n2 = checked_at(normals, face.normalIndices[2]); - } else { // generate normals from triangle plane if not provided - n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); - } - mesh.normals << n0 << n1 << n2; - if (face.textureUVIndices.count()) { - specifiesUV = true; - mesh.texCoords << - checked_at(textureUVs, face.textureUVIndices[0]) << - checked_at(textureUVs, face.textureUVIndices[1]) << - checked_at(textureUVs, face.textureUVIndices[2]); - } else { - glm::vec2 corner(0.0f, 1.0f); - mesh.texCoords << corner << corner << corner; - } - } - // All the faces in the same group will have the same name and material. - OBJFace leadFace = faceGroup[0]; - QString groupMaterialName = leadFace.materialName; - if (groupMaterialName.isEmpty() && specifiesUV) { - #ifdef WANT_DEBUG - qCDebug(modelformat) << "OBJ Reader WARNING: " << url - << " needs a texture that isn't specified. Using default mechanism."; - #endif - groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; - } - if (!groupMaterialName.isEmpty()) { - OBJMaterial& material = materials[groupMaterialName]; - if (specifiesUV) { - material.userSpecifiesUV = true; // Note might not be true in a later usage. - } - if (specifiesUV || (0 != groupMaterialName.compare("none", Qt::CaseInsensitive))) { - // Blender has a convention that a material named "None" isn't really used (or defined). - material.used = true; - needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; - } - materials[groupMaterialName] = material; - meshPart.materialID = groupMaterialName; - } + FBXMesh& meshNew = geometry.meshes[0]; + meshNew.meshIndex = 0; + meshNew.clusters.append(cluster); + // Add this mesh part to the mesh. + meshNew.parts.append(meshPart); + + // Add it to the mesh vector. + fbxMeshes.append(meshNew); + + // Do some of the material logic (which previously lived below) now. + // All the faces in the same group will have the same name and material. + OBJFace leadFace = faceGroup[0]; + QString groupMaterialName = leadFace.materialName; + if (groupMaterialName.isEmpty() && specifiesUV) { +#ifdef WANT_DEBUG + qCDebug(modelformat) << "OBJ Reader WARNING: " << url + << " needs a texture that isn't specified. Using default mechanism."; +#endif + groupMaterialName = SMART_DEFAULT_MATERIAL_NAME; + } + if (!groupMaterialName.isEmpty()) { + OBJMaterial& material = materials[groupMaterialName]; + if (specifiesUV) { + material.userSpecifiesUV = true; // Note might not be true in a later usage. + } + if (specifiesUV || (0 != groupMaterialName.compare("none", Qt::CaseInsensitive))) { + // Blender has a convention that a material named "None" isn't really used (or defined). + material.used = true; + needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; + } + materials[groupMaterialName] = material; + meshPart.materialID = groupMaterialName; + } + } + } + + // Now that each mesh has been created with its own unique material mappings, fill them with data (vertex data is duplicated, face data is not). + foreach(OBJFace face, faceGroup) { + FBXMesh& mesh = fbxMeshes[materialMeshIdMap[face.materialName]]; + + glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]); + glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]); + glm::vec3 v2 = checked_at(vertices, face.vertexIndices[2]); + + // Scale the vertices if the OBJ file scale is specified as non-one. + if (scaleGuess != 1.0f) { + v0 *= scaleGuess; + v1 *= scaleGuess; + v2 *= scaleGuess; + } + + // Add the vertices. + meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices + mesh.vertices << v0; + meshPart.triangleIndices.append(mesh.vertices.count()); + mesh.vertices << v1; + meshPart.triangleIndices.append(mesh.vertices.count()); + mesh.vertices << v2; + + glm::vec3 n0, n1, n2; + if (face.normalIndices.count()) { + n0 = checked_at(normals, face.normalIndices[0]); + n1 = checked_at(normals, face.normalIndices[1]); + n2 = checked_at(normals, face.normalIndices[2]); + } + else { + // generate normals from triangle plane if not provided + n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); + } + mesh.normals << n0 << n1 << n2; + if (face.textureUVIndices.count()) { + specifiesUV = true; + mesh.texCoords << + checked_at(textureUVs, face.textureUVIndices[0]) << + checked_at(textureUVs, face.textureUVIndices[1]) << + checked_at(textureUVs, face.textureUVIndices[2]); + } + else { + glm::vec2 corner(0.0f, 1.0f); + mesh.texCoords << corner << corner << corner; + } + } } - // if we got a hint about units, scale all the points - if (scaleGuess != 1.0f) { - for (int i = 0; i < mesh.vertices.size(); i++) { - mesh.vertices[i] *= scaleGuess; - } - } + geometry.meshes.clear(); + foreach(FBXMesh mesh, fbxMeshes) { + geometry.meshes.append(mesh); - mesh.meshExtents.reset(); - foreach (const glm::vec3& vertex, mesh.vertices) { - mesh.meshExtents.addPoint(vertex); - geometry.meshExtents.addPoint(vertex); - } + mesh.meshExtents.reset(); + foreach(const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + geometry.meshExtents.addPoint(vertex); + } + + FBXReader::buildModelMesh(mesh, url.toString()); + } - FBXReader::buildModelMesh(mesh, url.toString()); - // fbxDebugDump(geometry); + // fbxDebugDump(geometry); } catch(const std::exception& e) { qCDebug(modelformat) << "OBJ reader fail: " << e.what(); } From c5bb419bd1559164b4e477216b1c6c1b16310baf Mon Sep 17 00:00:00 2001 From: trent Date: Thu, 30 Mar 2017 18:16:55 -0400 Subject: [PATCH 4/9] Fixed OBJ reader crash, did not fix OBJ reader not working properly. --- libraries/fbx/src/OBJReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 16562c4fdb..18450403c1 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -473,8 +473,8 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // Create a new FBXMesh for this material mapping. materialMeshIdMap.insert(face.materialName, materialMeshIdMap.count()); - FBXMesh& meshNew = geometry.meshes[0]; - meshNew.meshIndex = 0; + FBXMesh meshNew = geometry.meshes[0]; + meshNew.meshIndex = fbxMeshes.count(); meshNew.clusters.append(cluster); // Add this mesh part to the mesh. From e9035a1efba097575c48afafd026a0eaf2b486d3 Mon Sep 17 00:00:00 2001 From: trent Date: Thu, 30 Mar 2017 19:10:15 -0400 Subject: [PATCH 5/9] More fixes for the OBJ reader. The data seems to be fine. The rendering seems not so fine. --- libraries/fbx/src/OBJReader.cpp | 46 ++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 18450403c1..7f6f6a210a 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -463,7 +463,6 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, QMap materialMeshIdMap; QVector fbxMeshes; for (int i = 0, meshPartCount = 0; i < geometry.meshes[0].parts.count(); i++, meshPartCount++) { - FBXMeshPart& meshPart = geometry.meshes[0].parts[i]; FaceGroup faceGroup = faceGroups[meshPartCount]; bool specifiesUV = false; foreach(OBJFace face, faceGroup) { @@ -473,20 +472,15 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // Create a new FBXMesh for this material mapping. materialMeshIdMap.insert(face.materialName, materialMeshIdMap.count()); - FBXMesh meshNew = geometry.meshes[0]; - meshNew.meshIndex = fbxMeshes.count(); + FBXMesh meshNew; + meshNew.modelTransform = geometry.meshes[0].modelTransform; + meshNew.meshExtents = geometry.meshes[0].meshExtents; + meshNew.meshIndex = 0;// fbxMeshes.count(); meshNew.clusters.append(cluster); - // Add this mesh part to the mesh. - meshNew.parts.append(meshPart); - - // Add it to the mesh vector. - fbxMeshes.append(meshNew); - // Do some of the material logic (which previously lived below) now. // All the faces in the same group will have the same name and material. - OBJFace leadFace = faceGroup[0]; - QString groupMaterialName = leadFace.materialName; + QString groupMaterialName = face.materialName; if (groupMaterialName.isEmpty() && specifiesUV) { #ifdef WANT_DEBUG qCDebug(modelformat) << "OBJ Reader WARNING: " << url @@ -505,14 +499,21 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; } materials[groupMaterialName] = material; - meshPart.materialID = groupMaterialName; + geometry.meshes[0].parts[i].materialID = groupMaterialName; } + + // Add this mesh part. + meshNew.parts.append(FBXMeshPart(geometry.meshes[0].parts[i])); + + // Add it to the mesh vector. + fbxMeshes.append(meshNew); } } // Now that each mesh has been created with its own unique material mappings, fill them with data (vertex data is duplicated, face data is not). foreach(OBJFace face, faceGroup) { FBXMesh& mesh = fbxMeshes[materialMeshIdMap[face.materialName]]; + FBXMeshPart& meshPart = mesh.parts.last(); glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]); glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]); @@ -527,11 +528,11 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // Add the vertices. meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices - mesh.vertices << v0; + mesh.vertices.append(v0); meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices << v1; + mesh.vertices.append(v1); meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices << v2; + mesh.vertices.append(v2); glm::vec3 n0, n1, n2; if (face.normalIndices.count()) { @@ -543,17 +544,20 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // generate normals from triangle plane if not provided n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); } - mesh.normals << n0 << n1 << n2; + mesh.normals.append(n0); + mesh.normals.append(n1); + mesh.normals.append(n2); if (face.textureUVIndices.count()) { specifiesUV = true; - mesh.texCoords << - checked_at(textureUVs, face.textureUVIndices[0]) << - checked_at(textureUVs, face.textureUVIndices[1]) << - checked_at(textureUVs, face.textureUVIndices[2]); + mesh.texCoords.append(checked_at(textureUVs, face.textureUVIndices[0])); + mesh.texCoords.append(checked_at(textureUVs, face.textureUVIndices[1])); + mesh.texCoords.append(checked_at(textureUVs, face.textureUVIndices[2])); } else { glm::vec2 corner(0.0f, 1.0f); - mesh.texCoords << corner << corner << corner; + mesh.texCoords.append(corner); + mesh.texCoords.append(corner); + mesh.texCoords.append(corner); } } } From 29913326523622fb7a39b5b8e64afa917641c331 Mon Sep 17 00:00:00 2001 From: trent Date: Mon, 3 Apr 2017 16:46:22 -0400 Subject: [PATCH 6/9] Rewrote the OBJ reader (again) to use FBXMeshPart instead of separate meshes. Works now! Multi-material support win. --- libraries/fbx/src/OBJReader.cpp | 81 +++++++++++++++++---------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 7f6f6a210a..af58cef6ad 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -440,7 +440,9 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // add a new meshPart to the geometry's single mesh. while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess)) {} -// FBXMesh& mesh = geometry.meshes[0]; + FBXMesh& mesh = geometry.meshes[0]; + mesh.meshIndex = 0; + geometry.joints.resize(1); geometry.joints[0].isFree = false; geometry.joints[0].parentIndex = -1; @@ -459,11 +461,14 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + mesh.clusters.append(cluster); QMap materialMeshIdMap; - QVector fbxMeshes; - for (int i = 0, meshPartCount = 0; i < geometry.meshes[0].parts.count(); i++, meshPartCount++) { - FaceGroup faceGroup = faceGroups[meshPartCount]; + QVector fbxMeshParts; + int meshPartCount = 0; + for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) { + FBXMeshPart& meshPart = mesh.parts[i]; + FaceGroup faceGroup = faceGroups[meshPartCount]; bool specifiesUV = false; foreach(OBJFace face, faceGroup) { // Go through all of the OBJ faces and determine the number of different materials necessary (each different material will be a unique mesh). @@ -472,11 +477,11 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // Create a new FBXMesh for this material mapping. materialMeshIdMap.insert(face.materialName, materialMeshIdMap.count()); - FBXMesh meshNew; - meshNew.modelTransform = geometry.meshes[0].modelTransform; - meshNew.meshExtents = geometry.meshes[0].meshExtents; - meshNew.meshIndex = 0;// fbxMeshes.count(); - meshNew.clusters.append(cluster); + fbxMeshParts.append(FBXMeshPart()); + FBXMeshPart& meshPartNew = fbxMeshParts.last(); + meshPartNew.quadIndices = QVector(meshPart.quadIndices); // Copy over quad indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway]. + meshPartNew.quadTrianglesIndices = QVector(meshPart.quadTrianglesIndices); // Copy over quad triangulated indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway]. + meshPartNew.triangleIndices = QVector(meshPart.triangleIndices); // Copy over triangle indices. // Do some of the material logic (which previously lived below) now. // All the faces in the same group will have the same name and material. @@ -499,21 +504,23 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; } materials[groupMaterialName] = material; - geometry.meshes[0].parts[i].materialID = groupMaterialName; + meshPartNew.materialID = groupMaterialName; } - - // Add this mesh part. - meshNew.parts.append(FBXMeshPart(geometry.meshes[0].parts[i])); - - // Add it to the mesh vector. - fbxMeshes.append(meshNew); } } + } + + // clean up old mesh parts. + int unmodifiedMeshPartCount = mesh.parts.count(); + mesh.parts.clear(); + mesh.parts = QVector(fbxMeshParts); + + for (int i = 0, meshPartCount = 0; i < unmodifiedMeshPartCount; i++, meshPartCount++) { + FaceGroup faceGroup = faceGroups[meshPartCount]; // Now that each mesh has been created with its own unique material mappings, fill them with data (vertex data is duplicated, face data is not). foreach(OBJFace face, faceGroup) { - FBXMesh& mesh = fbxMeshes[materialMeshIdMap[face.materialName]]; - FBXMeshPart& meshPart = mesh.parts.last(); + FBXMeshPart& meshPart = mesh.parts[materialMeshIdMap[face.materialName]]; glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]); glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]); @@ -528,11 +535,11 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, // Add the vertices. meshPart.triangleIndices.append(mesh.vertices.count()); // not face.vertexIndices into vertices - mesh.vertices.append(v0); + mesh.vertices << v0; meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices.append(v1); + mesh.vertices << v1; meshPart.triangleIndices.append(mesh.vertices.count()); - mesh.vertices.append(v2); + mesh.vertices << v2; glm::vec3 n0, n1, n2; if (face.normalIndices.count()) { @@ -548,39 +555,33 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, mesh.normals.append(n1); mesh.normals.append(n2); if (face.textureUVIndices.count()) { - specifiesUV = true; - mesh.texCoords.append(checked_at(textureUVs, face.textureUVIndices[0])); - mesh.texCoords.append(checked_at(textureUVs, face.textureUVIndices[1])); - mesh.texCoords.append(checked_at(textureUVs, face.textureUVIndices[2])); + mesh.texCoords << + checked_at(textureUVs, face.textureUVIndices[0]) << + checked_at(textureUVs, face.textureUVIndices[1]) << + checked_at(textureUVs, face.textureUVIndices[2]); } else { glm::vec2 corner(0.0f, 1.0f); - mesh.texCoords.append(corner); - mesh.texCoords.append(corner); - mesh.texCoords.append(corner); + mesh.texCoords << corner << corner << corner; } } } - geometry.meshes.clear(); - foreach(FBXMesh mesh, fbxMeshes) { - geometry.meshes.append(mesh); - - mesh.meshExtents.reset(); - foreach(const glm::vec3& vertex, mesh.vertices) { - mesh.meshExtents.addPoint(vertex); - geometry.meshExtents.addPoint(vertex); - } - - FBXReader::buildModelMesh(mesh, url.toString()); + mesh.meshExtents.reset(); + foreach(const glm::vec3& vertex, mesh.vertices) { + mesh.meshExtents.addPoint(vertex); + geometry.meshExtents.addPoint(vertex); } + // Build the single mesh. + FBXReader::buildModelMesh(mesh, url.toString()); + // fbxDebugDump(geometry); } catch(const std::exception& e) { qCDebug(modelformat) << "OBJ reader fail: " << e.what(); } - QString queryPart = _url.query(); + QString queryPart = _url.query(); bool suppressMaterialsHack = queryPart.contains("hifiusemat"); // If this appears in query string, don't fetch mtl even if used. OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME]; preDefinedMaterial.used = true; From 5cc87ccc4a3a42a9bc2bd9d16d07b07109c9d5db Mon Sep 17 00:00:00 2001 From: trent Date: Mon, 3 Apr 2017 19:38:34 -0400 Subject: [PATCH 7/9] Fixed warning for subtly-stupid unused variable. --- libraries/fbx/src/OBJReader.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 93b474db25..7ed1c9cc1d 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -465,7 +465,6 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, QMap materialMeshIdMap; QVector fbxMeshParts; - int meshPartCount = 0; for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) { FBXMeshPart& meshPart = mesh.parts[i]; FaceGroup faceGroup = faceGroups[meshPartCount]; From 362ffba11718cb94b212923e2588ca3c8bbd2a5b Mon Sep 17 00:00:00 2001 From: trent Date: Mon, 3 Apr 2017 21:54:19 -0400 Subject: [PATCH 8/9] Fixes to OBJReader.cpp style inconsistencies. --- libraries/fbx/src/OBJReader.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 7ed1c9cc1d..c99b847722 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -497,7 +497,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, if (specifiesUV) { material.userSpecifiesUV = true; // Note might not be true in a later usage. } - if (specifiesUV || (0 != groupMaterialName.compare("none", Qt::CaseInsensitive))) { + if (specifiesUV || (groupMaterialName.compare("none", Qt::CaseInsensitive) != 0)) { // Blender has a convention that a material named "None" isn't really used (or defined). material.used = true; needsMaterialLibrary = groupMaterialName != SMART_DEFAULT_MATERIAL_NAME; @@ -545,21 +545,21 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, n0 = checked_at(normals, face.normalIndices[0]); n1 = checked_at(normals, face.normalIndices[1]); n2 = checked_at(normals, face.normalIndices[2]); - } - else { + } else { // generate normals from triangle plane if not provided n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); } + mesh.normals.append(n0); mesh.normals.append(n1); mesh.normals.append(n2); + if (face.textureUVIndices.count()) { mesh.texCoords << checked_at(textureUVs, face.textureUVIndices[0]) << checked_at(textureUVs, face.textureUVIndices[1]) << checked_at(textureUVs, face.textureUVIndices[2]); - } - else { + } else { glm::vec2 corner(0.0f, 1.0f); mesh.texCoords << corner << corner << corner; } @@ -580,7 +580,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, qCDebug(modelformat) << "OBJ reader fail: " << e.what(); } - QString queryPart = _url.query(); + QString queryPart = _url.query(); bool suppressMaterialsHack = queryPart.contains("hifiusemat"); // If this appears in query string, don't fetch mtl even if used. OBJMaterial& preDefinedMaterial = materials[SMART_DEFAULT_MATERIAL_NAME]; preDefinedMaterial.used = true; From c58fdb590a170008847fe7ccef0ee436e97edeea Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 4 Apr 2017 11:00:34 -0700 Subject: [PATCH 9/9] Fix for sliding feet when leaning in HMD mode. --- libraries/animation/src/Rig.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 020ea1d657..fb0867e2de 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1204,7 +1204,7 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f } else { _animVars.unset("leftFootPosition"); _animVars.unset("leftFootRotation"); - _animVars.set("leftFootType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); + _animVars.set("leftFootType", (int)IKTarget::Type::RotationAndPosition); } if (params.isRightFootEnabled) { @@ -1214,7 +1214,7 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f } else { _animVars.unset("rightFootPosition"); _animVars.unset("rightFootRotation"); - _animVars.set("rightFootType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); + _animVars.set("rightFootType", (int)IKTarget::Type::RotationAndPosition); } }