nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file GenUVCoords step */ nuclear@0: nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #include "ComputeUVMappingProcess.h" nuclear@0: #include "ProcessHelper.h" nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: nuclear@0: namespace { nuclear@0: nuclear@0: const static aiVector3D base_axis_y(0.f,1.f,0.f); nuclear@0: const static aiVector3D base_axis_x(1.f,0.f,0.f); nuclear@0: const static aiVector3D base_axis_z(0.f,0.f,1.f); nuclear@0: const static float angle_epsilon = 0.95f; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Constructor to be privately used by Importer nuclear@0: ComputeUVMappingProcess::ComputeUVMappingProcess() nuclear@0: { nuclear@0: // nothing to do here nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Destructor, private as well nuclear@0: ComputeUVMappingProcess::~ComputeUVMappingProcess() nuclear@0: { nuclear@0: // nothing to do here nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns whether the processing step is present in the given flag field. nuclear@0: bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const nuclear@0: { nuclear@0: return (pFlags & aiProcess_GenUVCoords) != 0; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Check whether a ray intersects a plane and find the intersection point nuclear@0: inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, nuclear@0: const aiVector3D& planeNormal, aiVector3D& pos) nuclear@0: { nuclear@0: const float b = planeNormal * (planePos - ray.pos); nuclear@0: float h = ray.dir * planeNormal; nuclear@0: if ((h < 10e-5f && h > -10e-5f) || (h = b/h) < 0) nuclear@0: return false; nuclear@0: nuclear@0: pos = ray.pos + (ray.dir * h); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Find the first empty UV channel in a mesh nuclear@0: inline unsigned int FindEmptyUVChannel (aiMesh* mesh) nuclear@0: { nuclear@0: for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m) nuclear@0: if (!mesh->mTextureCoords[m])return m; nuclear@0: nuclear@0: DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found"); nuclear@0: return UINT_MAX; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Try to remove UV seams nuclear@0: void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) nuclear@0: { nuclear@0: // TODO: just a very rough algorithm. I think it could be done nuclear@0: // much easier, but I don't know how and am currently too tired to nuclear@0: // to think about a better solution. nuclear@0: nuclear@0: const static float LOWER_LIMIT = 0.1f; nuclear@0: const static float UPPER_LIMIT = 0.9f; nuclear@0: nuclear@0: const static float LOWER_EPSILON = 10e-3f; nuclear@0: const static float UPPER_EPSILON = 1.f-10e-3f; nuclear@0: nuclear@0: for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) nuclear@0: { nuclear@0: const aiFace& face = mesh->mFaces[fidx]; nuclear@0: if (face.mNumIndices < 3) continue; // triangles and polygons only, please nuclear@0: nuclear@0: unsigned int small = face.mNumIndices, large = small; nuclear@0: bool zero = false, one = false, round_to_zero = false; nuclear@0: nuclear@0: // Check whether this face lies on a UV seam. We can just guess, nuclear@0: // but the assumption that a face with at least one very small nuclear@0: // on the one side and one very large U coord on the other side nuclear@0: // lies on a UV seam should work for most cases. nuclear@0: for (unsigned int n = 0; n < face.mNumIndices;++n) nuclear@0: { nuclear@0: if (out[face.mIndices[n]].x < LOWER_LIMIT) nuclear@0: { nuclear@0: small = n; nuclear@0: nuclear@0: // If we have a U value very close to 0 we can't nuclear@0: // round the others to 0, too. nuclear@0: if (out[face.mIndices[n]].x <= LOWER_EPSILON) nuclear@0: zero = true; nuclear@0: else round_to_zero = true; nuclear@0: } nuclear@0: if (out[face.mIndices[n]].x > UPPER_LIMIT) nuclear@0: { nuclear@0: large = n; nuclear@0: nuclear@0: // If we have a U value very close to 1 we can't nuclear@0: // round the others to 1, too. nuclear@0: if (out[face.mIndices[n]].x >= UPPER_EPSILON) nuclear@0: one = true; nuclear@0: } nuclear@0: } nuclear@0: if (small != face.mNumIndices && large != face.mNumIndices) nuclear@0: { nuclear@0: for (unsigned int n = 0; n < face.mNumIndices;++n) nuclear@0: { nuclear@0: // If the u value is over the upper limit and no other u nuclear@0: // value of that face is 0, round it to 0 nuclear@0: if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero) nuclear@0: out[face.mIndices[n]].x = 0.f; nuclear@0: nuclear@0: // If the u value is below the lower limit and no other u nuclear@0: // value of that face is 1, round it to 1 nuclear@0: else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one) nuclear@0: out[face.mIndices[n]].x = 1.f; nuclear@0: nuclear@0: // The face contains both 0 and 1 as UV coords. This can occur nuclear@0: // for faces which have an edge that lies directly on the seam. nuclear@0: // Due to numerical inaccuracies one U coord becomes 0, the nuclear@0: // other 1. But we do still have a third UV coord to determine nuclear@0: // to which side we must round to. nuclear@0: else if (one && zero) nuclear@0: { nuclear@0: if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON) nuclear@0: out[face.mIndices[n]].x = 0.f; nuclear@0: else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON) nuclear@0: out[face.mIndices[n]].x = 1.f; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) nuclear@0: { nuclear@0: aiVector3D center, min, max; nuclear@0: FindMeshCenter(mesh, center, min, max); nuclear@0: nuclear@0: // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... nuclear@0: // currently the mapping axis will always be one of x,y,z, except if the nuclear@0: // PretransformVertices step is used (it transforms the meshes into worldspace, nuclear@0: // thus changing the mapping axis) nuclear@0: if (axis * base_axis_x >= angle_epsilon) { nuclear@0: nuclear@0: // For each point get a normalized projection vector in the sphere, nuclear@0: // get its longitude and latitude and map them to their respective nuclear@0: // UV axes. Problems occur around the poles ... unsolvable. nuclear@0: // nuclear@0: // The spherical coordinate system looks like this: nuclear@0: // x = cos(lon)*cos(lat) nuclear@0: // y = sin(lon)*cos(lat) nuclear@0: // z = sin(lat) nuclear@0: // nuclear@0: // Thus we can derive: nuclear@0: // lat = arcsin (z) nuclear@0: // lon = arctan (y/x) nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); nuclear@0: out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, nuclear@0: (asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); nuclear@0: } nuclear@0: } nuclear@0: else if (axis * base_axis_y >= angle_epsilon) { nuclear@0: // ... just the same again nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); nuclear@0: out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, nuclear@0: (asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); nuclear@0: } nuclear@0: } nuclear@0: else if (axis * base_axis_z >= angle_epsilon) { nuclear@0: // ... just the same again nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); nuclear@0: out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, nuclear@0: (asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); nuclear@0: } nuclear@0: } nuclear@0: // slower code path in case the mapping axis is not one of the coordinate system axes nuclear@0: else { nuclear@0: aiMatrix4x4 mTrafo; nuclear@0: aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); nuclear@0: nuclear@0: // again the same, except we're applying a transformation now nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize(); nuclear@0: out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, nuclear@0: (asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // Now find and remove UV seams. A seam occurs if a face has a tcoord nuclear@0: // close to zero on the one side, and a tcoord close to one on the nuclear@0: // other side. nuclear@0: RemoveUVSeams(mesh,out); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) nuclear@0: { nuclear@0: aiVector3D center, min, max; nuclear@0: nuclear@0: // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... nuclear@0: // currently the mapping axis will always be one of x,y,z, except if the nuclear@0: // PretransformVertices step is used (it transforms the meshes into worldspace, nuclear@0: // thus changing the mapping axis) nuclear@0: if (axis * base_axis_x >= angle_epsilon) { nuclear@0: FindMeshCenter(mesh, center, min, max); nuclear@0: const float diff = max.x - min.x; nuclear@0: nuclear@0: // If the main axis is 'z', the z coordinate of a point 'p' is mapped nuclear@0: // directly to the texture V axis. The other axis is derived from nuclear@0: // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where nuclear@0: // 'c' is the center point of the mesh. nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D& pos = mesh->mVertices[pnt]; nuclear@0: aiVector3D& uv = out[pnt]; nuclear@0: nuclear@0: uv.y = (pos.x - min.x) / diff; nuclear@0: uv.x = (atan2 ( pos.z - center.z, pos.y - center.y) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI; nuclear@0: } nuclear@0: } nuclear@0: else if (axis * base_axis_y >= angle_epsilon) { nuclear@0: FindMeshCenter(mesh, center, min, max); nuclear@0: const float diff = max.y - min.y; nuclear@0: nuclear@0: // just the same ... nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D& pos = mesh->mVertices[pnt]; nuclear@0: aiVector3D& uv = out[pnt]; nuclear@0: nuclear@0: uv.y = (pos.y - min.y) / diff; nuclear@0: uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI; nuclear@0: } nuclear@0: } nuclear@0: else if (axis * base_axis_z >= angle_epsilon) { nuclear@0: FindMeshCenter(mesh, center, min, max); nuclear@0: const float diff = max.z - min.z; nuclear@0: nuclear@0: // just the same ... nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D& pos = mesh->mVertices[pnt]; nuclear@0: aiVector3D& uv = out[pnt]; nuclear@0: nuclear@0: uv.y = (pos.z - min.z) / diff; nuclear@0: uv.x = (atan2 ( pos.y - center.y, pos.x - center.x) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI; nuclear@0: } nuclear@0: } nuclear@0: // slower code path in case the mapping axis is not one of the coordinate system axes nuclear@0: else { nuclear@0: aiMatrix4x4 mTrafo; nuclear@0: aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); nuclear@0: FindMeshCenterTransformed(mesh, center, min, max,mTrafo); nuclear@0: const float diff = max.y - min.y; nuclear@0: nuclear@0: // again the same, except we're applying a transformation now nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){ nuclear@0: const aiVector3D pos = mTrafo* mesh->mVertices[pnt]; nuclear@0: aiVector3D& uv = out[pnt]; nuclear@0: nuclear@0: uv.y = (pos.y - min.y) / diff; nuclear@0: uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Now find and remove UV seams. A seam occurs if a face has a tcoord nuclear@0: // close to zero on the one side, and a tcoord close to one on the nuclear@0: // other side. nuclear@0: RemoveUVSeams(mesh,out); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) nuclear@0: { nuclear@0: float diffu,diffv; nuclear@0: aiVector3D center, min, max; nuclear@0: nuclear@0: // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... nuclear@0: // currently the mapping axis will always be one of x,y,z, except if the nuclear@0: // PretransformVertices step is used (it transforms the meshes into worldspace, nuclear@0: // thus changing the mapping axis) nuclear@0: if (axis * base_axis_x >= angle_epsilon) { nuclear@0: FindMeshCenter(mesh, center, min, max); nuclear@0: diffu = max.z - min.z; nuclear@0: diffv = max.y - min.y; nuclear@0: nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D& pos = mesh->mVertices[pnt]; nuclear@0: out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.f); nuclear@0: } nuclear@0: } nuclear@0: else if (axis * base_axis_y >= angle_epsilon) { nuclear@0: FindMeshCenter(mesh, center, min, max); nuclear@0: diffu = max.x - min.x; nuclear@0: diffv = max.z - min.z; nuclear@0: nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D& pos = mesh->mVertices[pnt]; nuclear@0: out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f); nuclear@0: } nuclear@0: } nuclear@0: else if (axis * base_axis_z >= angle_epsilon) { nuclear@0: FindMeshCenter(mesh, center, min, max); nuclear@0: diffu = max.y - min.y; nuclear@0: diffv = max.z - min.z; nuclear@0: nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D& pos = mesh->mVertices[pnt]; nuclear@0: out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.f); nuclear@0: } nuclear@0: } nuclear@0: // slower code path in case the mapping axis is not one of the coordinate system axes nuclear@0: else nuclear@0: { nuclear@0: aiMatrix4x4 mTrafo; nuclear@0: aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); nuclear@0: FindMeshCenterTransformed(mesh, center, min, max,mTrafo); nuclear@0: diffu = max.x - min.x; nuclear@0: diffv = max.z - min.z; nuclear@0: nuclear@0: // again the same, except we're applying a transformation now nuclear@0: for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { nuclear@0: const aiVector3D pos = mTrafo * mesh->mVertices[pnt]; nuclear@0: out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // shouldn't be necessary to remove UV seams ... nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void ComputeUVMappingProcess::ComputeBoxMapping(aiMesh* /*mesh*/, aiVector3D* /*out*/) nuclear@0: { nuclear@0: DefaultLogger::get()->error("Mapping type currently not implemented"); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void ComputeUVMappingProcess::Execute( aiScene* pScene) nuclear@0: { nuclear@0: DefaultLogger::get()->debug("GenUVCoordsProcess begin"); nuclear@0: char buffer[1024]; nuclear@0: nuclear@0: if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) nuclear@0: throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); nuclear@0: nuclear@0: std::list mappingStack; nuclear@0: nuclear@0: /* Iterate through all materials and search for non-UV mapped textures nuclear@0: */ nuclear@0: for (unsigned int i = 0; i < pScene->mNumMaterials;++i) nuclear@0: { nuclear@0: mappingStack.clear(); nuclear@0: aiMaterial* mat = pScene->mMaterials[i]; nuclear@0: for (unsigned int a = 0; a < mat->mNumProperties;++a) nuclear@0: { nuclear@0: aiMaterialProperty* prop = mat->mProperties[a]; nuclear@0: if (!::strcmp( prop->mKey.data, "$tex.mapping")) nuclear@0: { nuclear@0: aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData); nuclear@0: if (aiTextureMapping_UV != mapping) nuclear@0: { nuclear@0: if (!DefaultLogger::isNullLogger()) nuclear@0: { nuclear@0: sprintf(buffer, "Found non-UV mapped texture (%s,%i). Mapping type: %s", nuclear@0: TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, nuclear@0: MappingTypeToString(mapping)); nuclear@0: nuclear@0: DefaultLogger::get()->info(buffer); nuclear@0: } nuclear@0: nuclear@0: if (aiTextureMapping_OTHER == mapping) nuclear@0: continue; nuclear@0: nuclear@0: MappingInfo info (mapping); nuclear@0: nuclear@0: // Get further properties - currently only the major axis nuclear@0: for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) nuclear@0: { nuclear@0: aiMaterialProperty* prop2 = mat->mProperties[a2]; nuclear@0: if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) nuclear@0: continue; nuclear@0: nuclear@0: if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) { nuclear@0: info.axis = *((aiVector3D*)prop2->mData); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: unsigned int idx; nuclear@0: nuclear@0: // Check whether we have this mapping mode already nuclear@0: std::list::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info); nuclear@0: if (mappingStack.end() != it) nuclear@0: { nuclear@0: idx = (*it).uv; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: /* We have found a non-UV mapped texture. Now nuclear@0: * we need to find all meshes using this material nuclear@0: * that we can compute UV channels for them. nuclear@0: */ nuclear@0: for (unsigned int m = 0; m < pScene->mNumMeshes;++m) nuclear@0: { nuclear@0: aiMesh* mesh = pScene->mMeshes[m]; nuclear@0: unsigned int outIdx; nuclear@0: if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX || nuclear@0: !mesh->mNumVertices) nuclear@0: { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: // Allocate output storage nuclear@0: aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices]; nuclear@0: nuclear@0: switch (mapping) nuclear@0: { nuclear@0: case aiTextureMapping_SPHERE: nuclear@0: ComputeSphereMapping(mesh,info.axis,p); nuclear@0: break; nuclear@0: case aiTextureMapping_CYLINDER: nuclear@0: ComputeCylinderMapping(mesh,info.axis,p); nuclear@0: break; nuclear@0: case aiTextureMapping_PLANE: nuclear@0: ComputePlaneMapping(mesh,info.axis,p); nuclear@0: break; nuclear@0: case aiTextureMapping_BOX: nuclear@0: ComputeBoxMapping(mesh,p); nuclear@0: break; nuclear@0: default: nuclear@0: ai_assert(false); nuclear@0: } nuclear@0: if (m && idx != outIdx) nuclear@0: { nuclear@0: DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to " nuclear@0: "this material have equal numbers of UV channels. The UV index stored in " nuclear@0: "the material structure does therefore not apply for all meshes. "); nuclear@0: } nuclear@0: idx = outIdx; nuclear@0: } nuclear@0: info.uv = idx; nuclear@0: mappingStack.push_back(info); nuclear@0: } nuclear@0: nuclear@0: // Update the material property list nuclear@0: mapping = aiTextureMapping_UV; nuclear@0: ((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex)); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: DefaultLogger::get()->debug("GenUVCoordsProcess finished"); nuclear@0: }