feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -13,7 +13,7 @@ TriangleSplitter::TriangleSplitter(const VertexList &inVertices, const IndexedTr
mTriangles(inTriangles)
{
mSortedTriangleIdx.resize(inTriangles.size());
mCentroids.resize(inTriangles.size());
mCentroids.resize(inTriangles.size() + 1); // Add 1 so we can load with Vec3::sLoadFloat3Unsafe
for (uint t = 0; t < inTriangles.size(); ++t)
{
@ -23,44 +23,50 @@ TriangleSplitter::TriangleSplitter(const VertexList &inVertices, const IndexedTr
// Calculate centroid
inTriangles[t].GetCentroid(inVertices).StoreFloat3(&mCentroids[t]);
}
// Make sure Vec3::sLoatFloat3Unsafe doesn't read uninitialized data
mCentroids.back() = Float3(0, 0, 0);
}
bool TriangleSplitter::SplitInternal(const Range &inTriangles, uint inDimension, float inSplit, Range &outLeft, Range &outRight)
{
// Divide triangles
uint start = inTriangles.mBegin, end = inTriangles.mEnd;
uint *start = mSortedTriangleIdx.data() + inTriangles.mBegin;
uint *end = mSortedTriangleIdx.data() + inTriangles.mEnd;
while (start < end)
{
// Search for first element that is on the right hand side of the split plane
while (start < end && mCentroids[mSortedTriangleIdx[start]][inDimension] < inSplit)
while (start < end && mCentroids[*start][inDimension] < inSplit)
++start;
// Search for the first element that is on the left hand side of the split plane
while (start < end && mCentroids[mSortedTriangleIdx[end - 1]][inDimension] >= inSplit)
while (start < end && mCentroids[*(end - 1)][inDimension] >= inSplit)
--end;
if (start < end)
{
// Swap the two elements
std::swap(mSortedTriangleIdx[start], mSortedTriangleIdx[end - 1]);
++start;
--end;
std::swap(*start, *end);
++start;
}
}
JPH_ASSERT(start == end);
uint start_idx = uint(start - mSortedTriangleIdx.data());
#ifdef JPH_ENABLE_ASSERTS
// Validate division algorithm
JPH_ASSERT(inTriangles.mBegin <= start);
JPH_ASSERT(start <= inTriangles.mEnd);
for (uint i = inTriangles.mBegin; i < start; ++i)
JPH_ASSERT(inTriangles.mBegin <= start_idx);
JPH_ASSERT(start_idx <= inTriangles.mEnd);
for (uint i = inTriangles.mBegin; i < start_idx; ++i)
JPH_ASSERT(mCentroids[mSortedTriangleIdx[i]][inDimension] < inSplit);
for (uint i = start; i < inTriangles.mEnd; ++i)
for (uint i = start_idx; i < inTriangles.mEnd; ++i)
JPH_ASSERT(mCentroids[mSortedTriangleIdx[i]][inDimension] >= inSplit);
#endif
outLeft = Range(inTriangles.mBegin, start);
outRight = Range(start, inTriangles.mEnd);
outLeft = Range(inTriangles.mBegin, start_idx);
outRight = Range(start_idx, inTriangles.mEnd);
return outLeft.Count() > 0 && outRight.Count() > 0;
}

View file

@ -19,10 +19,13 @@ TriangleSplitterBinning::TriangleSplitterBinning(const VertexList &inVertices, c
bool TriangleSplitterBinning::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
{
const uint *begin = mSortedTriangleIdx.data() + inTriangles.mBegin;
const uint *end = mSortedTriangleIdx.data() + inTriangles.mEnd;
// Calculate bounds for this range
AABox centroid_bounds;
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
centroid_bounds.Encapsulate(Vec3(mCentroids[mSortedTriangleIdx[t]]));
for (const uint *t = begin; t < end; ++t)
centroid_bounds.Encapsulate(Vec3::sLoadFloat3Unsafe(mCentroids[*t]));
// Convert bounds to min coordinate and size
// Prevent division by zero if one of the dimensions is zero
@ -57,11 +60,11 @@ bool TriangleSplitterBinning::Split(const Range &inTriangles, Range &outLeft, Ra
}
// Bin all triangles in all dimensions at once
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
for (const uint *t = begin; t < end; ++t)
{
Vec3 centroid_pos(mCentroids[mSortedTriangleIdx[t]]);
Vec3 centroid_pos = Vec3::sLoadFloat3Unsafe(mCentroids[*t]);
AABox triangle_bounds = AABox::sFromTriangle(mVertices, GetTriangle(t));
AABox triangle_bounds = AABox::sFromTriangle(mVertices, mTriangles[*t]);
Vec3 bin_no_f = (centroid_pos - bounds_min) / bounds_size * float(num_bins);
UVec4 bin_no = UVec4::sMin(bin_no_f.ToInt(), UVec4::sReplicate(num_bins - 1));

View file

@ -1,170 +0,0 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/TriangleSplitter/TriangleSplitterFixedLeafSize.h>
#include <Jolt/TriangleGrouper/TriangleGrouperClosestCentroid.h>
JPH_NAMESPACE_BEGIN
TriangleSplitterFixedLeafSize::TriangleSplitterFixedLeafSize(const VertexList &inVertices, const IndexedTriangleList &inTriangles, uint inLeafSize, uint inMinNumBins, uint inMaxNumBins, uint inNumTrianglesPerBin) :
TriangleSplitter(inVertices, inTriangles),
mLeafSize(inLeafSize),
mMinNumBins(inMinNumBins),
mMaxNumBins(inMaxNumBins),
mNumTrianglesPerBin(inNumTrianglesPerBin)
{
// Group the triangles
TriangleGrouperClosestCentroid grouper;
grouper.Group(inVertices, inTriangles, mLeafSize, mSortedTriangleIdx);
// Pad triangles so that we have a multiple of mLeafSize
const uint num_triangles = (uint)inTriangles.size();
const uint num_groups = (num_triangles + mLeafSize - 1) / mLeafSize;
const uint last_triangle_idx = mSortedTriangleIdx.back();
for (uint t = num_triangles, t_end = num_groups * mLeafSize; t < t_end; ++t)
mSortedTriangleIdx.push_back(last_triangle_idx);
}
Vec3 TriangleSplitterFixedLeafSize::GetCentroidForGroup(uint inFirstTriangleInGroup)
{
JPH_ASSERT(inFirstTriangleInGroup % mLeafSize == 0);
AABox box;
for (uint g = 0; g < mLeafSize; ++g)
box.Encapsulate(mVertices, GetTriangle(inFirstTriangleInGroup + g));
return box.GetCenter();
}
bool TriangleSplitterFixedLeafSize::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
{
// Cannot split anything smaller than leaf size
JPH_ASSERT(inTriangles.Count() > mLeafSize);
JPH_ASSERT(inTriangles.Count() % mLeafSize == 0);
// Calculate bounds for this range
AABox centroid_bounds;
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; t += mLeafSize)
centroid_bounds.Encapsulate(GetCentroidForGroup(t));
float best_cp = FLT_MAX;
uint best_dim = 0xffffffff;
float best_split = 0;
// Bin in all dimensions
uint num_bins = Clamp(inTriangles.Count() / mNumTrianglesPerBin, mMinNumBins, mMaxNumBins);
Array<Bin> bins(num_bins);
for (uint dim = 0; dim < 3; ++dim)
{
float bounds_min = centroid_bounds.mMin[dim];
float bounds_size = centroid_bounds.mMax[dim] - bounds_min;
// Skip axis if too small
if (bounds_size < 1.0e-5f)
continue;
// Initialize bins
for (uint b = 0; b < num_bins; ++b)
{
Bin &bin = bins[b];
bin.mBounds.SetEmpty();
bin.mMinCentroid = bounds_min + bounds_size * (b + 1) / num_bins;
bin.mNumTriangles = 0;
}
// Bin all triangles
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; t += mLeafSize)
{
// Calculate average centroid for group
float centroid_pos = GetCentroidForGroup(t)[dim];
// Select bin
uint bin_no = min(uint((centroid_pos - bounds_min) / bounds_size * num_bins), num_bins - 1);
Bin &bin = bins[bin_no];
// Put all triangles of group in same bin
for (uint g = 0; g < mLeafSize; ++g)
bin.mBounds.Encapsulate(mVertices, GetTriangle(t + g));
bin.mMinCentroid = min(bin.mMinCentroid, centroid_pos);
bin.mNumTriangles += mLeafSize;
}
// Calculate totals left to right
AABox prev_bounds;
int prev_triangles = 0;
for (uint b = 0; b < num_bins; ++b)
{
Bin &bin = bins[b];
bin.mBoundsAccumulatedLeft = prev_bounds; // Don't include this node as we'll take a split on the left side of the bin
bin.mNumTrianglesAccumulatedLeft = prev_triangles;
prev_bounds.Encapsulate(bin.mBounds);
prev_triangles += bin.mNumTriangles;
}
// Calculate totals right to left
prev_bounds.SetEmpty();
prev_triangles = 0;
for (int b = num_bins - 1; b >= 0; --b)
{
Bin &bin = bins[b];
prev_bounds.Encapsulate(bin.mBounds);
prev_triangles += bin.mNumTriangles;
bin.mBoundsAccumulatedRight = prev_bounds;
bin.mNumTrianglesAccumulatedRight = prev_triangles;
}
// Get best splitting plane
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
{
// Calculate surface area heuristic and see if it is better than the current best
const Bin &bin = bins[b];
float cp = bin.mBoundsAccumulatedLeft.GetSurfaceArea() * bin.mNumTrianglesAccumulatedLeft + bin.mBoundsAccumulatedRight.GetSurfaceArea() * bin.mNumTrianglesAccumulatedRight;
if (cp < best_cp)
{
best_cp = cp;
best_dim = dim;
best_split = bin.mMinCentroid;
}
}
}
// No split found?
if (best_dim == 0xffffffff)
return false;
// Divide triangles
uint start = inTriangles.mBegin, end = inTriangles.mEnd;
while (start < end)
{
// Search for first element that is on the right hand side of the split plane
while (start < end && GetCentroidForGroup(start)[best_dim] < best_split)
start += mLeafSize;
// Search for the first element that is on the left hand side of the split plane
while (start < end && GetCentroidForGroup(end - mLeafSize)[best_dim] >= best_split)
end -= mLeafSize;
if (start < end)
{
// Swap the two elements
for (uint g = 0; g < mLeafSize; ++g)
std::swap(mSortedTriangleIdx[start + g], mSortedTriangleIdx[end - mLeafSize + g]);
start += mLeafSize;
end -= mLeafSize;
}
}
JPH_ASSERT(start == end);
// No suitable split found, doing random split in half
if (start == inTriangles.mBegin || start == inTriangles.mEnd)
start = inTriangles.mBegin + (inTriangles.Count() / mLeafSize + 1) / 2 * mLeafSize;
outLeft = Range(inTriangles.mBegin, start);
outRight = Range(start, inTriangles.mEnd);
JPH_ASSERT(outLeft.mEnd > outLeft.mBegin && outRight.mEnd > outRight.mBegin);
JPH_ASSERT(outLeft.Count() % mLeafSize == 0 && outRight.Count() % mLeafSize == 0);
return true;
}
JPH_NAMESPACE_END

View file

@ -1,55 +0,0 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/TriangleSplitter/TriangleSplitter.h>
#include <Jolt/Geometry/AABox.h>
JPH_NAMESPACE_BEGIN
/// Same as TriangleSplitterBinning, but ensuring that leaves have a fixed amount of triangles
/// The resulting tree should be suitable for processing on GPU where we want all threads to process an equal amount of triangles
class JPH_EXPORT TriangleSplitterFixedLeafSize : public TriangleSplitter
{
public:
/// Constructor
TriangleSplitterFixedLeafSize(const VertexList &inVertices, const IndexedTriangleList &inTriangles, uint inLeafSize, uint inMinNumBins = 8, uint inMaxNumBins = 128, uint inNumTrianglesPerBin = 6);
// See TriangleSplitter::GetStats
virtual void GetStats(Stats &outStats) const override
{
outStats.mSplitterName = "TriangleSplitterFixedLeafSize";
outStats.mLeafSize = mLeafSize;
}
// See TriangleSplitter::Split
virtual bool Split(const Range &inTriangles, Range &outLeft, Range &outRight) override;
private:
/// Get centroid for group
Vec3 GetCentroidForGroup(uint inFirstTriangleInGroup);
// Configuration
const uint mLeafSize;
const uint mMinNumBins;
const uint mMaxNumBins;
const uint mNumTrianglesPerBin;
struct Bin
{
// Properties of this bin
AABox mBounds;
float mMinCentroid;
uint mNumTriangles;
// Accumulated data from left most / right most bin to current (including this bin)
AABox mBoundsAccumulatedLeft;
AABox mBoundsAccumulatedRight;
uint mNumTrianglesAccumulatedLeft;
uint mNumTrianglesAccumulatedRight;
};
};
JPH_NAMESPACE_END

View file

@ -1,31 +0,0 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/TriangleSplitter/TriangleSplitterLongestAxis.h>
#include <Jolt/Geometry/AABox.h>
JPH_NAMESPACE_BEGIN
TriangleSplitterLongestAxis::TriangleSplitterLongestAxis(const VertexList &inVertices, const IndexedTriangleList &inTriangles) :
TriangleSplitter(inVertices, inTriangles)
{
}
bool TriangleSplitterLongestAxis::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
{
// Calculate bounding box for triangles
AABox bounds;
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
bounds.Encapsulate(mVertices, GetTriangle(t));
// Calculate split plane
uint dimension = bounds.GetExtent().GetHighestComponentIndex();
float split = bounds.GetCenter()[dimension];
return SplitInternal(inTriangles, dimension, split, outLeft, outRight);
}
JPH_NAMESPACE_END

View file

@ -1,28 +0,0 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/TriangleSplitter/TriangleSplitter.h>
JPH_NAMESPACE_BEGIN
/// Splitter using center of bounding box with longest axis
class JPH_EXPORT TriangleSplitterLongestAxis : public TriangleSplitter
{
public:
/// Constructor
TriangleSplitterLongestAxis(const VertexList &inVertices, const IndexedTriangleList &inTriangles);
// See TriangleSplitter::GetStats
virtual void GetStats(Stats &outStats) const override
{
outStats.mSplitterName = "TriangleSplitterLongestAxis";
}
// See TriangleSplitter::Split
virtual bool Split(const Range &inTriangles, Range &outLeft, Range &outRight) override;
};
JPH_NAMESPACE_END

View file

@ -15,17 +15,20 @@ TriangleSplitterMean::TriangleSplitterMean(const VertexList &inVertices, const I
bool TriangleSplitterMean::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
{
const uint *begin = mSortedTriangleIdx.data() + inTriangles.mBegin;
const uint *end = mSortedTriangleIdx.data() + inTriangles.mEnd;
// Calculate mean value for these triangles
Vec3 mean = Vec3::sZero();
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
mean += Vec3(mCentroids[mSortedTriangleIdx[t]]);
for (const uint *t = begin; t < end; ++t)
mean += Vec3::sLoadFloat3Unsafe(mCentroids[*t]);
mean *= 1.0f / inTriangles.Count();
// Calculate deviation
Vec3 deviation = Vec3::sZero();
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
for (const uint *t = begin; t < end; ++t)
{
Vec3 delta = Vec3(mCentroids[mSortedTriangleIdx[t]]) - mean;
Vec3 delta = Vec3::sLoadFloat3Unsafe(mCentroids[*t]) - mean;
deviation += delta * delta;
}
deviation *= 1.0f / inTriangles.Count();

View file

@ -1,63 +0,0 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/TriangleSplitter/TriangleSplitterMorton.h>
#include <Jolt/Geometry/MortonCode.h>
#include <Jolt/Core/QuickSort.h>
JPH_NAMESPACE_BEGIN
TriangleSplitterMorton::TriangleSplitterMorton(const VertexList &inVertices, const IndexedTriangleList &inTriangles) :
TriangleSplitter(inVertices, inTriangles)
{
// Calculate bounds of centroids
AABox bounds;
for (uint t = 0; t < inTriangles.size(); ++t)
bounds.Encapsulate(Vec3(mCentroids[t]));
// Make sure box is not degenerate
bounds.EnsureMinimalEdgeLength(1.0e-5f);
// Calculate morton codes
mMortonCodes.resize(inTriangles.size());
for (uint t = 0; t < inTriangles.size(); ++t)
mMortonCodes[t] = MortonCode::sGetMortonCode(Vec3(mCentroids[t]), bounds);
// Sort triangles on morton code
const Array<uint32> &morton_codes = mMortonCodes;
QuickSort(mSortedTriangleIdx.begin(), mSortedTriangleIdx.end(), [&morton_codes](uint inLHS, uint inRHS) { return morton_codes[inLHS] < morton_codes[inRHS]; });
}
bool TriangleSplitterMorton::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
{
uint32 first_code = mMortonCodes[mSortedTriangleIdx[inTriangles.mBegin]];
uint32 last_code = mMortonCodes[mSortedTriangleIdx[inTriangles.mEnd - 1]];
uint common_prefix = CountLeadingZeros(first_code ^ last_code);
// Use binary search to find where the next bit differs
uint split = inTriangles.mBegin; // Initial guess
uint step = inTriangles.Count();
do
{
step = (step + 1) >> 1; // Exponential decrease
uint new_split = split + step; // Proposed new position
if (new_split < inTriangles.mEnd)
{
uint32 split_code = mMortonCodes[mSortedTriangleIdx[new_split]];
uint split_prefix = CountLeadingZeros(first_code ^ split_code);
if (split_prefix > common_prefix)
split = new_split; // Accept proposal
}
}
while (step > 1);
outLeft = Range(inTriangles.mBegin, split + 1);
outRight = Range(split + 1, inTriangles.mEnd);
return outLeft.Count() > 0 && outRight.Count() > 0;
}
JPH_NAMESPACE_END

View file

@ -1,32 +0,0 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/TriangleSplitter/TriangleSplitter.h>
JPH_NAMESPACE_BEGIN
/// Splitter using Morton codes, see: http://devblogs.nvidia.com/parallelforall/thinking-parallel-part-iii-tree-construction-gpu/
class JPH_EXPORT TriangleSplitterMorton : public TriangleSplitter
{
public:
/// Constructor
TriangleSplitterMorton(const VertexList &inVertices, const IndexedTriangleList &inTriangles);
// See TriangleSplitter::GetStats
virtual void GetStats(Stats &outStats) const override
{
outStats.mSplitterName = "TriangleSplitterMorton";
}
// See TriangleSplitter::Split
virtual bool Split(const Range &inTriangles, Range &outLeft, Range &outRight) override;
private:
// Precalculated Morton codes
Array<uint32> mMortonCodes;
};
JPH_NAMESPACE_END