| /* |
| --------------------------------------------------------------------------- |
| Open Asset Import Library (assimp) |
| --------------------------------------------------------------------------- |
| |
| Copyright (c) 2006-2017, assimp team |
| |
| |
| All rights reserved. |
| |
| Redistribution and use of this software in source and binary forms, |
| with or without modification, are permitted provided that the following |
| conditions are met: |
| |
| * Redistributions of source code must retain the above |
| copyright notice, this list of conditions and the |
| following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the |
| following disclaimer in the documentation and/or other |
| materials provided with the distribution. |
| |
| * Neither the name of the assimp team, nor the names of its |
| contributors may be used to endorse or promote products |
| derived from this software without specific prior |
| written permission of the assimp team. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| --------------------------------------------------------------------------- |
| */ |
| |
| /** @file Implementation of the post processing step to invert |
| * all normals in meshes with infacing normals. |
| */ |
| |
| // internal headers |
| #include "FixNormalsStep.h" |
| #include "StringUtils.h" |
| #include <assimp/DefaultLogger.hpp> |
| #include <assimp/postprocess.h> |
| #include <assimp/scene.h> |
| #include <stdio.h> |
| |
| |
| using namespace Assimp; |
| |
| |
| // ------------------------------------------------------------------------------------------------ |
| // Constructor to be privately used by Importer |
| FixInfacingNormalsProcess::FixInfacingNormalsProcess() |
| { |
| // nothing to do here |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| // Destructor, private as well |
| FixInfacingNormalsProcess::~FixInfacingNormalsProcess() |
| { |
| // nothing to do here |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| // Returns whether the processing step is present in the given flag field. |
| bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const |
| { |
| return (pFlags & aiProcess_FixInfacingNormals) != 0; |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| // Executes the post processing step on the given imported data. |
| void FixInfacingNormalsProcess::Execute( aiScene* pScene) |
| { |
| DefaultLogger::get()->debug("FixInfacingNormalsProcess begin"); |
| |
| bool bHas = false; |
| for( unsigned int a = 0; a < pScene->mNumMeshes; a++) |
| if(ProcessMesh( pScene->mMeshes[a],a))bHas = true; |
| |
| if (bHas) |
| DefaultLogger::get()->debug("FixInfacingNormalsProcess finished. Found issues."); |
| else DefaultLogger::get()->debug("FixInfacingNormalsProcess finished. No changes to the scene."); |
| } |
| |
| // ------------------------------------------------------------------------------------------------ |
| // Apply the step to the mesh |
| bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index) |
| { |
| ai_assert(NULL != pcMesh); |
| |
| // Nothing to do if there are no model normals |
| if (!pcMesh->HasNormals())return false; |
| |
| // Compute the bounding box of both the model vertices + normals and |
| // the umodified model vertices. Then check whether the first BB |
| // is smaller than the second. In this case we can assume that the |
| // normals need to be flipped, although there are a few special cases .. |
| // convex, concave, planar models ... |
| |
| aiVector3D vMin0 (1e10f,1e10f,1e10f); |
| aiVector3D vMin1 (1e10f,1e10f,1e10f); |
| aiVector3D vMax0 (-1e10f,-1e10f,-1e10f); |
| aiVector3D vMax1 (-1e10f,-1e10f,-1e10f); |
| |
| for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) |
| { |
| vMin1.x = std::min(vMin1.x,pcMesh->mVertices[i].x); |
| vMin1.y = std::min(vMin1.y,pcMesh->mVertices[i].y); |
| vMin1.z = std::min(vMin1.z,pcMesh->mVertices[i].z); |
| |
| vMax1.x = std::max(vMax1.x,pcMesh->mVertices[i].x); |
| vMax1.y = std::max(vMax1.y,pcMesh->mVertices[i].y); |
| vMax1.z = std::max(vMax1.z,pcMesh->mVertices[i].z); |
| |
| const aiVector3D vWithNormal = pcMesh->mVertices[i] + pcMesh->mNormals[i]; |
| |
| vMin0.x = std::min(vMin0.x,vWithNormal.x); |
| vMin0.y = std::min(vMin0.y,vWithNormal.y); |
| vMin0.z = std::min(vMin0.z,vWithNormal.z); |
| |
| vMax0.x = std::max(vMax0.x,vWithNormal.x); |
| vMax0.y = std::max(vMax0.y,vWithNormal.y); |
| vMax0.z = std::max(vMax0.z,vWithNormal.z); |
| } |
| |
| const float fDelta0_x = (vMax0.x - vMin0.x); |
| const float fDelta0_y = (vMax0.y - vMin0.y); |
| const float fDelta0_z = (vMax0.z - vMin0.z); |
| |
| const float fDelta1_x = (vMax1.x - vMin1.x); |
| const float fDelta1_y = (vMax1.y - vMin1.y); |
| const float fDelta1_z = (vMax1.z - vMin1.z); |
| |
| // Check whether the boxes are overlapping |
| if ((fDelta0_x > 0.0f) != (fDelta1_x > 0.0f))return false; |
| if ((fDelta0_y > 0.0f) != (fDelta1_y > 0.0f))return false; |
| if ((fDelta0_z > 0.0f) != (fDelta1_z > 0.0f))return false; |
| |
| // Check whether this is a planar surface |
| const float fDelta1_yz = fDelta1_y * fDelta1_z; |
| |
| if (fDelta1_x < 0.05f * std::sqrt( fDelta1_yz ))return false; |
| if (fDelta1_y < 0.05f * std::sqrt( fDelta1_z * fDelta1_x ))return false; |
| if (fDelta1_z < 0.05f * std::sqrt( fDelta1_y * fDelta1_x ))return false; |
| |
| // now compare the volumes of the bounding boxes |
| if (std::fabs(fDelta0_x * fDelta0_y * fDelta0_z) < |
| std::fabs(fDelta1_x * fDelta1_yz)) |
| { |
| if (!DefaultLogger::isNullLogger()) |
| { |
| char buffer[128]; // should be sufficiently large |
| ai_snprintf(buffer,128,"Mesh %u: Normals are facing inwards (or the mesh is planar)",index); |
| DefaultLogger::get()->info(buffer); |
| } |
| |
| // Invert normals |
| for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) |
| pcMesh->mNormals[i] *= -1.0f; |
| |
| // ... and flip faces |
| for (unsigned int i = 0; i < pcMesh->mNumFaces;++i) |
| { |
| aiFace& face = pcMesh->mFaces[i]; |
| for( unsigned int b = 0; b < face.mNumIndices / 2; b++) |
| std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]); |
| } |
| return true; |
| } |
| return false; |
| } |