TriangleSplitterBinning.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #include <Jolt/TriangleSplitter/TriangleSplitterBinning.h>
  6. JPH_NAMESPACE_BEGIN
  7. TriangleSplitterBinning::TriangleSplitterBinning(const VertexList &inVertices, const IndexedTriangleList &inTriangles, uint inMinNumBins, uint inMaxNumBins, uint inNumTrianglesPerBin) :
  8. TriangleSplitter(inVertices, inTriangles),
  9. mMinNumBins(inMinNumBins),
  10. mMaxNumBins(inMaxNumBins),
  11. mNumTrianglesPerBin(inNumTrianglesPerBin)
  12. {
  13. mBins.resize(mMaxNumBins * 3); // mMaxNumBins per dimension
  14. }
  15. bool TriangleSplitterBinning::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
  16. {
  17. // Calculate bounds for this range
  18. AABox centroid_bounds;
  19. for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
  20. centroid_bounds.Encapsulate(Vec3(mCentroids[mSortedTriangleIdx[t]]));
  21. // Convert bounds to min coordinate and size
  22. // Prevent division by zero if one of the dimensions is zero
  23. constexpr float cMinSize = 1.0e-5f;
  24. Vec3 bounds_min = centroid_bounds.mMin;
  25. Vec3 bounds_size = Vec3::sMax(centroid_bounds.mMax - bounds_min, Vec3::sReplicate(cMinSize));
  26. float best_cp = FLT_MAX;
  27. uint best_dim = 0xffffffff;
  28. float best_split = 0;
  29. // Bin in all dimensions
  30. uint num_bins = Clamp(inTriangles.Count() / mNumTrianglesPerBin, mMinNumBins, mMaxNumBins);
  31. // Initialize bins
  32. for (uint dim = 0; dim < 3; ++dim)
  33. {
  34. // Get bounding box size for this dimension
  35. float bounds_min_dim = bounds_min[dim];
  36. float bounds_size_dim = bounds_size[dim];
  37. // Get the bins for this dimension
  38. Bin *bins_dim = &mBins[num_bins * dim];
  39. for (uint b = 0; b < num_bins; ++b)
  40. {
  41. Bin &bin = bins_dim[b];
  42. bin.mBounds.SetEmpty();
  43. bin.mMinCentroid = bounds_min_dim + bounds_size_dim * (b + 1) / num_bins;
  44. bin.mNumTriangles = 0;
  45. }
  46. }
  47. // Bin all triangles in all dimensions at once
  48. for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
  49. {
  50. Vec3 centroid_pos(mCentroids[mSortedTriangleIdx[t]]);
  51. AABox triangle_bounds = AABox::sFromTriangle(mVertices, GetTriangle(t));
  52. Vec3 bin_no_f = (centroid_pos - bounds_min) / bounds_size * float(num_bins);
  53. UVec4 bin_no = UVec4::sMin(bin_no_f.ToInt(), UVec4::sReplicate(num_bins - 1));
  54. for (uint dim = 0; dim < 3; ++dim)
  55. {
  56. // Select bin
  57. Bin &bin = mBins[num_bins * dim + bin_no[dim]];
  58. // Accumulate triangle in bin
  59. bin.mBounds.Encapsulate(triangle_bounds);
  60. bin.mMinCentroid = min(bin.mMinCentroid, centroid_pos[dim]);
  61. bin.mNumTriangles++;
  62. }
  63. }
  64. for (uint dim = 0; dim < 3; ++dim)
  65. {
  66. // Skip axis if too small
  67. if (bounds_size[dim] <= cMinSize)
  68. continue;
  69. // Get the bins for this dimension
  70. Bin *bins_dim = &mBins[num_bins * dim];
  71. // Calculate totals left to right
  72. AABox prev_bounds;
  73. int prev_triangles = 0;
  74. for (uint b = 0; b < num_bins; ++b)
  75. {
  76. Bin &bin = bins_dim[b];
  77. bin.mBoundsAccumulatedLeft = prev_bounds; // Don't include this node as we'll take a split on the left side of the bin
  78. bin.mNumTrianglesAccumulatedLeft = prev_triangles;
  79. prev_bounds.Encapsulate(bin.mBounds);
  80. prev_triangles += bin.mNumTriangles;
  81. }
  82. // Calculate totals right to left
  83. prev_bounds.SetEmpty();
  84. prev_triangles = 0;
  85. for (int b = num_bins - 1; b >= 0; --b)
  86. {
  87. Bin &bin = bins_dim[b];
  88. prev_bounds.Encapsulate(bin.mBounds);
  89. prev_triangles += bin.mNumTriangles;
  90. bin.mBoundsAccumulatedRight = prev_bounds;
  91. bin.mNumTrianglesAccumulatedRight = prev_triangles;
  92. }
  93. // Get best splitting plane
  94. 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
  95. {
  96. // Calculate surface area heuristic and see if it is better than the current best
  97. const Bin &bin = bins_dim[b];
  98. float cp = bin.mBoundsAccumulatedLeft.GetSurfaceArea() * bin.mNumTrianglesAccumulatedLeft + bin.mBoundsAccumulatedRight.GetSurfaceArea() * bin.mNumTrianglesAccumulatedRight;
  99. if (cp < best_cp)
  100. {
  101. best_cp = cp;
  102. best_dim = dim;
  103. best_split = bin.mMinCentroid;
  104. }
  105. }
  106. }
  107. // No split found?
  108. if (best_dim == 0xffffffff)
  109. return false;
  110. return SplitInternal(inTriangles, best_dim, best_split, outLeft, outRight);
  111. }
  112. JPH_NAMESPACE_END