Browse Source

Odd negative scale: OptimizeGraph

OptimizeGraph postprocessing now reverses face order when
node scale is mirroring.
Fixes flip to backfacing in models that mirrored some nodes.

(Odd count of negative scale components, negative determinant)
RichardTea 5 years ago
parent
commit
193b02cdac

+ 3 - 2
code/PostProcessing/ConvertToLHProcess.h

@@ -137,8 +137,9 @@ public:
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     void Execute( aiScene* pScene);
     void Execute( aiScene* pScene);
 
 
-protected:
-    void ProcessMesh( aiMesh* pMesh);
+public:
+    /** Some other types of post-processing require winding order flips */
+    static void ProcessMesh( aiMesh* pMesh);
 };
 };
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------

+ 21 - 11
code/PostProcessing/OptimizeGraph.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "OptimizeGraph.h"
 #include "OptimizeGraph.h"
 #include "ProcessHelper.h"
 #include "ProcessHelper.h"
+#include "ConvertToLHProcess.h"
 #include <assimp/Exceptional.h>
 #include <assimp/Exceptional.h>
 #include <assimp/SceneCombiner.h>
 #include <assimp/SceneCombiner.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -135,7 +136,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &n
 		nodes.push_back(nd);
 		nodes.push_back(nd);
 
 
 		// Now check for possible optimizations in our list of child nodes. join as many as possible
 		// Now check for possible optimizations in our list of child nodes. join as many as possible
-		aiNode *join_master = NULL;
+		aiNode *join_master = nullptr;
 		aiMatrix4x4 inv;
 		aiMatrix4x4 inv;
 
 
 		const LockedSetType::const_iterator end = locked.end();
 		const LockedSetType::const_iterator end = locked.end();
@@ -172,7 +173,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &n
 			join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i", count_merged++);
 			join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i", count_merged++);
 
 
 			unsigned int out_meshes = 0;
 			unsigned int out_meshes = 0;
-			for (std::list<aiNode *>::iterator it = join.begin(); it != join.end(); ++it) {
+			for (std::list<aiNode *>::const_iterator it = join.cbegin(); it != join.cend(); ++it) {
 				out_meshes += (*it)->mNumMeshes;
 				out_meshes += (*it)->mNumMeshes;
 			}
 			}
 
 
@@ -183,17 +184,26 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &n
 					*tmp++ = join_master->mMeshes[n];
 					*tmp++ = join_master->mMeshes[n];
 				}
 				}
 
 
-				for (std::list<aiNode *>::iterator it = join.begin(); it != join.end(); ++it) {
-					for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) {
+				for (const aiNode *join_node : join) {
+					for (unsigned int n = 0; n < join_node->mNumMeshes; ++n) {
 
 
-						*tmp = (*it)->mMeshes[n];
+						*tmp = join_node->mMeshes[n];
 						aiMesh *mesh = mScene->mMeshes[*tmp++];
 						aiMesh *mesh = mScene->mMeshes[*tmp++];
 
 
+						// Assume the transformation is affine
 						// manually move the mesh into the right coordinate system
 						// manually move the mesh into the right coordinate system
-						const aiMatrix3x3 IT = aiMatrix3x3((*it)->mTransformation).Inverse().Transpose();
+
+						// Check for odd negative scale (mirror)
+						if (join_node->mTransformation.Determinant() < 0) {
+							// Reverse the mesh face winding order
+                            FlipWindingOrderProcess::ProcessMesh(mesh);
+						}
+
+                        // Update positions, normals and tangents
+						const aiMatrix3x3 IT = aiMatrix3x3(join_node->mTransformation).Inverse().Transpose();
 						for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
 						for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
 
 
-							mesh->mVertices[a] *= (*it)->mTransformation;
+							mesh->mVertices[a] *= join_node->mTransformation;
 
 
 							if (mesh->HasNormals())
 							if (mesh->HasNormals())
 								mesh->mNormals[a] *= IT;
 								mesh->mNormals[a] *= IT;
@@ -204,7 +214,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &n
 							}
 							}
 						}
 						}
 					}
 					}
-					delete *it; // bye, node
+					delete join_node; // bye, node
 				}
 				}
 				delete[] join_master->mMeshes;
 				delete[] join_master->mMeshes;
 				join_master->mMeshes = meshes;
 				join_master->mMeshes = meshes;
@@ -304,7 +314,7 @@ void OptimizeGraphProcess::Execute(aiScene *pScene) {
 	ai_assert(nodes.size() == 1);
 	ai_assert(nodes.size() == 1);
 
 
 	if (dummy_root->mNumChildren == 0) {
 	if (dummy_root->mNumChildren == 0) {
-		pScene->mRootNode = NULL;
+		pScene->mRootNode = nullptr;
 		throw DeadlyImportError("After optimizing the scene graph, no data remains");
 		throw DeadlyImportError("After optimizing the scene graph, no data remains");
 	}
 	}
 
 
@@ -318,11 +328,11 @@ void OptimizeGraphProcess::Execute(aiScene *pScene) {
 		// Remove the dummy root node again.
 		// Remove the dummy root node again.
 		pScene->mRootNode = dummy_root->mChildren[0];
 		pScene->mRootNode = dummy_root->mChildren[0];
 
 
-		dummy_root->mChildren[0] = NULL;
+		dummy_root->mChildren[0] = nullptr;
 		delete dummy_root;
 		delete dummy_root;
 	}
 	}
 
 
-	pScene->mRootNode->mParent = NULL;
+	pScene->mRootNode->mParent = nullptr;
 	if (!DefaultLogger::isNullLogger()) {
 	if (!DefaultLogger::isNullLogger()) {
 		if (nodes_in != nodes_out) {
 		if (nodes_in != nodes_out) {
 			ASSIMP_LOG_INFO_F("OptimizeGraphProcess finished; Input nodes: ", nodes_in, ", Output nodes: ", nodes_out);
 			ASSIMP_LOG_INFO_F("OptimizeGraphProcess finished; Input nodes: ", nodes_in, ", Output nodes: ", nodes_out);

+ 3 - 3
code/PostProcessing/OptimizeGraph.h

@@ -75,13 +75,13 @@ public:
     ~OptimizeGraphProcess();
     ~OptimizeGraphProcess();
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
-    bool IsActive( unsigned int pFlags) const;
+    bool IsActive( unsigned int pFlags) const override;
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
-    void Execute( aiScene* pScene);
+    void Execute( aiScene* pScene) override;
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer* pImp) override;
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** @brief Add a list of node names to be locked and not modified.
     /** @brief Add a list of node names to be locked and not modified.