SpiecsEngine
 
Loading...
Searching...
No Matches
MeshProcessor.cpp
Go to the documentation of this file.
1/**
2* @file MeshProcessor.cpp.
3* @brief The MeshProcessor Class Implementation.
4* @author Spices.
5*/
6
7#include "Pchheader.h"
9#include "MeshPack.h"
10
11#include <src/meshoptimizer.h>
12#include <metis.h>
13#include <glm/gtx/norm.hpp>
14
15namespace Spices {
16
18 {
20
21 /**
22 * @brief Lod0
23 */
24 {
25 auto primVertices = meshPack->m_MeshResource.primitiveVertices.attributes;
26 meshPack->m_MeshResource.primitiveVertices.attributes = std::make_shared<std::vector<glm::uvec3>>();
27
28 /**
29 * @brief Pack to Points.
30 */
31 std::vector<glm::vec3> initPoints;
32 PackVertexToPoints(meshPack, *primVertices, initPoints);
33
34 /**
35 * @brief Calculate Bound Sphere.
36 */
37 SpicesShader::Sphere initBoundSphere = CalculateBoundSphere(initPoints);
38
39 /**
40 * @brief Create Lod0 meshlets.
41 */
42 AppendMeshlets(meshPack, 0, initBoundSphere, *primVertices);
43 }
44
45 uint32_t meshletStart = 0;
46 const uint32_t maxLod = 0;
47 for (uint32_t lod = 0; lod < maxLod; ++lod)
48 {
49 auto in = std::chrono::high_resolution_clock::now();
50
51 float tLod = lod / (float)maxLod;
52
53 /**
54 * @brief meshlets of last lod.
55 */
56 std::vector<Meshlet> meshlets = std::vector<Meshlet>(
57 meshPack->m_MeshResource.meshlets.attributes->begin() + meshletStart,
58 meshPack->m_MeshResource.meshlets.attributes->end()
59 );
60
61 if (meshlets.size() <= 1)
62 {
63 return;
64 }
65
66 const uint32_t nextStart = meshPack->m_MeshResource.meshlets.attributes->size();
67 meshletStart = nextStart;
68 auto groups = GroupMeshlets(meshPack, meshlets);
69
70 for (const auto& group : groups)
71 {
72 std::vector<glm::uvec3> groupPrimVertices;
73 auto ptr = meshPack->m_MeshResource.primitiveVertices.attributes;
74 for (const auto& meshletIndex : group.meshlets)
75 {
76 const auto& meshlet = meshlets[meshletIndex];
77
78 groupPrimVertices.insert(
79 groupPrimVertices.end(),
80 ptr->begin() + meshlet.primitiveOffset,
81 ptr->begin() + meshlet.primitiveOffset + meshlet.nPrimitives
82 );
83 }
84
85 /**
86 * @brief Build KDTree.
87 */
88 scl::kd_tree<6> kdTree;
89 BuildKDTree(meshPack, groupPrimVertices, kdTree);
90
91 /**
92 * @brief Pack to Points.
93 */
94 std::vector<glm::vec3> points;
95 PackVertexToPoints(meshPack, groupPrimVertices, points);
96
97 /**
98 * @brief Calculate Bound Sphere.
99 */
100 SpicesShader::Sphere clusterBoundSphere = CalculateBoundSphere(points);
101
102 float simplifyScale = meshopt_simplifyScale(&points[0].x, points.size(), sizeof(glm::vec3));
103 const float maxDistance = (tLod * 0.01f + (1 - tLod) * 0.001f) * simplifyScale;
104 const float maxUVDistance = tLod * 0.1f + (1 - tLod) * 0.001f;
105 MergeByDistance(meshPack, groupPrimVertices, kdTree, maxDistance, maxUVDistance);
106
107 /**
108 * @brief Pack Sparse Inputs.
109 */
110 std::vector<glm::vec3> packPoints;
111 std::vector<glm::uvec3> packPrimPoints;
112 std::unordered_map<uint32_t, uint32_t> primVerticesMapReverse;
113 PackPrimVerticesFromSparseInputs(meshPack, groupPrimVertices, packPoints, packPrimPoints, primVerticesMapReverse);
114
115 /**
116 * @brief Simplify meshlets group primPoints.
117 */
118 const float threshold = 0.5f;
119 size_t targetCount = packPrimPoints.size() * threshold * 3;
120 float targetError = 0.1f * tLod + 0.01f * (1 - tLod);
121 uint32_t options = meshopt_SimplifyLockBorder;
122
123 std::vector<glm::uvec3> simplifiedPrimPoints(packPrimPoints.size());
124 float simplificationError = 0.0f;
125
126 size_t simplifiedCount = meshopt_simplify(
127 &simplifiedPrimPoints[0].x ,
128 &packPrimPoints[0].x ,
129 packPrimPoints.size() * 3 ,
130 &packPoints[0].x ,
131 packPoints.size() ,
132 sizeof(glm::vec3) ,
133 targetCount ,
134 targetError ,
135 options ,
136 &simplificationError
137 );
138 simplifiedPrimPoints.resize(simplifiedCount / 3);
139
140 /**
141 * @brief Simplify succeed: merge result to meshlets.
142 */
143 std::vector<glm::uvec3> primVerticesBuffer;
144 UnPackPrimVerticesToSparseInputs(primVerticesBuffer, primVerticesMapReverse, simplifiedPrimPoints);
145
146 AppendMeshlets(meshPack, lod + 1, clusterBoundSphere, primVerticesBuffer);
147 }
148
149 auto out = std::chrono::high_resolution_clock::now();
150 std::cout << " Lod Cost: " << std::chrono::duration_cast<std::chrono::milliseconds>(out - in).count() << " " << meshlets.size() << std::endl;
151 }
152 }
153
154 void MeshProcessor::AppendMeshlets(
155 MeshPack* meshPack ,
156 uint32_t lod ,
157 const SpicesShader::Sphere& clusterBoundSphere ,
158 const std::vector<glm::uvec3>& primVertices
159 )
160 {
162
163 /**
164 * @brief normal cone weight set 0.5f;
165 * Get Const variable.
166 */
167 const float coneWeight = 0.5f;
168 const uint32_t primLocationsOffset = meshPack->m_MeshResource.primitiveLocations.attributes->size();
169 const uint32_t primVerticesOffset = meshPack->m_MeshResource.primitiveVertices.attributes->size();
170 const uint32_t meshletsOffset = meshPack->m_MeshResource.meshlets.attributes->size();
171
172 /**
173 * @brief Init meshopt variable.
174 */
175 size_t max_meshlets = meshopt_buildMeshletsBound(primVertices.size() * 3, SpicesShader::MESHLET_NVERTICES, SpicesShader::MESHLET_NPRIMITIVES);
176 std::vector<meshopt_Meshlet> meshoptlets(max_meshlets);
177 std::vector<unsigned int> meshlet_vertices(max_meshlets * SpicesShader::MESHLET_NVERTICES);
178 std::vector<unsigned char> meshlet_triangles(max_meshlets * SpicesShader::MESHLET_NPRIMITIVES * 3);
179
180 /**
181 * @brief Pack Sparse Inputs.
182 */
183 std::vector<glm::vec3> packPoints;
184 std::vector<glm::uvec3> packPrimPoints;
185 std::unordered_map<uint32_t, uint32_t> primVerticesMapReverse;
186 PackPrimVerticesFromSparseInputs(meshPack, primVertices, packPoints, packPrimPoints, primVerticesMapReverse);
187
188 /**
189 * @brief Build Meshlets.
190 */
191 size_t nMeshlet = meshopt_buildMeshlets(
192 meshoptlets.data() ,
193 meshlet_vertices.data() ,
194 meshlet_triangles.data() ,
195 &packPrimPoints[0].x ,
196 packPrimPoints.size() * 3 ,
197 &packPoints[0].x ,
198 packPoints.size() ,
199 sizeof(glm::vec3) ,
200 SpicesShader::MESHLET_NVERTICES ,
201 SpicesShader::MESHLET_NPRIMITIVES ,
202 coneWeight
203 );
204
205 /**
206 * @brief Adjust meshopt variable.
207 */
208 const meshopt_Meshlet& last = meshoptlets[nMeshlet - 1];
209 meshoptlets .resize(nMeshlet);
210 meshlet_vertices .resize(last.vertex_offset + last.vertex_count);
211 meshlet_triangles.resize(last.triangle_offset + (last.triangle_count * 3 + 3) & ~3);
212
213 /**
214 * @brief Optimize meshlets and compute meshlet bound and cone.
215 */
216 uint32_t nPrimitives = 0;
217 for (size_t i = 0; i < nMeshlet; ++i)
218 {
219 meshopt_optimizeMeshlet(
220 &meshlet_vertices[meshoptlets[i].vertex_offset] ,
221 &meshlet_triangles[meshoptlets[i].triangle_offset] ,
222 meshoptlets[i].triangle_count, meshoptlets[i].vertex_count
223 );
224
225 const meshopt_Meshlet& m = meshoptlets[i];
226 meshopt_Bounds bounds = meshopt_computeMeshletBounds(
227 &meshlet_vertices[m.vertex_offset] ,
228 &meshlet_triangles[m.triangle_offset] ,
229 m.triangle_count ,
230 &packPoints[0].x,
231 packPoints.size(),
232 sizeof(glm::vec3)
233 );
234
235 Meshlet meshlet;
236 meshlet.FromMeshopt(meshoptlets[i], bounds);
237 meshlet.primitiveOffset = nPrimitives;
238
239 meshlet.vertexOffset += primLocationsOffset;
240 meshlet.primitiveOffset += primVerticesOffset;
241 meshlet.lod = lod;
242
243 meshlet.clusterBoundSphere = clusterBoundSphere;
244
245 meshPack->m_MeshResource.meshlets.attributes->push_back(std::move(meshlet));
246
247 nPrimitives += m.triangle_count;
248 }
249
250 /**
251 * @brief Layout map for primpoints.
252 */
253 std::unordered_map<glm::uvec3, uint32_t> inPrimPointsLayoutMap;
254 auto& vertices = *meshPack->m_MeshResource.vertices.attributes;
255 for (auto& primVertex : primVertices)
256 {
257 inPrimPointsLayoutMap[{ vertices[primVertex.x].x, vertices[primVertex.y].x, vertices[primVertex.z].x }] = inPrimPointsLayoutMap.size();
258 }
259
260 /**
261 * @brief Fill in data back to meshpack variable.
262 */
263 const Meshlet& lastm = (*meshPack->m_MeshResource.meshlets.attributes)[meshletsOffset + nMeshlet - 1];
264 meshPack->m_MeshResource.primitivePoints .attributes->resize(lastm.primitiveOffset + lastm.nPrimitives);
265 meshPack->m_MeshResource.primitiveVertices .attributes->resize(lastm.primitiveOffset + lastm.nPrimitives);
266 meshPack->m_MeshResource.primitiveLocations .attributes->resize(lastm.primitiveOffset + lastm.nPrimitives);
267
268 for (uint32_t i = 0; i < nMeshlet; i++)
269 {
270 const meshopt_Meshlet& m = meshoptlets[i];
271 const Meshlet& ml = (*meshPack->m_MeshResource.meshlets.attributes)[meshletsOffset + i];
272
273 for (uint32_t j = 0; j < m.triangle_count; j++)
274 {
275 uint32_t a = (uint32_t)meshlet_triangles[m.triangle_offset + 3 * j + 0] + m.vertex_offset;
276 uint32_t b = (uint32_t)meshlet_triangles[m.triangle_offset + 3 * j + 1] + m.vertex_offset;
277 uint32_t c = (uint32_t)meshlet_triangles[m.triangle_offset + 3 * j + 2] + m.vertex_offset;
278
279 uint32_t& x = vertices[primVerticesMapReverse[meshlet_vertices[a]]].x;
280 uint32_t& y = vertices[primVerticesMapReverse[meshlet_vertices[b]]].x;
281 uint32_t& z = vertices[primVerticesMapReverse[meshlet_vertices[c]]].x;
282
283 (*meshPack->m_MeshResource.primitivePoints.attributes)[ml.primitiveOffset + j] = { x, y, z };
284
285 (*meshPack->m_MeshResource.primitiveLocations.attributes)[ml.primitiveOffset + j].x = a + primLocationsOffset;
286 (*meshPack->m_MeshResource.primitiveLocations.attributes)[ml.primitiveOffset + j].y = b + primLocationsOffset;
287 (*meshPack->m_MeshResource.primitiveLocations.attributes)[ml.primitiveOffset + j].z = c + primLocationsOffset;
288
289 (*meshPack->m_MeshResource.primitiveVertices.attributes)[ml.primitiveOffset + j] = primVertices[inPrimPointsLayoutMap[{ x, y, z }]];
290 }
291 }
292
293 /**
294 * @brief Fill in Lod data.
295 */
296 uint32_t nLods = meshPack->m_MeshResource.lods.attributes->size();
297
298 if (nLods == lod + 1)
299 {
300 Lod& lodRef = (*meshPack->m_MeshResource.lods.attributes)[lod];
301
302 lodRef.nPrimitives += lastm.primitiveOffset + lastm.nPrimitives - primVerticesOffset;
303 lodRef.nMeshlets += nMeshlet;
304 }
305 else
306 {
307 Lod lodData;
308 lodData.primVertexOffset = primVerticesOffset;
309 lodData.nPrimitives = lastm.primitiveOffset + lastm.nPrimitives - primVerticesOffset;
310 lodData.nMeshlets = nMeshlet;
311 lodData.meshletOffset = meshletsOffset;
312
313 meshPack->m_MeshResource.lods.attributes->push_back(std::move(lodData));
314 }
315 }
316
317 std::vector<MeshletGroup> MeshProcessor::GroupMeshlets(MeshPack* meshPack, std::vector<Meshlet>& meshlets)
318 {
320
321 /**
322 * @brief Return one group with all meshlets.
323 */
324 auto groupWithMeshlets = [&]()
325 {
326 MeshletGroup group;
327 for (int i = 0; i < meshlets.size(); ++i)
328 {
329 group.meshlets.push_back(i);
330 }
331 return std::vector{ group };
332 };
333
334 /**
335 * @brief Return if less than 8 meshlets.
336 */
337 if (meshlets.size() < 8)
338 {
339 return groupWithMeshlets();
340 }
341
342 std::unordered_map<Edge, std::set<size_t>> edges2Meshlets;
343 std::unordered_map<size_t, std::vector<Edge>> meshlets2Edges;
344
345 for (size_t meshletIndex = 0; meshletIndex < meshlets.size(); meshletIndex++)
346 {
347 const auto& meshlet = meshlets[meshletIndex];
348
349 for (size_t triangleIndex = 0; triangleIndex < meshlet.nPrimitives; triangleIndex++)
350 {
351 const glm::uvec3& primPts = (*meshPack->m_MeshResource.primitivePoints.attributes)[meshlet.primitiveOffset + triangleIndex];
352
353 Edge edge0{ primPts.x , primPts.y };
354 Edge edge1{ primPts.y , primPts.z };
355 Edge edge2{ primPts.z , primPts.x };
356
357 edges2Meshlets[edge0].insert(meshletIndex);
358 edges2Meshlets[edge1].insert(meshletIndex);
359 edges2Meshlets[edge2].insert(meshletIndex);
360
361 meshlets2Edges[meshletIndex].push_back(edge0);
362 meshlets2Edges[meshletIndex].push_back(edge1);
363 meshlets2Edges[meshletIndex].push_back(edge2);
364 }
365 }
366
367 /*
368 * @brief remove internal edge.
369 */
370 for (auto first = edges2Meshlets.begin(), last = edges2Meshlets.end(); first != last;)
371 {
372 if ((*first).second.size() <= 1)
373 {
374 first = edges2Meshlets.erase(first);
375 }
376 else
377 {
378 ++first;
379 }
380 }
381
382 /*
383 * @brief return if no connected edge.
384 */
385 if (edges2Meshlets.empty())
386 {
387 return groupWithMeshlets();
388 }
389
390 idx_t vertexCount = meshlets.size();
391 idx_t ncon = 1;
392 idx_t nparts = meshlets.size() / 4;
393 assert(nparts > 1);
394
395 idx_t options[METIS_NOPTIONS];
396 METIS_SetDefaultOptions(options);
397
398 options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
399 options[METIS_OPTION_CCORDER] = 1;
400
401 std::vector<idx_t> partition;
402 partition.resize(vertexCount);
403
404 /**
405 * @brief xadj.
406 */
407 std::vector<idx_t> xadjacency;
408 xadjacency.reserve(vertexCount + 1);
409
410 /**
411 * @brief adjncy.
412 * Stores Meshlets Index.
413 */
414 std::vector<idx_t> edgeAdjacency;
415
416 /**
417 * @brief Connect meshlets Count of each meshlet.
418 */
419 std::vector<idx_t> edgeWeights;
420
421 for (size_t meshletIndex = 0; meshletIndex < meshlets.size(); meshletIndex++)
422 {
423 size_t startIndexInEdgeAdjacency = edgeAdjacency.size();
424 for (const auto& edge : meshlets2Edges[meshletIndex])
425 {
426 /**
427 * @brief Skip if edge is internal edge.
428 */
429 auto connectionsIter = edges2Meshlets.find(edge);
430 if (connectionsIter == edges2Meshlets.end())
431 {
432 continue;
433 }
434
435 /**
436 * @brief Iter connected edge's meshlets.
437 */
438 const auto& connections = connectionsIter->second;
439 for (const auto& connectedMeshlet : connections)
440 {
441 /**
442 * @brief Get a connect other meshlet.
443 */
444 if (connectedMeshlet != meshletIndex)
445 {
446 auto existingEdgeIter = std::find(edgeAdjacency.begin() + startIndexInEdgeAdjacency, edgeAdjacency.end(), connectedMeshlet);
447 if (existingEdgeIter == edgeAdjacency.end())
448 {
449 edgeAdjacency.emplace_back(connectedMeshlet);
450 edgeWeights.emplace_back(1);
451 }
452 else
453 {
454 std::ptrdiff_t d = std::distance(edgeAdjacency.begin(), existingEdgeIter);
455 assert(d >= 0 && d < edgeWeights.size());
456 edgeWeights[d]++;
457 }
458 }
459 }
460 }
461 xadjacency.push_back(startIndexInEdgeAdjacency);
462 }
463 xadjacency.push_back(edgeAdjacency.size());
464
465 assert(xadjacency.size() == meshlets.size() + 1);
466 assert(edgeAdjacency.size() == edgeWeights.size());
467
468 /**
469 * @brief Split Meshlets to Part.
470 */
471 idx_t edgeCut;
472 int result = METIS_PartGraphKway(
473 &vertexCount,
474 &ncon,
475 xadjacency.data(),
476 edgeAdjacency.data(),
477 nullptr, /* vertex weights */
478 nullptr, /* vertex size */
479 edgeWeights.data(),
480 &nparts,
481 nullptr,
482 nullptr,
483 options,
484 &edgeCut,
485 partition.data()
486 );
487
488 assert(result == METIS_OK);
489
490 /**
491 * @brief Return groups.
492 */
493 std::vector<MeshletGroup> groups;
494 groups.resize(nparts);
495 for (size_t i = 0; i < meshlets.size(); i++)
496 {
497 idx_t partitionNumber = partition[i];
498 groups[partitionNumber].meshlets.push_back(i);
499 }
500
501 return groups;
502 }
503
504 bool MeshProcessor::MergeByDistance(
505 MeshPack* meshPack ,
506 std::vector<glm::uvec3>& primVertices ,
507 scl::kd_tree<6>& kdTree ,
508 float maxDistance ,
509 float maxUVDistance
510 )
511 {
513
514 auto& positions = *meshPack->m_MeshResource.positions.attributes;
515 auto& texCoords = *meshPack->m_MeshResource.texCoords.attributes;
516 auto& vertices = *meshPack->m_MeshResource.vertices .attributes;
517
518 /**
519 * @brief Get boundary points.
520 */
521 std::unordered_map<uint32_t, bool> boundaryPoints;
522 std::unordered_map<uint32_t, bool> stableBoundaryPoints;
523 std::unordered_map<uint32_t, EdgePoint> boundaryEdgePoints;
524 std::unordered_map<uint32_t, std::unordered_map<uint32_t, bool>> pointConnect;
525 FindBoundaryPoints(
526 meshPack ,
527 primVertices ,
528 boundaryPoints ,
529 stableBoundaryPoints ,
530 boundaryEdgePoints ,
531 pointConnect
532 );
533
534 std::unordered_map<uint32_t, uint32_t> primVerticesMap;
535 auto addToMap = [&](const uint32_t& k, const uint32_t& v) {
536 if (primVerticesMap.find(k) == primVerticesMap.end())
537 {
538 primVerticesMap[k] = v;
539 }
540 };
541
542 /**
543 * @brief Find merged vertices.
544 */
545 for (int i = 0; i < primVertices.size(); i++)
546 {
547 auto& primVertex = primVertices[i];
548
549 std::array<uint32_t, 3> primVertexArray = { primVertex.x, primVertex.y, primVertex.z };
550
551 for (int j = 0; j < 3; j++)
552 {
553 const glm::uvec4& vertex = vertices[primVertexArray[j]];
554
555 /**
556 * @brief Find near vertex.
557 */
558 scl::kd_tree<6>::item item = {
559 positions[vertex.x].x,
560 positions[vertex.x].y,
561 positions[vertex.x].z,
562 texCoords[vertex.w].x,
563 texCoords[vertex.w].y,
564 (float)primVertexArray[j]
565 };
566 auto rangeVts = kdTree.range_search(item, {
567 maxDistance ,
568 maxDistance ,
569 maxDistance ,
570 maxUVDistance ,
571 maxUVDistance ,
572 (float)UINT32_MAX
573 });
574
575 /**
576 * @brief Only allow near merge.
577 */
578 std::vector<scl::kd_tree<6>::item> nearVts;
579 for (auto& vt : rangeVts)
580 {
581 uint32_t pt = vertices[(uint32_t)vt[5]].x;
582
583 if (pointConnect[vertex.x].find(pt) != pointConnect[vertex.x].end())
584 {
585 nearVts.push_back(vt);
586 }
587 }
588
589 /**
590 * @brief Can merge if this vertex is in stableboundary.
591 * @attention This situation not allowed merge to line and point here.
592 */
593 if (stableBoundaryPoints.find(vertex.x) != stableBoundaryPoints.end())
594 {
595 std::unordered_map<uint32_t, bool> mergedVertex;
596
597 for (auto& rangeVt : nearVts)
598 {
599 uint32_t primVertexIndex = (uint32_t)rangeVt[5];
600 mergedVertex[vertices[primVertexIndex].x] = true;
601 }
602
603 bool canBeTriangle = true;
604 for (int k = 0; k < primVertexArray.size(); k++)
605 {
606 if (mergedVertex.find(vertices[primVertexArray[k]].x) != mergedVertex.end())
607 {
608 canBeTriangle = false;
609 break;
610 }
611 }
612
613 if(canBeTriangle)
614 {
615 for (auto& rangeVt : nearVts)
616 {
617 uint32_t primVertexIndex = (uint32_t)rangeVt[5];
618 addToMap(primVertexIndex, primVertexArray[j]);
619 }
620 }
621 else
622 {
623 addToMap(primVertexArray[j], primVertexArray[j]);
624 }
625 }
626
627 /**
628 * @brief Can merge when target is not in stableboundary if this vertex is in boundary.
629 * @attention boundarypoint can only be merged when connected.
630 */
631 else if (boundaryPoints.find(vertex.x) != boundaryPoints.end())
632 {
633 for (auto& rangeVt : nearVts)
634 {
635 uint32_t primVertexIndex = (uint32_t)rangeVt[5];
636 uint32_t pt = vertices[primVertexIndex].x;
637
638 if (boundaryPoints.find(pt) == boundaryPoints.end())
639 {
640 addToMap(primVertexIndex, primVertexArray[j]);
641 }
642 else if (stableBoundaryPoints.find(pt) == stableBoundaryPoints.end())
643 {
644 if (boundaryEdgePoints[vertex.x].next == pt ||
645 boundaryEdgePoints[vertex.x].prev == pt ||
646 boundaryEdgePoints[vertex.x].self == pt
647 )
648 {
649 addToMap(primVertexIndex, primVertexArray[j]);
650 }
651 }
652 }
653 }
654
655 /**
656 * @brief Can merge when target is not in boundary if this vertex is not in boundary.
657 */
658 else
659 {
660 for (auto& rangeVt : nearVts)
661 {
662 uint32_t primVertexIndex = (uint32_t)rangeVt[5];
663 uint32_t pt = vertices[primVertexIndex].x;
664
665 if (boundaryPoints.find(pt) == boundaryPoints.end())
666 {
667 addToMap(primVertexIndex, primVertexArray[j]);
668 }
669 }
670 }
671 }
672 }
673
674 /**
675 * @brief Copy primVertices and merge.
676 */
677 std::vector<glm::uvec3> tempPrimVertices = primVertices;
678 for (int i = 0; i < primVertices.size(); i++)
679 {
680 auto primVertex = primVertices[i];
681
682 if(primVerticesMap.find(primVertex.x) != primVerticesMap.end()) tempPrimVertices[i].x = primVerticesMap[primVertex.x];
683 if(primVerticesMap.find(primVertex.y) != primVerticesMap.end()) tempPrimVertices[i].y = primVerticesMap[primVertex.y];
684 if(primVerticesMap.find(primVertex.z) != primVerticesMap.end()) tempPrimVertices[i].z = primVerticesMap[primVertex.z];
685 }
686
687 /**
688 * @brief Remove lines and poins merged from triangles;
689 */
690 primVertices.clear();
691 for (auto& primVertex : tempPrimVertices)
692 {
693 std::set<uint32_t> set;
694
695 set.insert(primVertex.x);
696 set.insert(primVertex.y);
697 set.insert(primVertex.z);
698
699 if (set.size() < 3) continue;
700
701 primVertices.push_back(primVertex);
702 }
703
704 return true;
705 }
706
707 bool MeshProcessor::PackVertexToPoints(
708 MeshPack* meshPack ,
709 const std::vector<glm::uvec3>& primVertices ,
710 std::vector<glm::vec3>& points
711 )
712 {
714
715 std::unordered_map<uint32_t, bool> pointsMap;
716
717 auto& positions = *meshPack->m_MeshResource.positions.attributes;
718 auto& vertices = *meshPack->m_MeshResource.vertices .attributes;
719 for (auto& primVertex : primVertices)
720 {
721 const glm::uvec4& vertex0 = vertices[primVertex.x];
722 const glm::uvec4& vertex1 = vertices[primVertex.y];
723 const glm::uvec4& vertex2 = vertices[primVertex.z];
724
725 pointsMap[vertex0.x] = true;
726 pointsMap[vertex1.x] = true;
727 pointsMap[vertex2.x] = true;
728 }
729
730 points.resize(pointsMap.size());
731 uint32_t i = 0;
732 for (auto& [pt, ignore] : pointsMap)
733 {
734 points[i] = positions[pt];
735 ++i;
736 }
737
738 return true;
739 }
740
741 SpicesShader::Sphere MeshProcessor::CalculateBoundSphere(const std::vector<glm::vec3>& points)
742 {
744
745 SpicesShader::Sphere sphere;
746
747 glm::vec3 min = { 1E11, 1E11, 1E11 };
748 glm::vec3 max = { -1E11, -1E11, -1E11 };
749
750 for (const auto& point : points)
751 {
752 min = glm::min(min, point);
753 max = glm::max(max, point);
754 }
755
756 glm::vec3 bound = max - min;
757 sphere.c = 0.5f * (max + min);
758 sphere.r = 0.5f * glm::sqrt(bound.x * bound.x + bound.y * bound.y + bound.z * bound.z);
759
760 return sphere;
761 }
762
763 bool MeshProcessor::BuildKDTree(
764 MeshPack* meshPack ,
765 const std::vector<glm::uvec3>& primVertices ,
766 scl::kd_tree<6>& kdTree
767 )
768 {
770
771 std::unordered_map<uint32_t, bool> primVerticesMap;
772 for (auto& primVertex : primVertices)
773 {
774 primVerticesMap[primVertex.x] = true;
775 primVerticesMap[primVertex.y] = true;
776 primVerticesMap[primVertex.z] = true;
777 }
778
779 auto& positions = *meshPack->m_MeshResource.positions.attributes;
780 auto& texCoords = *meshPack->m_MeshResource.texCoords.attributes;
781 auto& vertices = *meshPack->m_MeshResource.vertices .attributes;
782
783 std::vector<scl::kd_tree<6>::item> items;
784 items.resize(primVerticesMap.size());
785
786 uint32_t i = 0;
787 for (auto& [primVertex, ignore] : primVerticesMap)
788 {
789 glm::uvec4 vertex = vertices[primVertex];
790
791 items[i] =
792 {
793 positions[vertex.x].x,
794 positions[vertex.x].y,
795 positions[vertex.x].z,
796 texCoords[vertex.w].x,
797 texCoords[vertex.w].y,
798 (float)primVertex
799 };
800
801 ++i;
802 }
803
804 kdTree.insert(items);
805
806 return true;
807 }
808
809 bool MeshProcessor::FindBoundaryPoints(
810 MeshPack* meshPack ,
811 const std::vector<glm::uvec3>& primVertices ,
812 std::unordered_map<uint32_t, bool>& boundaryPoints ,
813 std::unordered_map<uint32_t, bool>& stableBoundaryPoints ,
814 std::unordered_map<uint32_t, EdgePoint>& boundaryEdgePoints ,
815 std::unordered_map<uint32_t, std::unordered_map<uint32_t, bool>>& pointConnect
816 )
817 {
819
820 /**
821 * @brief Get edge connected primitive.
822 */
823 std::unordered_map<Edge, uint32_t> edgesConnects;
824 auto& vertices = *meshPack->m_MeshResource.vertices.attributes;
825 for (uint32_t triangleIndex = 0; triangleIndex < primVertices.size(); triangleIndex++)
826 {
827 auto& primVertex = primVertices[triangleIndex];
828 std::array<uint32_t, 3> primVertexArray = { primVertex.x, primVertex.y, primVertex.z };
829
830 for (uint32_t i = 0; i < 3; i++)
831 {
832 Edge edge;
833 edge.first = vertices[primVertexArray[i]].x;
834 edge.second = vertices[primVertexArray[(i + 1) % 3]].x;
835
836 if (edgesConnects.find(edge) == edgesConnects.end())
837 {
838 edgesConnects[edge] = 1;
839 }
840 else
841 {
842 edgesConnects[edge]++;
843 }
844 }
845 }
846
847 /**
848 * @brief Get pointconnect.
849 */
850 for (auto& [edge, connects] : edgesConnects)
851 {
852 pointConnect[edge.first][edge.second] = true;
853 pointConnect[edge.first][edge.first] = true;
854
855 pointConnect[edge.second][edge.first] = true;
856 pointConnect[edge.second][edge.second] = true;
857 }
858
859 /*
860 * @brief remove internal edge.
861 */
862 for (auto first = edgesConnects.begin(), last = edgesConnects.end(); first != last;)
863 {
864 if ((*first).second != 1)
865 {
866 first = edgesConnects.erase(first);
867 }
868 else
869 {
870 ++first;
871 }
872 }
873
874 for (auto& [edge, connects] : edgesConnects)
875 {
876 boundaryPoints[edge.first] = true;
877 boundaryPoints[edge.second] = true;
878 }
879
880 /**
881 * @brief get bound edge points.
882 */
883 for (auto& [edge, connects] : edgesConnects)
884 {
885 if (boundaryEdgePoints.find(edge.first) == boundaryEdgePoints.end())
886 {
887 boundaryEdgePoints[edge.first].self = edge.first;
888 boundaryEdgePoints[edge.first].next = edge.second;
889 }
890 else
891 {
892 boundaryEdgePoints[edge.first].prev = edge.second;
893 }
894
895 if (boundaryEdgePoints.find(edge.second) == boundaryEdgePoints.end())
896 {
897 boundaryEdgePoints[edge.second].self = edge.second;
898 boundaryEdgePoints[edge.second].next = edge.first;
899 }
900 else
901 {
902 boundaryEdgePoints[edge.second].prev = edge.first;
903 }
904 }
905
906 /**
907 * @brief only stable points with high curvature.
908 */
909 auto& position = *meshPack->m_MeshResource.positions.attributes;
910 for (auto& pair : boundaryEdgePoints)
911 {
912 if (!pair.second.valid()) continue;
913
914 glm::vec3 l = glm::normalize(position[pair.second.next] - position[pair.first]);
915 glm::vec3 r = glm::normalize(position[pair.second.prev] - position[pair.first]);
916
917 if (glm::dot(l, r) > -0.98f)
918 {
919 stableBoundaryPoints[pair.second.self] = true;
920
921#define ExpandStablePoint
923
924 stableBoundaryPoints[pair.second.next] = true;
925 stableBoundaryPoints[pair.second.prev] = true;
926
927#endif
928
929 }
930 }
931
932 return true;
933 }
934
935 bool MeshProcessor::PackPrimVerticesFromSparseInputs(
936 MeshPack* meshPack ,
937 const std::vector<glm::uvec3> primVertices ,
938 std::vector<glm::vec3>& packPoints ,
939 std::vector<glm::uvec3>& packPrimPoints ,
940 std::unordered_map<uint32_t, uint32_t>& primVerticesMapReverse
941 )
942 {
944
945 /**
946 * @brief Merge Vertex.
947 */
948 std::unordered_map<uint32_t, uint32_t> primVerticesMap; // old: primVertexIndex , new: primPointIndex
949 for (auto& primVertex : primVertices)
950 {
951 if (primVerticesMap.find(primVertex.x) == primVerticesMap.end()) primVerticesMap[primVertex.x] = primVerticesMap.size();
952 if (primVerticesMap.find(primVertex.y) == primVerticesMap.end()) primVerticesMap[primVertex.y] = primVerticesMap.size();
953 if (primVerticesMap.find(primVertex.z) == primVerticesMap.end()) primVerticesMap[primVertex.z] = primVerticesMap.size();
954 }
955
956 /**
957 * @brief Flatten Vertex Position.
958 */
959 packPoints.resize(primVerticesMap.size());
960 auto& vertices = *meshPack->m_MeshResource.vertices.attributes;
961 for (auto& pair : primVerticesMap)
962 {
963 packPoints[pair.second] = (*meshPack->m_MeshResource.positions.attributes)[vertices[pair.first].x];
964 primVerticesMapReverse[pair.second] = pair.first;
965 }
966
967 packPrimPoints.resize(primVertices.size());
968 for (int i = 0; i < primVertices.size(); i++)
969 {
970 glm::uvec3 primVertex = primVertices[i];
971
972 packPrimPoints[i].x = primVerticesMap[primVertex.x];
973 packPrimPoints[i].y = primVerticesMap[primVertex.y];
974 packPrimPoints[i].z = primVerticesMap[primVertex.z];
975 }
976
977 return true;
978 }
979
980 bool MeshProcessor::UnPackPrimVerticesToSparseInputs(
981 std::vector<glm::uvec3>& primVertices ,
982 std::unordered_map<uint32_t, uint32_t>& primVerticesMapReverse ,
983 const std::vector<glm::uvec3>& packPrimPoints
984 )
985 {
987
988 primVertices.resize(packPrimPoints.size());
989 for (int i = 0; i < packPrimPoints.size(); i++)
990 {
991 uint32_t x = primVerticesMapReverse[packPrimPoints[i].x];
992 uint32_t y = primVerticesMapReverse[packPrimPoints[i].y];
993 uint32_t z = primVerticesMapReverse[packPrimPoints[i].z];
994
995 primVertices[i] = glm::uvec3(x, y, z);
996 }
997
998 return true;
999 }
1000}
#define ExpandStablePoint
#define SPICES_PROFILE_ZONE
MeshPack Class. This class defines some basic behaves and variables. This class need to be inherited ...
Definition MeshPack.h:156
static void GenerateMeshLodClusterHierarchy(MeshPack *meshPack)
Generate Mesh Lod Resources.
Class for provide functions of process Meshpack.
The kd_tree with K dimensions container Class. K the number of dimensions. Every node in the tree is ...
Definition KDTree.h:27
uint32_t meshletOffset
Definition MeshPack.h:31
uint32_t nPrimitives
Definition MeshPack.h:30
uint32_t primVertexOffset
Definition MeshPack.h:29
Lod Data.
Definition MeshPack.h:28
MeshletGroup for simplify.
Meshlet Class. This class defines what Meshlet data.
Definition Vertex.h:58