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