2
0

TriangleSplitterBinning.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/TriangleSplitter/TriangleSplitterBinning.h>
  5. JPH_NAMESPACE_BEGIN
  6. TriangleSplitterBinning::TriangleSplitterBinning(const VertexList &inVertices, const IndexedTriangleList &inTriangles, uint inMinNumBins, uint inMaxNumBins, uint inNumTrianglesPerBin) :
  7. TriangleSplitter(inVertices, inTriangles),
  8. mMinNumBins(inMinNumBins),
  9. mMaxNumBins(inMaxNumBins),
  10. mNumTrianglesPerBin(inNumTrianglesPerBin)
  11. {
  12. mBins.resize(mMaxNumBins);
  13. }
  14. bool TriangleSplitterBinning::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
  15. {
  16. // Calculate bounds for this range
  17. AABox centroid_bounds;
  18. for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
  19. centroid_bounds.Encapsulate(Vec3(mCentroids[mSortedTriangleIdx[t]]));
  20. float best_cp = FLT_MAX;
  21. uint best_dim = 0xffffffff;
  22. float best_split = 0;
  23. // Bin in all dimensions
  24. uint num_bins = Clamp(inTriangles.Count() / mNumTrianglesPerBin, mMinNumBins, mMaxNumBins);
  25. for (uint dim = 0; dim < 3; ++dim)
  26. {
  27. float bounds_min = centroid_bounds.mMin[dim];
  28. float bounds_size = centroid_bounds.mMax[dim] - bounds_min;
  29. // Skip axis if too small
  30. if (bounds_size < 1.0e-5f)
  31. continue;
  32. // Initialize bins
  33. for (uint b = 0; b < num_bins; ++b)
  34. {
  35. Bin &bin = mBins[b];
  36. bin.mBounds.SetEmpty();
  37. bin.mMinCentroid = bounds_min + bounds_size * (b + 1) / num_bins;
  38. bin.mNumTriangles = 0;
  39. }
  40. // Bin all triangles
  41. for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
  42. {
  43. float centroid_pos = mCentroids[mSortedTriangleIdx[t]][dim];
  44. // Select bin
  45. uint bin_no = min(uint((centroid_pos - bounds_min) / bounds_size * num_bins), num_bins - 1);
  46. Bin &bin = mBins[bin_no];
  47. // Accumulate triangle in bin
  48. bin.mBounds.Encapsulate(mVertices, GetTriangle(t));
  49. bin.mMinCentroid = min(bin.mMinCentroid, centroid_pos);
  50. bin.mNumTriangles++;
  51. }
  52. // Calculate totals left to right
  53. AABox prev_bounds;
  54. int prev_triangles = 0;
  55. for (uint b = 0; b < num_bins; ++b)
  56. {
  57. Bin &bin = mBins[b];
  58. bin.mBoundsAccumulatedLeft = prev_bounds; // Don't include this node as we'll take a split on the left side of the bin
  59. bin.mNumTrianglesAccumulatedLeft = prev_triangles;
  60. prev_bounds.Encapsulate(bin.mBounds);
  61. prev_triangles += bin.mNumTriangles;
  62. }
  63. // Calculate totals right to left
  64. prev_bounds.SetEmpty();
  65. prev_triangles = 0;
  66. for (int b = num_bins - 1; b >= 0; --b)
  67. {
  68. Bin &bin = mBins[b];
  69. prev_bounds.Encapsulate(bin.mBounds);
  70. prev_triangles += bin.mNumTriangles;
  71. bin.mBoundsAccumulatedRight = prev_bounds;
  72. bin.mNumTrianglesAccumulatedRight = prev_triangles;
  73. }
  74. // Get best splitting plane
  75. for (uint b = 1; b < num_bins; ++b) // Start at 1 since selecting bin 0 would result in everything ending up on the right side
  76. {
  77. // Calculate surface area heuristic and see if it is better than the current best
  78. const Bin &bin = mBins[b];
  79. float cp = bin.mBoundsAccumulatedLeft.GetSurfaceArea() * bin.mNumTrianglesAccumulatedLeft + bin.mBoundsAccumulatedRight.GetSurfaceArea() * bin.mNumTrianglesAccumulatedRight;
  80. if (cp < best_cp)
  81. {
  82. best_cp = cp;
  83. best_dim = dim;
  84. best_split = bin.mMinCentroid;
  85. }
  86. }
  87. }
  88. // No split found?
  89. if (best_dim == 0xffffffff)
  90. return false;
  91. return SplitInternal(inTriangles, best_dim, best_split, outLeft, outRight);
  92. }
  93. JPH_NAMESPACE_END