TriangleSplitterBinning.cpp 4.3 KB

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