Path: blob/master/thirdparty/jolt_physics/Jolt/TriangleSplitter/TriangleSplitterBinning.cpp
9906 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#include <Jolt/Jolt.h>56#include <Jolt/TriangleSplitter/TriangleSplitterBinning.h>78JPH_NAMESPACE_BEGIN910TriangleSplitterBinning::TriangleSplitterBinning(const VertexList &inVertices, const IndexedTriangleList &inTriangles, uint inMinNumBins, uint inMaxNumBins, uint inNumTrianglesPerBin) :11TriangleSplitter(inVertices, inTriangles),12mMinNumBins(inMinNumBins),13mMaxNumBins(inMaxNumBins),14mNumTrianglesPerBin(inNumTrianglesPerBin)15{16mBins.resize(mMaxNumBins * 3); // mMaxNumBins per dimension17}1819bool TriangleSplitterBinning::Split(const Range &inTriangles, Range &outLeft, Range &outRight)20{21const uint *begin = mSortedTriangleIdx.data() + inTriangles.mBegin;22const uint *end = mSortedTriangleIdx.data() + inTriangles.mEnd;2324// Calculate bounds for this range25AABox centroid_bounds;26for (const uint *t = begin; t < end; ++t)27centroid_bounds.Encapsulate(Vec3::sLoadFloat3Unsafe(mCentroids[*t]));2829// Convert bounds to min coordinate and size30// Prevent division by zero if one of the dimensions is zero31constexpr float cMinSize = 1.0e-5f;32Vec3 bounds_min = centroid_bounds.mMin;33Vec3 bounds_size = Vec3::sMax(centroid_bounds.mMax - bounds_min, Vec3::sReplicate(cMinSize));3435float best_cp = FLT_MAX;36uint best_dim = 0xffffffff;37float best_split = 0;3839// Bin in all dimensions40uint num_bins = Clamp(inTriangles.Count() / mNumTrianglesPerBin, mMinNumBins, mMaxNumBins);4142// Initialize bins43for (uint dim = 0; dim < 3; ++dim)44{45// Get bounding box size for this dimension46float bounds_min_dim = bounds_min[dim];47float bounds_size_dim = bounds_size[dim];4849// Get the bins for this dimension50Bin *bins_dim = &mBins[num_bins * dim];5152for (uint b = 0; b < num_bins; ++b)53{54Bin &bin = bins_dim[b];55bin.mBounds.SetEmpty();56bin.mMinCentroid = bounds_min_dim + bounds_size_dim * (b + 1) / num_bins;57bin.mNumTriangles = 0;58}59}6061// Bin all triangles in all dimensions at once62for (const uint *t = begin; t < end; ++t)63{64Vec3 centroid_pos = Vec3::sLoadFloat3Unsafe(mCentroids[*t]);6566AABox triangle_bounds = AABox::sFromTriangle(mVertices, mTriangles[*t]);6768Vec3 bin_no_f = (centroid_pos - bounds_min) / bounds_size * float(num_bins);69UVec4 bin_no = UVec4::sMin(bin_no_f.ToInt(), UVec4::sReplicate(num_bins - 1));7071for (uint dim = 0; dim < 3; ++dim)72{73// Select bin74Bin &bin = mBins[num_bins * dim + bin_no[dim]];7576// Accumulate triangle in bin77bin.mBounds.Encapsulate(triangle_bounds);78bin.mMinCentroid = min(bin.mMinCentroid, centroid_pos[dim]);79bin.mNumTriangles++;80}81}8283for (uint dim = 0; dim < 3; ++dim)84{85// Skip axis if too small86if (bounds_size[dim] <= cMinSize)87continue;8889// Get the bins for this dimension90Bin *bins_dim = &mBins[num_bins * dim];9192// Calculate totals left to right93AABox prev_bounds;94int prev_triangles = 0;95for (uint b = 0; b < num_bins; ++b)96{97Bin &bin = bins_dim[b];98bin.mBoundsAccumulatedLeft = prev_bounds; // Don't include this node as we'll take a split on the left side of the bin99bin.mNumTrianglesAccumulatedLeft = prev_triangles;100prev_bounds.Encapsulate(bin.mBounds);101prev_triangles += bin.mNumTriangles;102}103104// Calculate totals right to left105prev_bounds.SetEmpty();106prev_triangles = 0;107for (int b = num_bins - 1; b >= 0; --b)108{109Bin &bin = bins_dim[b];110prev_bounds.Encapsulate(bin.mBounds);111prev_triangles += bin.mNumTriangles;112bin.mBoundsAccumulatedRight = prev_bounds;113bin.mNumTrianglesAccumulatedRight = prev_triangles;114}115116// Get best splitting plane117for (uint b = 1; b < num_bins; ++b) // Start at 1 since selecting bin 0 would result in everything ending up on the right side118{119// Calculate surface area heuristic and see if it is better than the current best120const Bin &bin = bins_dim[b];121float cp = bin.mBoundsAccumulatedLeft.GetSurfaceArea() * bin.mNumTrianglesAccumulatedLeft + bin.mBoundsAccumulatedRight.GetSurfaceArea() * bin.mNumTrianglesAccumulatedRight;122if (cp < best_cp)123{124best_cp = cp;125best_dim = dim;126best_split = bin.mMinCentroid;127}128}129}130131// No split found?132if (best_dim == 0xffffffff)133return false;134135return SplitInternal(inTriangles, best_dim, best_split, outLeft, outRight);136}137138JPH_NAMESPACE_END139140141