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)
pull/2818/head
RichardTea 2019-12-09 10:42:50 +00:00
parent 463573c771
commit 193b02cdac
3 changed files with 27 additions and 16 deletions

View File

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

View File

@ -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 (const aiNode *join_node : join) {
for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) { 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);

View File

@ -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.