void Atlas::extractCharts() { const uint faceCount = m_mesh->faceCount(); int first = 0; Array<uint> queue(faceCount); BitArray bitFlags(faceCount); bitFlags.clearAll(); for (uint f = 0; f < faceCount; f++) { if (bitFlags.bitAt(f) == false) { // Start new patch. Reset queue. first = 0; queue.clear(); queue.append(f); bitFlags.setBitAt(f); while (first != queue.count()) { const HalfEdge::Face * face = m_mesh->faceAt(queue[first]); // Visit face neighbors of queue[first] for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) { const HalfEdge::Edge * edge = it.current(); nvDebugCheck(edge->pair != NULL); if (!edge->isBoundary() && /*!edge->isSeam()*/ //!(edge->from()->tex() != edge->pair()->to()->tex() || edge->to()->tex() != edge->pair()->from()->tex())) !(edge->from() != edge->pair->to() || edge->to() != edge->pair->from())) // Preserve existing seams (not just texture seams). { const HalfEdge::Face * neighborFace = edge->pair->face; nvDebugCheck(neighborFace != NULL); if (bitFlags.bitAt(neighborFace->id) == false) { queue.append(neighborFace->id); bitFlags.setBitAt(neighborFace->id); } } } first++; } Chart * chart = new Chart(); chart->build(m_mesh, queue); m_chartArray.append(chart); } } }
void Atlas::computeCharts(const SegmentationSettings & settings) { AtlasBuilder builder(m_mesh); // Tweak these values: const float maxThreshold = 2; const uint growFaceCount = 32; const uint maxIterations = 4; builder.settings = settings; //builder.settings.proxyFitMetricWeight *= 0.75; // relax proxy fit weight during initial seed placement. //builder.settings.roundnessMetricWeight = 0; //builder.settings.straightnessMetricWeight = 0; // This seems a reasonable estimate. uint maxSeedCount = max(6U, m_mesh->faceCount()); // Create initial charts greedely. nvDebug("### Placing seeds\n"); builder.placeSeeds(maxThreshold, maxSeedCount); nvDebug("### Placed %d seeds (max = %d)\n", builder.chartCount(), maxSeedCount); builder.updateProxies(); builder.mergeCharts(); #if 1 nvDebug("### Relocating seeds\n"); builder.relocateSeeds(); nvDebug("### Reset charts\n"); builder.resetCharts(); builder.settings = settings; nvDebug("### Growing charts\n"); // Restart process growing charts in parallel. uint iteration = 0; while (true) { if (!builder.growCharts(maxThreshold, growFaceCount)) { nvDebug("### Can't grow anymore\n"); // If charts cannot grow more: fill holes, merge charts, relocate seeds and start new iteration. nvDebug("### Filling holes\n"); builder.fillHoles(maxThreshold); nvDebug("### Using %d charts now\n", builder.chartCount()); builder.updateProxies(); nvDebug("### Merging charts\n"); builder.mergeCharts(); nvDebug("### Using %d charts now\n", builder.chartCount()); nvDebug("### Reseeding\n"); if (!builder.relocateSeeds()) { nvDebug("### Cannot relocate seeds anymore\n"); // Done! break; } if (iteration == maxIterations) { nvDebug("### Reached iteration limit\n"); break; } iteration++; nvDebug("### Reset charts\n"); builder.resetCharts(); nvDebug("### Growing charts\n"); } }; #endif // Make sure no holes are left! nvDebugCheck(builder.facesLeft == 0); const uint chartCount = builder.chartArray.count(); for (uint i = 0; i < chartCount; i++) { Chart * chart = new Chart(); m_chartArray.append(chart); chart->build(m_mesh, builder.chartFaces(i)); } // Build face indices. m_faceChart.resize(m_mesh->faceCount()); m_faceIndex.resize(m_mesh->faceCount()); for (uint i = 0; i < chartCount; i++) { const Chart * chart = m_chartArray[i]; const uint faceCount = chart->faceCount(); for (uint f = 0; f < faceCount; f++) { uint idx = chart->faceAt(f); m_faceChart[idx] = i; m_faceIndex[idx] = f; } } // Build an exclusive prefix sum of the chart vertex counts. m_chartVertexCountPrefixSum.resize(chartCount); if (chartCount > 0) { m_chartVertexCountPrefixSum[0] = 0; for (uint i = 1; i < chartCount; i++) { const Chart * chart = m_chartArray[i-1]; m_chartVertexCountPrefixSum[i] = m_chartVertexCountPrefixSum[i-1] + chart->vertexCount(); } m_totalVertexCount = m_chartVertexCountPrefixSum[chartCount - 1] + m_chartArray[chartCount-1]->vertexCount(); } else { m_totalVertexCount = 0; } }