feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -0,0 +1,67 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/TriangleSplitter/TriangleSplitter.h>
JPH_NAMESPACE_BEGIN
TriangleSplitter::TriangleSplitter(const VertexList &inVertices, const IndexedTriangleList &inTriangles) :
mVertices(inVertices),
mTriangles(inTriangles)
{
mSortedTriangleIdx.resize(inTriangles.size());
mCentroids.resize(inTriangles.size());
for (uint t = 0; t < inTriangles.size(); ++t)
{
// Initially triangles start unsorted
mSortedTriangleIdx[t] = t;
// Calculate centroid
inTriangles[t].GetCentroid(inVertices).StoreFloat3(&mCentroids[t]);
}
}
bool TriangleSplitter::SplitInternal(const Range &inTriangles, uint inDimension, float inSplit, Range &outLeft, Range &outRight)
{
// 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 && mCentroids[mSortedTriangleIdx[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)
--end;
if (start < end)
{
// Swap the two elements
std::swap(mSortedTriangleIdx[start], mSortedTriangleIdx[end - 1]);
++start;
--end;
}
}
JPH_ASSERT(start == end);
#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(mCentroids[mSortedTriangleIdx[i]][inDimension] < inSplit);
for (uint i = start; i < inTriangles.mEnd; ++i)
JPH_ASSERT(mCentroids[mSortedTriangleIdx[i]][inDimension] >= inSplit);
#endif
outLeft = Range(inTriangles.mBegin, start);
outRight = Range(start, inTriangles.mEnd);
return outLeft.Count() > 0 && outRight.Count() > 0;
}
JPH_NAMESPACE_END

View file

@ -0,0 +1,84 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#pragma once
#include <Jolt/Geometry/IndexedTriangle.h>
#include <Jolt/Core/NonCopyable.h>
JPH_NAMESPACE_BEGIN
/// A class that splits a triangle list into two parts for building a tree
class JPH_EXPORT TriangleSplitter : public NonCopyable
{
public:
/// Constructor
TriangleSplitter(const VertexList &inVertices, const IndexedTriangleList &inTriangles);
/// Virtual destructor
virtual ~TriangleSplitter() = default;
struct Stats
{
const char * mSplitterName = nullptr;
int mLeafSize = 0;
};
/// Get stats of splitter
virtual void GetStats(Stats &outStats) const = 0;
/// Helper struct to indicate triangle range before and after the split
struct Range
{
/// Constructor
Range() = default;
Range(uint inBegin, uint inEnd) : mBegin(inBegin), mEnd(inEnd) { }
/// Get number of triangles in range
uint Count() const
{
return mEnd - mBegin;
}
/// Start and end index (end = 1 beyond end)
uint mBegin;
uint mEnd;
};
/// Range of triangles to start with
Range GetInitialRange() const
{
return Range(0, (uint)mSortedTriangleIdx.size());
}
/// Split triangles into two groups left and right, returns false if no split could be made
/// @param inTriangles The range of triangles (in mSortedTriangleIdx) to process
/// @param outLeft On return this will contain the ranges for the left subpart. mSortedTriangleIdx may have been shuffled.
/// @param outRight On return this will contain the ranges for the right subpart. mSortedTriangleIdx may have been shuffled.
/// @return Returns true when a split was found
virtual bool Split(const Range &inTriangles, Range &outLeft, Range &outRight) = 0;
/// Get the list of vertices
const VertexList & GetVertices() const
{
return mVertices;
}
/// Get triangle by index
const IndexedTriangle & GetTriangle(uint inIdx) const
{
return mTriangles[mSortedTriangleIdx[inIdx]];
}
protected:
/// Helper function to split triangles based on dimension and split value
bool SplitInternal(const Range &inTriangles, uint inDimension, float inSplit, Range &outLeft, Range &outRight);
const VertexList & mVertices; ///< Vertices of the indexed triangles
const IndexedTriangleList & mTriangles; ///< Unsorted triangles
Array<Float3> mCentroids; ///< Unsorted centroids of triangles
Array<uint> mSortedTriangleIdx; ///< Indices to sort triangles
};
JPH_NAMESPACE_END

View file

@ -0,0 +1,136 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/TriangleSplitter/TriangleSplitterBinning.h>
JPH_NAMESPACE_BEGIN
TriangleSplitterBinning::TriangleSplitterBinning(const VertexList &inVertices, const IndexedTriangleList &inTriangles, uint inMinNumBins, uint inMaxNumBins, uint inNumTrianglesPerBin) :
TriangleSplitter(inVertices, inTriangles),
mMinNumBins(inMinNumBins),
mMaxNumBins(inMaxNumBins),
mNumTrianglesPerBin(inNumTrianglesPerBin)
{
mBins.resize(mMaxNumBins * 3); // mMaxNumBins per dimension
}
bool TriangleSplitterBinning::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
{
// Calculate bounds for this range
AABox centroid_bounds;
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
centroid_bounds.Encapsulate(Vec3(mCentroids[mSortedTriangleIdx[t]]));
// Convert bounds to min coordinate and size
// Prevent division by zero if one of the dimensions is zero
constexpr float cMinSize = 1.0e-5f;
Vec3 bounds_min = centroid_bounds.mMin;
Vec3 bounds_size = Vec3::sMax(centroid_bounds.mMax - bounds_min, Vec3::sReplicate(cMinSize));
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);
// Initialize bins
for (uint dim = 0; dim < 3; ++dim)
{
// Get bounding box size for this dimension
float bounds_min_dim = bounds_min[dim];
float bounds_size_dim = bounds_size[dim];
// Get the bins for this dimension
Bin *bins_dim = &mBins[num_bins * dim];
for (uint b = 0; b < num_bins; ++b)
{
Bin &bin = bins_dim[b];
bin.mBounds.SetEmpty();
bin.mMinCentroid = bounds_min_dim + bounds_size_dim * (b + 1) / num_bins;
bin.mNumTriangles = 0;
}
}
// Bin all triangles in all dimensions at once
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
{
Vec3 centroid_pos(mCentroids[mSortedTriangleIdx[t]]);
AABox triangle_bounds = AABox::sFromTriangle(mVertices, GetTriangle(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));
for (uint dim = 0; dim < 3; ++dim)
{
// Select bin
Bin &bin = mBins[num_bins * dim + bin_no[dim]];
// Accumulate triangle in bin
bin.mBounds.Encapsulate(triangle_bounds);
bin.mMinCentroid = min(bin.mMinCentroid, centroid_pos[dim]);
bin.mNumTriangles++;
}
}
for (uint dim = 0; dim < 3; ++dim)
{
// Skip axis if too small
if (bounds_size[dim] <= cMinSize)
continue;
// Get the bins for this dimension
Bin *bins_dim = &mBins[num_bins * dim];
// Calculate totals left to right
AABox prev_bounds;
int prev_triangles = 0;
for (uint b = 0; b < num_bins; ++b)
{
Bin &bin = bins_dim[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_dim[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_dim[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;
return SplitInternal(inTriangles, best_dim, best_split, outLeft, outRight);
}
JPH_NAMESPACE_END

View file

@ -0,0 +1,52 @@
// 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
/// Binning splitter approach taken from: Realtime Ray Tracing on GPU with BVH-based Packet Traversal by Johannes Gunther et al.
class JPH_EXPORT TriangleSplitterBinning : public TriangleSplitter
{
public:
/// Constructor
TriangleSplitterBinning(const VertexList &inVertices, const IndexedTriangleList &inTriangles, uint inMinNumBins = 8, uint inMaxNumBins = 128, uint inNumTrianglesPerBin = 6);
// See TriangleSplitter::GetStats
virtual void GetStats(Stats &outStats) const override
{
outStats.mSplitterName = "TriangleSplitterBinning";
}
// See TriangleSplitter::Split
virtual bool Split(const Range &inTriangles, Range &outLeft, Range &outRight) override;
private:
// Configuration
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;
};
// Scratch area to store the bins
Array<Bin> mBins;
};
JPH_NAMESPACE_END

View file

@ -0,0 +1,170 @@
// 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

@ -0,0 +1,55 @@
// 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

@ -0,0 +1,31 @@
// 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

@ -0,0 +1,28 @@
// 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

@ -0,0 +1,40 @@
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
// SPDX-License-Identifier: MIT
#include <Jolt/Jolt.h>
#include <Jolt/TriangleSplitter/TriangleSplitterMean.h>
JPH_NAMESPACE_BEGIN
TriangleSplitterMean::TriangleSplitterMean(const VertexList &inVertices, const IndexedTriangleList &inTriangles) :
TriangleSplitter(inVertices, inTriangles)
{
}
bool TriangleSplitterMean::Split(const Range &inTriangles, Range &outLeft, Range &outRight)
{
// Calculate mean value for these triangles
Vec3 mean = Vec3::sZero();
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
mean += Vec3(mCentroids[mSortedTriangleIdx[t]]);
mean *= 1.0f / inTriangles.Count();
// Calculate deviation
Vec3 deviation = Vec3::sZero();
for (uint t = inTriangles.mBegin; t < inTriangles.mEnd; ++t)
{
Vec3 delta = Vec3(mCentroids[mSortedTriangleIdx[t]]) - mean;
deviation += delta * delta;
}
deviation *= 1.0f / inTriangles.Count();
// Calculate split plane
uint dimension = deviation.GetHighestComponentIndex();
float split = mean[dimension];
return SplitInternal(inTriangles, dimension, split, outLeft, outRight);
}
JPH_NAMESPACE_END

View file

@ -0,0 +1,28 @@
// 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 mean of axis with biggest centroid deviation
class JPH_EXPORT TriangleSplitterMean : public TriangleSplitter
{
public:
/// Constructor
TriangleSplitterMean(const VertexList &inVertices, const IndexedTriangleList &inTriangles);
// See TriangleSplitter::GetStats
virtual void GetStats(Stats &outStats) const override
{
outStats.mSplitterName = "TriangleSplitterMean";
}
// See TriangleSplitter::Split
virtual bool Split(const Range &inTriangles, Range &outLeft, Range &outRight) override;
};
JPH_NAMESPACE_END

View file

@ -0,0 +1,63 @@
// 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

@ -0,0 +1,32 @@
// 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