rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 Open Asset Import Library (assimp)
|
nuclear@0
|
3 ----------------------------------------------------------------------
|
nuclear@0
|
4
|
nuclear@0
|
5 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
6 All rights reserved.
|
nuclear@0
|
7
|
nuclear@0
|
8 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
9 with or without modification, are permitted provided that the
|
nuclear@0
|
10 following conditions are met:
|
nuclear@0
|
11
|
nuclear@0
|
12 * Redistributions of source code must retain the above
|
nuclear@0
|
13 copyright notice, this list of conditions and the
|
nuclear@0
|
14 following disclaimer.
|
nuclear@0
|
15
|
nuclear@0
|
16 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
17 copyright notice, this list of conditions and the
|
nuclear@0
|
18 following disclaimer in the documentation and/or other
|
nuclear@0
|
19 materials provided with the distribution.
|
nuclear@0
|
20
|
nuclear@0
|
21 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
22 contributors may be used to endorse or promote products
|
nuclear@0
|
23 derived from this software without specific prior
|
nuclear@0
|
24 written permission of the assimp team.
|
nuclear@0
|
25
|
nuclear@0
|
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
37
|
nuclear@0
|
38 ----------------------------------------------------------------------
|
nuclear@0
|
39 */
|
nuclear@0
|
40
|
nuclear@0
|
41 /** @file GenUVCoords step */
|
nuclear@0
|
42
|
nuclear@0
|
43
|
nuclear@0
|
44 #include "AssimpPCH.h"
|
nuclear@0
|
45 #include "ComputeUVMappingProcess.h"
|
nuclear@0
|
46 #include "ProcessHelper.h"
|
nuclear@0
|
47
|
nuclear@0
|
48 using namespace Assimp;
|
nuclear@0
|
49
|
nuclear@0
|
50 namespace {
|
nuclear@0
|
51
|
nuclear@0
|
52 const static aiVector3D base_axis_y(0.f,1.f,0.f);
|
nuclear@0
|
53 const static aiVector3D base_axis_x(1.f,0.f,0.f);
|
nuclear@0
|
54 const static aiVector3D base_axis_z(0.f,0.f,1.f);
|
nuclear@0
|
55 const static float angle_epsilon = 0.95f;
|
nuclear@0
|
56 }
|
nuclear@0
|
57
|
nuclear@0
|
58 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
59 // Constructor to be privately used by Importer
|
nuclear@0
|
60 ComputeUVMappingProcess::ComputeUVMappingProcess()
|
nuclear@0
|
61 {
|
nuclear@0
|
62 // nothing to do here
|
nuclear@0
|
63 }
|
nuclear@0
|
64
|
nuclear@0
|
65 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
66 // Destructor, private as well
|
nuclear@0
|
67 ComputeUVMappingProcess::~ComputeUVMappingProcess()
|
nuclear@0
|
68 {
|
nuclear@0
|
69 // nothing to do here
|
nuclear@0
|
70 }
|
nuclear@0
|
71
|
nuclear@0
|
72 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
73 // Returns whether the processing step is present in the given flag field.
|
nuclear@0
|
74 bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const
|
nuclear@0
|
75 {
|
nuclear@0
|
76 return (pFlags & aiProcess_GenUVCoords) != 0;
|
nuclear@0
|
77 }
|
nuclear@0
|
78
|
nuclear@0
|
79 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
80 // Check whether a ray intersects a plane and find the intersection point
|
nuclear@0
|
81 inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
|
nuclear@0
|
82 const aiVector3D& planeNormal, aiVector3D& pos)
|
nuclear@0
|
83 {
|
nuclear@0
|
84 const float b = planeNormal * (planePos - ray.pos);
|
nuclear@0
|
85 float h = ray.dir * planeNormal;
|
nuclear@0
|
86 if ((h < 10e-5f && h > -10e-5f) || (h = b/h) < 0)
|
nuclear@0
|
87 return false;
|
nuclear@0
|
88
|
nuclear@0
|
89 pos = ray.pos + (ray.dir * h);
|
nuclear@0
|
90 return true;
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
94 // Find the first empty UV channel in a mesh
|
nuclear@0
|
95 inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
|
nuclear@0
|
96 {
|
nuclear@0
|
97 for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
|
nuclear@0
|
98 if (!mesh->mTextureCoords[m])return m;
|
nuclear@0
|
99
|
nuclear@0
|
100 DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found");
|
nuclear@0
|
101 return UINT_MAX;
|
nuclear@0
|
102 }
|
nuclear@0
|
103
|
nuclear@0
|
104 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
105 // Try to remove UV seams
|
nuclear@0
|
106 void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
nuclear@0
|
107 {
|
nuclear@0
|
108 // TODO: just a very rough algorithm. I think it could be done
|
nuclear@0
|
109 // much easier, but I don't know how and am currently too tired to
|
nuclear@0
|
110 // to think about a better solution.
|
nuclear@0
|
111
|
nuclear@0
|
112 const static float LOWER_LIMIT = 0.1f;
|
nuclear@0
|
113 const static float UPPER_LIMIT = 0.9f;
|
nuclear@0
|
114
|
nuclear@0
|
115 const static float LOWER_EPSILON = 10e-3f;
|
nuclear@0
|
116 const static float UPPER_EPSILON = 1.f-10e-3f;
|
nuclear@0
|
117
|
nuclear@0
|
118 for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
|
nuclear@0
|
119 {
|
nuclear@0
|
120 const aiFace& face = mesh->mFaces[fidx];
|
nuclear@0
|
121 if (face.mNumIndices < 3) continue; // triangles and polygons only, please
|
nuclear@0
|
122
|
nuclear@0
|
123 unsigned int small = face.mNumIndices, large = small;
|
nuclear@0
|
124 bool zero = false, one = false, round_to_zero = false;
|
nuclear@0
|
125
|
nuclear@0
|
126 // Check whether this face lies on a UV seam. We can just guess,
|
nuclear@0
|
127 // but the assumption that a face with at least one very small
|
nuclear@0
|
128 // on the one side and one very large U coord on the other side
|
nuclear@0
|
129 // lies on a UV seam should work for most cases.
|
nuclear@0
|
130 for (unsigned int n = 0; n < face.mNumIndices;++n)
|
nuclear@0
|
131 {
|
nuclear@0
|
132 if (out[face.mIndices[n]].x < LOWER_LIMIT)
|
nuclear@0
|
133 {
|
nuclear@0
|
134 small = n;
|
nuclear@0
|
135
|
nuclear@0
|
136 // If we have a U value very close to 0 we can't
|
nuclear@0
|
137 // round the others to 0, too.
|
nuclear@0
|
138 if (out[face.mIndices[n]].x <= LOWER_EPSILON)
|
nuclear@0
|
139 zero = true;
|
nuclear@0
|
140 else round_to_zero = true;
|
nuclear@0
|
141 }
|
nuclear@0
|
142 if (out[face.mIndices[n]].x > UPPER_LIMIT)
|
nuclear@0
|
143 {
|
nuclear@0
|
144 large = n;
|
nuclear@0
|
145
|
nuclear@0
|
146 // If we have a U value very close to 1 we can't
|
nuclear@0
|
147 // round the others to 1, too.
|
nuclear@0
|
148 if (out[face.mIndices[n]].x >= UPPER_EPSILON)
|
nuclear@0
|
149 one = true;
|
nuclear@0
|
150 }
|
nuclear@0
|
151 }
|
nuclear@0
|
152 if (small != face.mNumIndices && large != face.mNumIndices)
|
nuclear@0
|
153 {
|
nuclear@0
|
154 for (unsigned int n = 0; n < face.mNumIndices;++n)
|
nuclear@0
|
155 {
|
nuclear@0
|
156 // If the u value is over the upper limit and no other u
|
nuclear@0
|
157 // value of that face is 0, round it to 0
|
nuclear@0
|
158 if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
|
nuclear@0
|
159 out[face.mIndices[n]].x = 0.f;
|
nuclear@0
|
160
|
nuclear@0
|
161 // If the u value is below the lower limit and no other u
|
nuclear@0
|
162 // value of that face is 1, round it to 1
|
nuclear@0
|
163 else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one)
|
nuclear@0
|
164 out[face.mIndices[n]].x = 1.f;
|
nuclear@0
|
165
|
nuclear@0
|
166 // The face contains both 0 and 1 as UV coords. This can occur
|
nuclear@0
|
167 // for faces which have an edge that lies directly on the seam.
|
nuclear@0
|
168 // Due to numerical inaccuracies one U coord becomes 0, the
|
nuclear@0
|
169 // other 1. But we do still have a third UV coord to determine
|
nuclear@0
|
170 // to which side we must round to.
|
nuclear@0
|
171 else if (one && zero)
|
nuclear@0
|
172 {
|
nuclear@0
|
173 if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
|
nuclear@0
|
174 out[face.mIndices[n]].x = 0.f;
|
nuclear@0
|
175 else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
|
nuclear@0
|
176 out[face.mIndices[n]].x = 1.f;
|
nuclear@0
|
177 }
|
nuclear@0
|
178 }
|
nuclear@0
|
179 }
|
nuclear@0
|
180 }
|
nuclear@0
|
181 }
|
nuclear@0
|
182
|
nuclear@0
|
183 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
184 void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
nuclear@0
|
185 {
|
nuclear@0
|
186 aiVector3D center, min, max;
|
nuclear@0
|
187 FindMeshCenter(mesh, center, min, max);
|
nuclear@0
|
188
|
nuclear@0
|
189 // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
nuclear@0
|
190 // currently the mapping axis will always be one of x,y,z, except if the
|
nuclear@0
|
191 // PretransformVertices step is used (it transforms the meshes into worldspace,
|
nuclear@0
|
192 // thus changing the mapping axis)
|
nuclear@0
|
193 if (axis * base_axis_x >= angle_epsilon) {
|
nuclear@0
|
194
|
nuclear@0
|
195 // For each point get a normalized projection vector in the sphere,
|
nuclear@0
|
196 // get its longitude and latitude and map them to their respective
|
nuclear@0
|
197 // UV axes. Problems occur around the poles ... unsolvable.
|
nuclear@0
|
198 //
|
nuclear@0
|
199 // The spherical coordinate system looks like this:
|
nuclear@0
|
200 // x = cos(lon)*cos(lat)
|
nuclear@0
|
201 // y = sin(lon)*cos(lat)
|
nuclear@0
|
202 // z = sin(lat)
|
nuclear@0
|
203 //
|
nuclear@0
|
204 // Thus we can derive:
|
nuclear@0
|
205 // lat = arcsin (z)
|
nuclear@0
|
206 // lon = arctan (y/x)
|
nuclear@0
|
207 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
208 const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
nuclear@0
|
209 out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
nuclear@0
|
210 (asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
nuclear@0
|
211 }
|
nuclear@0
|
212 }
|
nuclear@0
|
213 else if (axis * base_axis_y >= angle_epsilon) {
|
nuclear@0
|
214 // ... just the same again
|
nuclear@0
|
215 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
216 const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
nuclear@0
|
217 out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
nuclear@0
|
218 (asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
nuclear@0
|
219 }
|
nuclear@0
|
220 }
|
nuclear@0
|
221 else if (axis * base_axis_z >= angle_epsilon) {
|
nuclear@0
|
222 // ... just the same again
|
nuclear@0
|
223 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
224 const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize();
|
nuclear@0
|
225 out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
nuclear@0
|
226 (asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
nuclear@0
|
227 }
|
nuclear@0
|
228 }
|
nuclear@0
|
229 // slower code path in case the mapping axis is not one of the coordinate system axes
|
nuclear@0
|
230 else {
|
nuclear@0
|
231 aiMatrix4x4 mTrafo;
|
nuclear@0
|
232 aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
nuclear@0
|
233
|
nuclear@0
|
234 // again the same, except we're applying a transformation now
|
nuclear@0
|
235 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
236 const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize();
|
nuclear@0
|
237 out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F,
|
nuclear@0
|
238 (asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f);
|
nuclear@0
|
239 }
|
nuclear@0
|
240 }
|
nuclear@0
|
241
|
nuclear@0
|
242
|
nuclear@0
|
243 // Now find and remove UV seams. A seam occurs if a face has a tcoord
|
nuclear@0
|
244 // close to zero on the one side, and a tcoord close to one on the
|
nuclear@0
|
245 // other side.
|
nuclear@0
|
246 RemoveUVSeams(mesh,out);
|
nuclear@0
|
247 }
|
nuclear@0
|
248
|
nuclear@0
|
249 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
250 void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
nuclear@0
|
251 {
|
nuclear@0
|
252 aiVector3D center, min, max;
|
nuclear@0
|
253
|
nuclear@0
|
254 // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
nuclear@0
|
255 // currently the mapping axis will always be one of x,y,z, except if the
|
nuclear@0
|
256 // PretransformVertices step is used (it transforms the meshes into worldspace,
|
nuclear@0
|
257 // thus changing the mapping axis)
|
nuclear@0
|
258 if (axis * base_axis_x >= angle_epsilon) {
|
nuclear@0
|
259 FindMeshCenter(mesh, center, min, max);
|
nuclear@0
|
260 const float diff = max.x - min.x;
|
nuclear@0
|
261
|
nuclear@0
|
262 // If the main axis is 'z', the z coordinate of a point 'p' is mapped
|
nuclear@0
|
263 // directly to the texture V axis. The other axis is derived from
|
nuclear@0
|
264 // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
|
nuclear@0
|
265 // 'c' is the center point of the mesh.
|
nuclear@0
|
266 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
267 const aiVector3D& pos = mesh->mVertices[pnt];
|
nuclear@0
|
268 aiVector3D& uv = out[pnt];
|
nuclear@0
|
269
|
nuclear@0
|
270 uv.y = (pos.x - min.x) / diff;
|
nuclear@0
|
271 uv.x = (atan2 ( pos.z - center.z, pos.y - center.y) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
nuclear@0
|
272 }
|
nuclear@0
|
273 }
|
nuclear@0
|
274 else if (axis * base_axis_y >= angle_epsilon) {
|
nuclear@0
|
275 FindMeshCenter(mesh, center, min, max);
|
nuclear@0
|
276 const float diff = max.y - min.y;
|
nuclear@0
|
277
|
nuclear@0
|
278 // just the same ...
|
nuclear@0
|
279 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
280 const aiVector3D& pos = mesh->mVertices[pnt];
|
nuclear@0
|
281 aiVector3D& uv = out[pnt];
|
nuclear@0
|
282
|
nuclear@0
|
283 uv.y = (pos.y - min.y) / diff;
|
nuclear@0
|
284 uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
nuclear@0
|
285 }
|
nuclear@0
|
286 }
|
nuclear@0
|
287 else if (axis * base_axis_z >= angle_epsilon) {
|
nuclear@0
|
288 FindMeshCenter(mesh, center, min, max);
|
nuclear@0
|
289 const float diff = max.z - min.z;
|
nuclear@0
|
290
|
nuclear@0
|
291 // just the same ...
|
nuclear@0
|
292 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
293 const aiVector3D& pos = mesh->mVertices[pnt];
|
nuclear@0
|
294 aiVector3D& uv = out[pnt];
|
nuclear@0
|
295
|
nuclear@0
|
296 uv.y = (pos.z - min.z) / diff;
|
nuclear@0
|
297 uv.x = (atan2 ( pos.y - center.y, pos.x - center.x) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
nuclear@0
|
298 }
|
nuclear@0
|
299 }
|
nuclear@0
|
300 // slower code path in case the mapping axis is not one of the coordinate system axes
|
nuclear@0
|
301 else {
|
nuclear@0
|
302 aiMatrix4x4 mTrafo;
|
nuclear@0
|
303 aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
nuclear@0
|
304 FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
nuclear@0
|
305 const float diff = max.y - min.y;
|
nuclear@0
|
306
|
nuclear@0
|
307 // again the same, except we're applying a transformation now
|
nuclear@0
|
308 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){
|
nuclear@0
|
309 const aiVector3D pos = mTrafo* mesh->mVertices[pnt];
|
nuclear@0
|
310 aiVector3D& uv = out[pnt];
|
nuclear@0
|
311
|
nuclear@0
|
312 uv.y = (pos.y - min.y) / diff;
|
nuclear@0
|
313 uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI;
|
nuclear@0
|
314 }
|
nuclear@0
|
315 }
|
nuclear@0
|
316
|
nuclear@0
|
317 // Now find and remove UV seams. A seam occurs if a face has a tcoord
|
nuclear@0
|
318 // close to zero on the one side, and a tcoord close to one on the
|
nuclear@0
|
319 // other side.
|
nuclear@0
|
320 RemoveUVSeams(mesh,out);
|
nuclear@0
|
321 }
|
nuclear@0
|
322
|
nuclear@0
|
323 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
324 void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out)
|
nuclear@0
|
325 {
|
nuclear@0
|
326 float diffu,diffv;
|
nuclear@0
|
327 aiVector3D center, min, max;
|
nuclear@0
|
328
|
nuclear@0
|
329 // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
|
nuclear@0
|
330 // currently the mapping axis will always be one of x,y,z, except if the
|
nuclear@0
|
331 // PretransformVertices step is used (it transforms the meshes into worldspace,
|
nuclear@0
|
332 // thus changing the mapping axis)
|
nuclear@0
|
333 if (axis * base_axis_x >= angle_epsilon) {
|
nuclear@0
|
334 FindMeshCenter(mesh, center, min, max);
|
nuclear@0
|
335 diffu = max.z - min.z;
|
nuclear@0
|
336 diffv = max.y - min.y;
|
nuclear@0
|
337
|
nuclear@0
|
338 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
339 const aiVector3D& pos = mesh->mVertices[pnt];
|
nuclear@0
|
340 out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.f);
|
nuclear@0
|
341 }
|
nuclear@0
|
342 }
|
nuclear@0
|
343 else if (axis * base_axis_y >= angle_epsilon) {
|
nuclear@0
|
344 FindMeshCenter(mesh, center, min, max);
|
nuclear@0
|
345 diffu = max.x - min.x;
|
nuclear@0
|
346 diffv = max.z - min.z;
|
nuclear@0
|
347
|
nuclear@0
|
348 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
349 const aiVector3D& pos = mesh->mVertices[pnt];
|
nuclear@0
|
350 out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
|
nuclear@0
|
351 }
|
nuclear@0
|
352 }
|
nuclear@0
|
353 else if (axis * base_axis_z >= angle_epsilon) {
|
nuclear@0
|
354 FindMeshCenter(mesh, center, min, max);
|
nuclear@0
|
355 diffu = max.y - min.y;
|
nuclear@0
|
356 diffv = max.z - min.z;
|
nuclear@0
|
357
|
nuclear@0
|
358 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
359 const aiVector3D& pos = mesh->mVertices[pnt];
|
nuclear@0
|
360 out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.f);
|
nuclear@0
|
361 }
|
nuclear@0
|
362 }
|
nuclear@0
|
363 // slower code path in case the mapping axis is not one of the coordinate system axes
|
nuclear@0
|
364 else
|
nuclear@0
|
365 {
|
nuclear@0
|
366 aiMatrix4x4 mTrafo;
|
nuclear@0
|
367 aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo);
|
nuclear@0
|
368 FindMeshCenterTransformed(mesh, center, min, max,mTrafo);
|
nuclear@0
|
369 diffu = max.x - min.x;
|
nuclear@0
|
370 diffv = max.z - min.z;
|
nuclear@0
|
371
|
nuclear@0
|
372 // again the same, except we're applying a transformation now
|
nuclear@0
|
373 for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
nuclear@0
|
374 const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
|
nuclear@0
|
375 out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f);
|
nuclear@0
|
376 }
|
nuclear@0
|
377 }
|
nuclear@0
|
378
|
nuclear@0
|
379 // shouldn't be necessary to remove UV seams ...
|
nuclear@0
|
380 }
|
nuclear@0
|
381
|
nuclear@0
|
382 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
383 void ComputeUVMappingProcess::ComputeBoxMapping(aiMesh* /*mesh*/, aiVector3D* /*out*/)
|
nuclear@0
|
384 {
|
nuclear@0
|
385 DefaultLogger::get()->error("Mapping type currently not implemented");
|
nuclear@0
|
386 }
|
nuclear@0
|
387
|
nuclear@0
|
388 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
389 void ComputeUVMappingProcess::Execute( aiScene* pScene)
|
nuclear@0
|
390 {
|
nuclear@0
|
391 DefaultLogger::get()->debug("GenUVCoordsProcess begin");
|
nuclear@0
|
392 char buffer[1024];
|
nuclear@0
|
393
|
nuclear@0
|
394 if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
|
nuclear@0
|
395 throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
|
nuclear@0
|
396
|
nuclear@0
|
397 std::list<MappingInfo> mappingStack;
|
nuclear@0
|
398
|
nuclear@0
|
399 /* Iterate through all materials and search for non-UV mapped textures
|
nuclear@0
|
400 */
|
nuclear@0
|
401 for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
nuclear@0
|
402 {
|
nuclear@0
|
403 mappingStack.clear();
|
nuclear@0
|
404 aiMaterial* mat = pScene->mMaterials[i];
|
nuclear@0
|
405 for (unsigned int a = 0; a < mat->mNumProperties;++a)
|
nuclear@0
|
406 {
|
nuclear@0
|
407 aiMaterialProperty* prop = mat->mProperties[a];
|
nuclear@0
|
408 if (!::strcmp( prop->mKey.data, "$tex.mapping"))
|
nuclear@0
|
409 {
|
nuclear@0
|
410 aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData);
|
nuclear@0
|
411 if (aiTextureMapping_UV != mapping)
|
nuclear@0
|
412 {
|
nuclear@0
|
413 if (!DefaultLogger::isNullLogger())
|
nuclear@0
|
414 {
|
nuclear@0
|
415 sprintf(buffer, "Found non-UV mapped texture (%s,%i). Mapping type: %s",
|
nuclear@0
|
416 TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
|
nuclear@0
|
417 MappingTypeToString(mapping));
|
nuclear@0
|
418
|
nuclear@0
|
419 DefaultLogger::get()->info(buffer);
|
nuclear@0
|
420 }
|
nuclear@0
|
421
|
nuclear@0
|
422 if (aiTextureMapping_OTHER == mapping)
|
nuclear@0
|
423 continue;
|
nuclear@0
|
424
|
nuclear@0
|
425 MappingInfo info (mapping);
|
nuclear@0
|
426
|
nuclear@0
|
427 // Get further properties - currently only the major axis
|
nuclear@0
|
428 for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2)
|
nuclear@0
|
429 {
|
nuclear@0
|
430 aiMaterialProperty* prop2 = mat->mProperties[a2];
|
nuclear@0
|
431 if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
|
nuclear@0
|
432 continue;
|
nuclear@0
|
433
|
nuclear@0
|
434 if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) {
|
nuclear@0
|
435 info.axis = *((aiVector3D*)prop2->mData);
|
nuclear@0
|
436 break;
|
nuclear@0
|
437 }
|
nuclear@0
|
438 }
|
nuclear@0
|
439
|
nuclear@0
|
440 unsigned int idx;
|
nuclear@0
|
441
|
nuclear@0
|
442 // Check whether we have this mapping mode already
|
nuclear@0
|
443 std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info);
|
nuclear@0
|
444 if (mappingStack.end() != it)
|
nuclear@0
|
445 {
|
nuclear@0
|
446 idx = (*it).uv;
|
nuclear@0
|
447 }
|
nuclear@0
|
448 else
|
nuclear@0
|
449 {
|
nuclear@0
|
450 /* We have found a non-UV mapped texture. Now
|
nuclear@0
|
451 * we need to find all meshes using this material
|
nuclear@0
|
452 * that we can compute UV channels for them.
|
nuclear@0
|
453 */
|
nuclear@0
|
454 for (unsigned int m = 0; m < pScene->mNumMeshes;++m)
|
nuclear@0
|
455 {
|
nuclear@0
|
456 aiMesh* mesh = pScene->mMeshes[m];
|
nuclear@0
|
457 unsigned int outIdx;
|
nuclear@0
|
458 if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX ||
|
nuclear@0
|
459 !mesh->mNumVertices)
|
nuclear@0
|
460 {
|
nuclear@0
|
461 continue;
|
nuclear@0
|
462 }
|
nuclear@0
|
463
|
nuclear@0
|
464 // Allocate output storage
|
nuclear@0
|
465 aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
466
|
nuclear@0
|
467 switch (mapping)
|
nuclear@0
|
468 {
|
nuclear@0
|
469 case aiTextureMapping_SPHERE:
|
nuclear@0
|
470 ComputeSphereMapping(mesh,info.axis,p);
|
nuclear@0
|
471 break;
|
nuclear@0
|
472 case aiTextureMapping_CYLINDER:
|
nuclear@0
|
473 ComputeCylinderMapping(mesh,info.axis,p);
|
nuclear@0
|
474 break;
|
nuclear@0
|
475 case aiTextureMapping_PLANE:
|
nuclear@0
|
476 ComputePlaneMapping(mesh,info.axis,p);
|
nuclear@0
|
477 break;
|
nuclear@0
|
478 case aiTextureMapping_BOX:
|
nuclear@0
|
479 ComputeBoxMapping(mesh,p);
|
nuclear@0
|
480 break;
|
nuclear@0
|
481 default:
|
nuclear@0
|
482 ai_assert(false);
|
nuclear@0
|
483 }
|
nuclear@0
|
484 if (m && idx != outIdx)
|
nuclear@0
|
485 {
|
nuclear@0
|
486 DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to "
|
nuclear@0
|
487 "this material have equal numbers of UV channels. The UV index stored in "
|
nuclear@0
|
488 "the material structure does therefore not apply for all meshes. ");
|
nuclear@0
|
489 }
|
nuclear@0
|
490 idx = outIdx;
|
nuclear@0
|
491 }
|
nuclear@0
|
492 info.uv = idx;
|
nuclear@0
|
493 mappingStack.push_back(info);
|
nuclear@0
|
494 }
|
nuclear@0
|
495
|
nuclear@0
|
496 // Update the material property list
|
nuclear@0
|
497 mapping = aiTextureMapping_UV;
|
nuclear@0
|
498 ((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex));
|
nuclear@0
|
499 }
|
nuclear@0
|
500 }
|
nuclear@0
|
501 }
|
nuclear@0
|
502 }
|
nuclear@0
|
503 DefaultLogger::get()->debug("GenUVCoordsProcess finished");
|
nuclear@0
|
504 }
|