vrshoot
diff libs/assimp/GenVertexNormalsProcess.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/GenVertexNormalsProcess.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,233 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file Implementation of the post processing step to generate face 1.46 +* normals for all imported faces. 1.47 +*/ 1.48 + 1.49 +#include "AssimpPCH.h" 1.50 + 1.51 +// internal headers 1.52 +#include "GenVertexNormalsProcess.h" 1.53 +#include "ProcessHelper.h" 1.54 + 1.55 +using namespace Assimp; 1.56 + 1.57 +// ------------------------------------------------------------------------------------------------ 1.58 +// Constructor to be privately used by Importer 1.59 +GenVertexNormalsProcess::GenVertexNormalsProcess() 1.60 +{ 1.61 + this->configMaxAngle = AI_DEG_TO_RAD(175.f); 1.62 +} 1.63 + 1.64 +// ------------------------------------------------------------------------------------------------ 1.65 +// Destructor, private as well 1.66 +GenVertexNormalsProcess::~GenVertexNormalsProcess() 1.67 +{ 1.68 + // nothing to do here 1.69 +} 1.70 + 1.71 +// ------------------------------------------------------------------------------------------------ 1.72 +// Returns whether the processing step is present in the given flag field. 1.73 +bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const 1.74 +{ 1.75 + return (pFlags & aiProcess_GenSmoothNormals) != 0; 1.76 +} 1.77 + 1.78 +// ------------------------------------------------------------------------------------------------ 1.79 +// Executes the post processing step on the given imported data. 1.80 +void GenVertexNormalsProcess::SetupProperties(const Importer* pImp) 1.81 +{ 1.82 + // Get the current value of the AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE property 1.83 + configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,175.f); 1.84 + configMaxAngle = AI_DEG_TO_RAD(std::max(std::min(configMaxAngle,175.0f),0.0f)); 1.85 +} 1.86 + 1.87 +// ------------------------------------------------------------------------------------------------ 1.88 +// Executes the post processing step on the given imported data. 1.89 +void GenVertexNormalsProcess::Execute( aiScene* pScene) 1.90 +{ 1.91 + DefaultLogger::get()->debug("GenVertexNormalsProcess begin"); 1.92 + 1.93 + if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) 1.94 + throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); 1.95 + 1.96 + bool bHas = false; 1.97 + for( unsigned int a = 0; a < pScene->mNumMeshes; a++) 1.98 + { 1.99 + if(GenMeshVertexNormals( pScene->mMeshes[a],a)) 1.100 + bHas = true; 1.101 + } 1.102 + 1.103 + if (bHas) { 1.104 + DefaultLogger::get()->info("GenVertexNormalsProcess finished. " 1.105 + "Vertex normals have been calculated"); 1.106 + } 1.107 + else DefaultLogger::get()->debug("GenVertexNormalsProcess finished. " 1.108 + "Normals are already there"); 1.109 +} 1.110 + 1.111 +// ------------------------------------------------------------------------------------------------ 1.112 +// Executes the post processing step on the given imported data. 1.113 +bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex) 1.114 +{ 1.115 + if (NULL != pMesh->mNormals) 1.116 + return false; 1.117 + 1.118 + // If the mesh consists of lines and/or points but not of 1.119 + // triangles or higher-order polygons the normal vectors 1.120 + // are undefined. 1.121 + if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) 1.122 + { 1.123 + DefaultLogger::get()->info("Normal vectors are undefined for line and point meshes"); 1.124 + return false; 1.125 + } 1.126 + 1.127 + // Allocate the array to hold the output normals 1.128 + const float qnan = std::numeric_limits<float>::quiet_NaN(); 1.129 + pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; 1.130 + 1.131 + // Compute per-face normals but store them per-vertex 1.132 + for( unsigned int a = 0; a < pMesh->mNumFaces; a++) 1.133 + { 1.134 + const aiFace& face = pMesh->mFaces[a]; 1.135 + if (face.mNumIndices < 3) 1.136 + { 1.137 + // either a point or a line -> no normal vector 1.138 + for (unsigned int i = 0;i < face.mNumIndices;++i) { 1.139 + pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan); 1.140 + } 1.141 + 1.142 + continue; 1.143 + } 1.144 + 1.145 + const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; 1.146 + const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; 1.147 + const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]]; 1.148 + const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize(); 1.149 + 1.150 + for (unsigned int i = 0;i < face.mNumIndices;++i) { 1.151 + pMesh->mNormals[face.mIndices[i]] = vNor; 1.152 + } 1.153 + } 1.154 + 1.155 + // Set up a SpatialSort to quickly find all vertices close to a given position 1.156 + // check whether we can reuse the SpatialSort of a previous step. 1.157 + SpatialSort* vertexFinder = NULL; 1.158 + SpatialSort _vertexFinder; 1.159 + float posEpsilon = 1e-5f; 1.160 + if (shared) { 1.161 + std::vector<std::pair<SpatialSort,float> >* avf; 1.162 + shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); 1.163 + if (avf) 1.164 + { 1.165 + std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex); 1.166 + vertexFinder = &blubb.first; 1.167 + posEpsilon = blubb.second; 1.168 + } 1.169 + } 1.170 + if (!vertexFinder) { 1.171 + _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); 1.172 + vertexFinder = &_vertexFinder; 1.173 + posEpsilon = ComputePositionEpsilon(pMesh); 1.174 + } 1.175 + std::vector<unsigned int> verticesFound; 1.176 + aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices]; 1.177 + 1.178 + if (configMaxAngle >= AI_DEG_TO_RAD( 175.f )) { 1.179 + // There is no angle limit. Thus all vertices with positions close 1.180 + // to each other will receive the same vertex normal. This allows us 1.181 + // to optimize the whole algorithm a little bit ... 1.182 + std::vector<bool> abHad(pMesh->mNumVertices,false); 1.183 + for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { 1.184 + if (abHad[i]) { 1.185 + continue; 1.186 + } 1.187 + 1.188 + // Get all vertices that share this one ... 1.189 + vertexFinder->FindPositions( pMesh->mVertices[i], posEpsilon, verticesFound); 1.190 + 1.191 + aiVector3D pcNor; 1.192 + for (unsigned int a = 0; a < verticesFound.size(); ++a) { 1.193 + const aiVector3D& v = pMesh->mNormals[verticesFound[a]]; 1.194 + if (is_not_qnan(v.x))pcNor += v; 1.195 + } 1.196 + pcNor.Normalize(); 1.197 + 1.198 + // Write the smoothed normal back to all affected normals 1.199 + for (unsigned int a = 0; a < verticesFound.size(); ++a) 1.200 + { 1.201 + register unsigned int vidx = verticesFound[a]; 1.202 + pcNew[vidx] = pcNor; 1.203 + abHad[vidx] = true; 1.204 + } 1.205 + } 1.206 + } 1.207 + // Slower code path if a smooth angle is set. There are many ways to achieve 1.208 + // the effect, this one is the most straightforward one. 1.209 + else { 1.210 + const float fLimit = ::cos(configMaxAngle); 1.211 + for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { 1.212 + // Get all vertices that share this one ... 1.213 + vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound); 1.214 + 1.215 + aiVector3D pcNor; 1.216 + for (unsigned int a = 0; a < verticesFound.size(); ++a) { 1.217 + const aiVector3D& v = pMesh->mNormals[verticesFound[a]]; 1.218 + 1.219 + // check whether the angle between the two normals is not too large 1.220 + // HACK: if v.x is qnan the dot product will become qnan, too 1.221 + // therefore the comparison against fLimit should be false 1.222 + // in every case. 1.223 + if (v * pMesh->mNormals[i] < fLimit) 1.224 + continue; 1.225 + 1.226 + pcNor += v; 1.227 + } 1.228 + pcNew[i] = pcNor.Normalize(); 1.229 + } 1.230 + } 1.231 + 1.232 + delete[] pMesh->mNormals; 1.233 + pMesh->mNormals = pcNew; 1.234 + 1.235 + return true; 1.236 +}