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