Guest User

mesh welding

a guest
Apr 22nd, 2016
250
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.12 KB | None | 0 0
  1. namespace
  2. {
  3. //computes a hash
  4. REALINLINE u32 getBucketFromVector(const core::vector3df& vec, f32 tolerance, u32 bucketCount)
  5. {
  6.     f32 sum = (vec.X + vec.Y + vec.Z) / tolerance;
  7.     return ((u32)sum) % bucketCount;
  8. }
  9.  
  10. //helpers for comparing vertices
  11. template<typename T>
  12. bool vertsAreEqual(const T& v1, const T& v2, f32 tolerance, bool ignoreNormals)
  13. {
  14.     //empty, see specializations
  15. }
  16.  
  17. template<>
  18. inline bool vertsAreEqual<video::S3DVertex>(const video::S3DVertex& v1, const video::S3DVertex& v2, f32 tolerance, bool ignoreNormals)
  19. {
  20.     return
  21.         v1.Pos.equals(v2.Pos, tolerance) &&
  22.         (ignoreNormals || v1.Normal.equals(v2.Normal, tolerance)) &&
  23.         v1.TCoords.equals(v2.TCoords, tolerance) &&
  24.         (v1.Color == v2.Color);
  25. }
  26.  
  27. template<>
  28. inline bool vertsAreEqual<video::S3DVertex2TCoords>(const video::S3DVertex2TCoords& v1, const video::S3DVertex2TCoords& v2, f32 tolerance, bool ignoreNormals)
  29. {
  30.     return
  31.         v1.Pos.equals(v2.Pos, tolerance) &&
  32.         (ignoreNormals || v1.Normal.equals(v2.Normal, tolerance)) &&
  33.         v1.TCoords.equals(v2.TCoords, tolerance) &&
  34.         v1.TCoords2.equals(v2.TCoords2, tolerance) &&
  35.         (v1.Color == v2.Color);
  36. }
  37.  
  38. template<>
  39. inline bool vertsAreEqual<video::S3DVertexTangents>(const video::S3DVertexTangents& v1, const video::S3DVertexTangents& v2, f32 tolerance, bool ignoreNormals)
  40. {
  41.     return
  42.         v1.Pos.equals(v2.Pos, tolerance) &&
  43.         (ignoreNormals || v1.Normal.equals(v2.Normal, tolerance)) &&
  44.         v1.TCoords.equals(v2.TCoords) &&
  45.         v1.Tangent.equals(v2.Tangent, tolerance) &&
  46.         v1.Binormal.equals(v2.Binormal, tolerance) &&
  47.         (v1.Color == v2.Color);
  48. }
  49.  
  50. //TV: vertex type, TI: index type
  51. //TVList: the used type of dynamic array for the vertex output
  52. //TIList: the used type of dynamic array for the index output
  53. //the lists must provide size() and push_back()
  54. template <typename TV, typename TI, typename TVList, typename TIList>
  55. void createMeshBufWelded2T(const IMeshBuffer* const mbIn, TVList& vertsOut, TIList& indicesOut, f32 tolerance, bool ignoreNormals)
  56. {
  57.     //more buckets: faster but needs more memory
  58.     u32 avgVertsPerBucket = 4;  //smaller buckets = more buckets
  59.     const u32 absoluteMaxBuckets = 100000;
  60.     u32 bucketCount = core::min_(mbIn->getVertexCount() / avgVertsPerBucket, absoluteMaxBuckets);
  61.     core::array<u32>* buckets = new core::array<u32>[bucketCount];
  62.  
  63.     //prepare buckets, may increase speed?
  64.    
  65.     //for (u32 i=0; i<bucketCount; ++i)
  66.         //buckets[i] = core::array<u32>(avgVertsPerBucket);
  67.  
  68.     const TV* verticesIn = reinterpret_cast<const TV*>(mbIn->getVertices());
  69.     core::array<TI> redirects;
  70.     redirects.set_used(mbIn->getVertexCount());
  71.  
  72.  
  73.     //we fill the buckets using hashes
  74.     for (u32 i=0; i<mbIn->getVertexCount(); ++i)
  75.     {
  76.         u32 bucketNum = getBucketFromVector(verticesIn[i].Pos, tolerance, bucketCount);
  77.  
  78.         core::array<u32>* bucket = &buckets[bucketNum];
  79.  
  80.         bool found = false;
  81.  
  82.         for (u32 j=0; j<bucket->size(); ++j)
  83.         {
  84.             u32 vertexIndex = (*bucket)[j];
  85.             if (vertsAreEqual(verticesIn[i], verticesIn[vertexIndex], tolerance, ignoreNormals))
  86.             {
  87.                 found = true;
  88.                 redirects[i] = redirects[vertexIndex];
  89.             }
  90.         }
  91.  
  92.         //also check the previous and the next bucket
  93.  
  94.         bucket = (bucketNum == 0) ? &buckets[bucketCount-1] : &buckets[bucketNum-1];    //previous bucket
  95.         if (!found)
  96.             for (u32 j=0; j<bucket->size(); ++j)
  97.             {
  98.                 u32 vertexIndex = (*bucket)[j];
  99.                 if (vertsAreEqual(verticesIn[i], verticesIn[vertexIndex], tolerance, ignoreNormals))
  100.                 {
  101.                     found = true;
  102.                     redirects[i] = redirects[vertexIndex];
  103.                     break;
  104.                 }
  105.             }
  106.  
  107.         bucket = (bucketNum+1 >= bucketCount ) ? &buckets[0] : &buckets[bucketNum+1];   //next bucket
  108.         if (!found)
  109.             for (u32 j=0; j<bucket->size(); ++j)
  110.             {
  111.                 u32 vertexIndex = (*bucket)[j];
  112.                 if (vertsAreEqual(verticesIn[i], verticesIn[vertexIndex], tolerance, ignoreNormals))
  113.                 {
  114.                     found = true;
  115.                     redirects[i] = redirects[vertexIndex];
  116.                     break;
  117.                 }
  118.             }
  119.  
  120.         if (!found)
  121.         {
  122.             //add to bucket if not found
  123.             buckets[bucketNum].push_back(i);
  124.  
  125.             //also add to mesh and add to redirect list
  126.             vertsOut.push_back(verticesIn[i]);
  127.             redirects[i] = vertsOut.size() -1;
  128.         }
  129.     }
  130.  
  131.     //vertsOut is now final.
  132.    
  133.     //now, indices have to be updated
  134.     const TI* indicesIn = reinterpret_cast<const TI*>(mbIn->getIndices());
  135.     for (u32 i=0; i<mbIn->getIndexCount(); i+=3)
  136.     {
  137.         TI ia = indicesIn[i+0];
  138.         TI ib = indicesIn[i+1];
  139.         TI ic = indicesIn[i+2];
  140.         ia = redirects[ia];
  141.         ib = redirects[ib];
  142.         ic = redirects[ic];
  143.         //check for degenerate triangles:
  144.         if ((ia == ib) || (ib == ic) || (ic == ia) )
  145.             continue;
  146.        
  147.         indicesOut.push_back(ia);
  148.         indicesOut.push_back(ib);
  149.         indicesOut.push_back(ic);
  150.     }
  151.  
  152.     //now indicesOut are final
  153.     delete[] buckets;
  154. }
  155.  
  156. }
  157.  
  158. //! Creates a copy of a mesh, which will have identical vertices welded together
  159. // supports 32 bit and uses buckets for speedup
  160. IMesh* CMeshManipulator::createMeshWelded2(IMesh *mesh, f32 tolerance, bool ignoreNormals) const
  161. {
  162. #ifdef _MESH_WELDING_DEBUG
  163.     u32 time = os::Timer::getRealTime();
  164.     u32 vertCountInSum = 0;
  165.     u32 vertCountOutSum = 0;
  166. #endif
  167.     SMesh* clone = new SMesh();
  168.     clone->BoundingBox = mesh->getBoundingBox();
  169.  
  170.     for (u32 b=0; b<mesh->getMeshBufferCount(); ++b)
  171.     {
  172.         IMeshBuffer* mbIn = mesh->getMeshBuffer(b);
  173.         IMeshBuffer* mbOut = 0;
  174.  
  175.         if (mbIn->getIndexType() == video::EIT_16BIT)
  176.             switch (mbIn->getVertexType())
  177.             {
  178.             case video::EVT_STANDARD:
  179.             {
  180.                 SMeshBuffer* mbOutSpec;
  181.                 mbOut = mbOutSpec = new SMeshBuffer();
  182.                 createMeshBufWelded2T<video::S3DVertex, u16, core::array<video::S3DVertex>, core::array<u16>>(mbIn, mbOutSpec->Vertices, mbOutSpec->Indices, tolerance, ignoreNormals);
  183.                 break;
  184.             }
  185.             case video::EVT_2TCOORDS:
  186.             {
  187.                 SMeshBufferLightMap* mbOutSpec;
  188.                 mbOut = mbOutSpec = new SMeshBufferLightMap();
  189.                 createMeshBufWelded2T<video::S3DVertex2TCoords, u16, core::array<video::S3DVertex2TCoords>, core::array<u16>>(mbIn, mbOutSpec->Vertices, mbOutSpec->Indices, tolerance, ignoreNormals);
  190.                 break;
  191.             }
  192.             case video::EVT_TANGENTS:
  193.             {
  194.                 SMeshBufferTangents* mbOutSpec;
  195.                 mbOut = mbOutSpec = new SMeshBufferTangents();
  196.                 createMeshBufWelded2T<video::S3DVertexTangents, u16, core::array<video::S3DVertexTangents>, core::array<u16>>(mbIn, mbOutSpec->Vertices, mbOutSpec->Indices, tolerance, ignoreNormals);
  197.                 break;
  198.             }
  199.             default:
  200.                 os::Printer::log("Cannot create welded mesh, vertex type unsupported", ELL_ERROR);
  201.                 break;
  202.             }
  203.         else
  204.         {
  205.             CDynamicMeshBuffer* mbOutSpec;
  206.             mbOut = mbOutSpec = new CDynamicMeshBuffer(mbIn->getVertexType(), mbIn->getIndexType());
  207.             video::E_VERTEX_TYPE vType = mbIn->getVertexType();
  208.             video::E_INDEX_TYPE iType = mbIn->getIndexType();
  209.             switch(mbIn->getVertexType())
  210.             {
  211.             case video::EVT_STANDARD:
  212.                 createMeshBufWelded2T<video::S3DVertex, u32, IVertexBuffer, IIndexBuffer>(mbIn, mbOutSpec->getVertexBuffer(), mbOutSpec->getIndexBuffer(), tolerance, ignoreNormals);
  213.                 break;
  214.             case video::EVT_2TCOORDS:
  215.                 createMeshBufWelded2T<video::S3DVertex2TCoords, u32, IVertexBuffer, IIndexBuffer>(mbIn, mbOutSpec->getVertexBuffer(), mbOutSpec->getIndexBuffer(), tolerance, ignoreNormals);
  216.                 break;
  217.             case video::EVT_TANGENTS:
  218.                 createMeshBufWelded2T<video::S3DVertexTangents, u32, IVertexBuffer, IIndexBuffer>(mbIn, mbOutSpec->getVertexBuffer(), mbOutSpec->getIndexBuffer(), tolerance, ignoreNormals);
  219.                 break;
  220.             default:
  221.                 os::Printer::log("Cannot create welded mesh, vertex type unsupported", ELL_ERROR);
  222.                 break;
  223.             }
  224.         }
  225.  
  226.         if (mbOut == 0)
  227.             clone->addMeshBuffer(mbIn); //if it could not be welded, just return the old mb
  228.         else
  229.         {
  230.             mbOut->setBoundingBox(mbIn->getBoundingBox());
  231.             mbOut->getMaterial() = mbIn->getMaterial();
  232.             clone->addMeshBuffer(mbOut);       
  233.         }
  234.  
  235. #ifdef _MESH_WELDING_DEBUG
  236.         vertCountInSum += mbIn->getVertexCount();
  237.         vertCountOutSum += mbOut->getVertexCount();
  238. #endif
  239.     }
  240.  
  241. #ifdef _MESH_WELDING_DEBUG
  242.     time = os::Timer::getRealTime() - time;
  243.  
  244.     core::stringw info = "Mesh welded. Vertex Count before: ";
  245.     info += vertCountInSum;
  246.     info += " after: ";
  247.     info += vertCountOutSum;
  248.     info += " took ";
  249.     info += time;
  250.     info += "ms";
  251.     os::Printer::log(info.c_str(), ELL_DEBUG);
  252. #endif
  253.     return clone;
  254. }
Advertisement
Add Comment
Please, Sign In to add comment