vrshoot

annotate 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
rev   line source
nuclear@0 1 /*
nuclear@0 2 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file Implementation of the post processing step to generate face
nuclear@0 43 * normals for all imported faces.
nuclear@0 44 */
nuclear@0 45
nuclear@0 46 #include "AssimpPCH.h"
nuclear@0 47
nuclear@0 48 // internal headers
nuclear@0 49 #include "GenVertexNormalsProcess.h"
nuclear@0 50 #include "ProcessHelper.h"
nuclear@0 51
nuclear@0 52 using namespace Assimp;
nuclear@0 53
nuclear@0 54 // ------------------------------------------------------------------------------------------------
nuclear@0 55 // Constructor to be privately used by Importer
nuclear@0 56 GenVertexNormalsProcess::GenVertexNormalsProcess()
nuclear@0 57 {
nuclear@0 58 this->configMaxAngle = AI_DEG_TO_RAD(175.f);
nuclear@0 59 }
nuclear@0 60
nuclear@0 61 // ------------------------------------------------------------------------------------------------
nuclear@0 62 // Destructor, private as well
nuclear@0 63 GenVertexNormalsProcess::~GenVertexNormalsProcess()
nuclear@0 64 {
nuclear@0 65 // nothing to do here
nuclear@0 66 }
nuclear@0 67
nuclear@0 68 // ------------------------------------------------------------------------------------------------
nuclear@0 69 // Returns whether the processing step is present in the given flag field.
nuclear@0 70 bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const
nuclear@0 71 {
nuclear@0 72 return (pFlags & aiProcess_GenSmoothNormals) != 0;
nuclear@0 73 }
nuclear@0 74
nuclear@0 75 // ------------------------------------------------------------------------------------------------
nuclear@0 76 // Executes the post processing step on the given imported data.
nuclear@0 77 void GenVertexNormalsProcess::SetupProperties(const Importer* pImp)
nuclear@0 78 {
nuclear@0 79 // Get the current value of the AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE property
nuclear@0 80 configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,175.f);
nuclear@0 81 configMaxAngle = AI_DEG_TO_RAD(std::max(std::min(configMaxAngle,175.0f),0.0f));
nuclear@0 82 }
nuclear@0 83
nuclear@0 84 // ------------------------------------------------------------------------------------------------
nuclear@0 85 // Executes the post processing step on the given imported data.
nuclear@0 86 void GenVertexNormalsProcess::Execute( aiScene* pScene)
nuclear@0 87 {
nuclear@0 88 DefaultLogger::get()->debug("GenVertexNormalsProcess begin");
nuclear@0 89
nuclear@0 90 if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
nuclear@0 91 throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
nuclear@0 92
nuclear@0 93 bool bHas = false;
nuclear@0 94 for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
nuclear@0 95 {
nuclear@0 96 if(GenMeshVertexNormals( pScene->mMeshes[a],a))
nuclear@0 97 bHas = true;
nuclear@0 98 }
nuclear@0 99
nuclear@0 100 if (bHas) {
nuclear@0 101 DefaultLogger::get()->info("GenVertexNormalsProcess finished. "
nuclear@0 102 "Vertex normals have been calculated");
nuclear@0 103 }
nuclear@0 104 else DefaultLogger::get()->debug("GenVertexNormalsProcess finished. "
nuclear@0 105 "Normals are already there");
nuclear@0 106 }
nuclear@0 107
nuclear@0 108 // ------------------------------------------------------------------------------------------------
nuclear@0 109 // Executes the post processing step on the given imported data.
nuclear@0 110 bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex)
nuclear@0 111 {
nuclear@0 112 if (NULL != pMesh->mNormals)
nuclear@0 113 return false;
nuclear@0 114
nuclear@0 115 // If the mesh consists of lines and/or points but not of
nuclear@0 116 // triangles or higher-order polygons the normal vectors
nuclear@0 117 // are undefined.
nuclear@0 118 if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
nuclear@0 119 {
nuclear@0 120 DefaultLogger::get()->info("Normal vectors are undefined for line and point meshes");
nuclear@0 121 return false;
nuclear@0 122 }
nuclear@0 123
nuclear@0 124 // Allocate the array to hold the output normals
nuclear@0 125 const float qnan = std::numeric_limits<float>::quiet_NaN();
nuclear@0 126 pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
nuclear@0 127
nuclear@0 128 // Compute per-face normals but store them per-vertex
nuclear@0 129 for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
nuclear@0 130 {
nuclear@0 131 const aiFace& face = pMesh->mFaces[a];
nuclear@0 132 if (face.mNumIndices < 3)
nuclear@0 133 {
nuclear@0 134 // either a point or a line -> no normal vector
nuclear@0 135 for (unsigned int i = 0;i < face.mNumIndices;++i) {
nuclear@0 136 pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan);
nuclear@0 137 }
nuclear@0 138
nuclear@0 139 continue;
nuclear@0 140 }
nuclear@0 141
nuclear@0 142 const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
nuclear@0 143 const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
nuclear@0 144 const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
nuclear@0 145 const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize();
nuclear@0 146
nuclear@0 147 for (unsigned int i = 0;i < face.mNumIndices;++i) {
nuclear@0 148 pMesh->mNormals[face.mIndices[i]] = vNor;
nuclear@0 149 }
nuclear@0 150 }
nuclear@0 151
nuclear@0 152 // Set up a SpatialSort to quickly find all vertices close to a given position
nuclear@0 153 // check whether we can reuse the SpatialSort of a previous step.
nuclear@0 154 SpatialSort* vertexFinder = NULL;
nuclear@0 155 SpatialSort _vertexFinder;
nuclear@0 156 float posEpsilon = 1e-5f;
nuclear@0 157 if (shared) {
nuclear@0 158 std::vector<std::pair<SpatialSort,float> >* avf;
nuclear@0 159 shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
nuclear@0 160 if (avf)
nuclear@0 161 {
nuclear@0 162 std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
nuclear@0 163 vertexFinder = &blubb.first;
nuclear@0 164 posEpsilon = blubb.second;
nuclear@0 165 }
nuclear@0 166 }
nuclear@0 167 if (!vertexFinder) {
nuclear@0 168 _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
nuclear@0 169 vertexFinder = &_vertexFinder;
nuclear@0 170 posEpsilon = ComputePositionEpsilon(pMesh);
nuclear@0 171 }
nuclear@0 172 std::vector<unsigned int> verticesFound;
nuclear@0 173 aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
nuclear@0 174
nuclear@0 175 if (configMaxAngle >= AI_DEG_TO_RAD( 175.f )) {
nuclear@0 176 // There is no angle limit. Thus all vertices with positions close
nuclear@0 177 // to each other will receive the same vertex normal. This allows us
nuclear@0 178 // to optimize the whole algorithm a little bit ...
nuclear@0 179 std::vector<bool> abHad(pMesh->mNumVertices,false);
nuclear@0 180 for (unsigned int i = 0; i < pMesh->mNumVertices;++i) {
nuclear@0 181 if (abHad[i]) {
nuclear@0 182 continue;
nuclear@0 183 }
nuclear@0 184
nuclear@0 185 // Get all vertices that share this one ...
nuclear@0 186 vertexFinder->FindPositions( pMesh->mVertices[i], posEpsilon, verticesFound);
nuclear@0 187
nuclear@0 188 aiVector3D pcNor;
nuclear@0 189 for (unsigned int a = 0; a < verticesFound.size(); ++a) {
nuclear@0 190 const aiVector3D& v = pMesh->mNormals[verticesFound[a]];
nuclear@0 191 if (is_not_qnan(v.x))pcNor += v;
nuclear@0 192 }
nuclear@0 193 pcNor.Normalize();
nuclear@0 194
nuclear@0 195 // Write the smoothed normal back to all affected normals
nuclear@0 196 for (unsigned int a = 0; a < verticesFound.size(); ++a)
nuclear@0 197 {
nuclear@0 198 register unsigned int vidx = verticesFound[a];
nuclear@0 199 pcNew[vidx] = pcNor;
nuclear@0 200 abHad[vidx] = true;
nuclear@0 201 }
nuclear@0 202 }
nuclear@0 203 }
nuclear@0 204 // Slower code path if a smooth angle is set. There are many ways to achieve
nuclear@0 205 // the effect, this one is the most straightforward one.
nuclear@0 206 else {
nuclear@0 207 const float fLimit = ::cos(configMaxAngle);
nuclear@0 208 for (unsigned int i = 0; i < pMesh->mNumVertices;++i) {
nuclear@0 209 // Get all vertices that share this one ...
nuclear@0 210 vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound);
nuclear@0 211
nuclear@0 212 aiVector3D pcNor;
nuclear@0 213 for (unsigned int a = 0; a < verticesFound.size(); ++a) {
nuclear@0 214 const aiVector3D& v = pMesh->mNormals[verticesFound[a]];
nuclear@0 215
nuclear@0 216 // check whether the angle between the two normals is not too large
nuclear@0 217 // HACK: if v.x is qnan the dot product will become qnan, too
nuclear@0 218 // therefore the comparison against fLimit should be false
nuclear@0 219 // in every case.
nuclear@0 220 if (v * pMesh->mNormals[i] < fLimit)
nuclear@0 221 continue;
nuclear@0 222
nuclear@0 223 pcNor += v;
nuclear@0 224 }
nuclear@0 225 pcNew[i] = pcNor.Normalize();
nuclear@0 226 }
nuclear@0 227 }
nuclear@0 228
nuclear@0 229 delete[] pMesh->mNormals;
nuclear@0 230 pMesh->mNormals = pcNew;
nuclear@0 231
nuclear@0 232 return true;
nuclear@0 233 }