Просмотр исходного кода

MeshShape: Added option to favor build speed over quality (#1473)

* Also added option to turn off active edge calculation
* Deleted unused triangle splitter/grouper classes
* Small optimizations to the triangle splitter

Using the quality mode FavorBuildSpeed saves approximately 25% in build time. 
Turning off active edge calculations saves approximately 40% in build time.
Jorrit Rouwe 6 месяцев назад
Родитель
Сommit
94d88064a6

+ 0 - 11
Jolt/Jolt.cmake

@@ -426,23 +426,12 @@ set(JOLT_PHYSICS_SRC_FILES
 	${JOLT_PHYSICS_ROOT}/Skeleton/SkeletonMapper.h
 	${JOLT_PHYSICS_ROOT}/Skeleton/SkeletonPose.cpp
 	${JOLT_PHYSICS_ROOT}/Skeleton/SkeletonPose.h
-	${JOLT_PHYSICS_ROOT}/TriangleGrouper/TriangleGrouper.h
-	${JOLT_PHYSICS_ROOT}/TriangleGrouper/TriangleGrouperClosestCentroid.cpp
-	${JOLT_PHYSICS_ROOT}/TriangleGrouper/TriangleGrouperClosestCentroid.h
-	${JOLT_PHYSICS_ROOT}/TriangleGrouper/TriangleGrouperMorton.cpp
-	${JOLT_PHYSICS_ROOT}/TriangleGrouper/TriangleGrouperMorton.h
 	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitter.cpp
 	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitter.h
 	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterBinning.cpp
 	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterBinning.h
-	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterFixedLeafSize.cpp
-	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterFixedLeafSize.h
-	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterLongestAxis.cpp
-	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterLongestAxis.h
 	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterMean.cpp
 	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterMean.h
-	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterMorton.cpp
-	${JOLT_PHYSICS_ROOT}/TriangleSplitter/TriangleSplitterMorton.h
 )
 
 if (ENABLE_OBJECT_STREAM)

+ 36 - 2
Jolt/Physics/Collision/Shape/MeshShape.cpp

@@ -32,6 +32,7 @@
 #include <Jolt/Geometry/Plane.h>
 #include <Jolt/Geometry/OrientedBox.h>
 #include <Jolt/TriangleSplitter/TriangleSplitterBinning.h>
+#include <Jolt/TriangleSplitter/TriangleSplitterMean.h>
 #include <Jolt/AABBTree/AABBTreeBuilder.h>
 #include <Jolt/AABBTree/AABBTreeToBuffer.h>
 #include <Jolt/AABBTree/TriangleCodec/TriangleCodecIndexed8BitPackSOA4Flags.h>
@@ -55,6 +56,7 @@ JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(MeshShapeSettings)
 	JPH_ADD_ATTRIBUTE(MeshShapeSettings, mMaxTrianglesPerLeaf)
 	JPH_ADD_ATTRIBUTE(MeshShapeSettings, mActiveEdgeCosThresholdAngle)
 	JPH_ADD_ATTRIBUTE(MeshShapeSettings, mPerTriangleUserData)
+	JPH_ADD_ENUM_ATTRIBUTE(MeshShapeSettings, mBuildQuality)
 }
 
 // Codecs this mesh shape is using
@@ -190,12 +192,36 @@ MeshShape::MeshShape(const MeshShapeSettings &inSettings, ShapeResult &outResult
 	sFindActiveEdges(inSettings, indexed_triangles);
 
 	// Create triangle splitter
-	TriangleSplitterBinning splitter(inSettings.mTriangleVertices, indexed_triangles);
+	union Storage
+	{
+									Storage() { }
+									~Storage() { }
+
+		TriangleSplitterBinning		mBinning;
+		TriangleSplitterMean		mMean;
+	};
+	Storage storage;
+	TriangleSplitter *splitter = nullptr;
+	switch (inSettings.mBuildQuality)
+	{
+	case MeshShapeSettings::EBuildQuality::FavorRuntimePerformance:
+		splitter = new (&storage.mBinning) TriangleSplitterBinning(inSettings.mTriangleVertices, indexed_triangles);
+		break;
+
+	case MeshShapeSettings::EBuildQuality::FavorBuildSpeed:
+		splitter = new (&storage.mMean) TriangleSplitterMean(inSettings.mTriangleVertices, indexed_triangles);
+		break;
 
+	default:
+		JPH_ASSERT(false);
+		break;
+	}
+	
 	// Build tree
-	AABBTreeBuilder builder(splitter, inSettings.mMaxTrianglesPerLeaf);
+	AABBTreeBuilder builder(*splitter, inSettings.mMaxTrianglesPerLeaf);
 	AABBTreeBuilderStats builder_stats;
 	const AABBTreeBuilder::Node *root = builder.Build(builder_stats);
+	splitter->~TriangleSplitter();
 
 	// Convert to buffer
 	AABBTreeToBuffer<TriangleCodec, NodeCodec> buffer;
@@ -221,6 +247,14 @@ MeshShape::MeshShape(const MeshShapeSettings &inSettings, ShapeResult &outResult
 
 void MeshShape::sFindActiveEdges(const MeshShapeSettings &inSettings, IndexedTriangleList &ioIndices)
 {
+	// Check if we're requested to make all edges active
+	if (inSettings.mActiveEdgeCosThresholdAngle < 0.0f)
+	{
+		for (IndexedTriangle &triangle : ioIndices)
+			triangle.mMaterialIndex |= 0b111 << FLAGS_ACTIVE_EGDE_SHIFT;
+		return;
+	}
+
 	// A struct to hold the two vertex indices of an edge
 	struct Edge
 	{

+ 11 - 0
Jolt/Physics/Collision/Shape/MeshShape.h

@@ -58,6 +58,8 @@ public:
 	/// Cosine of the threshold angle (if the angle between the two triangles is bigger than this, the edge is active, note that a concave edge is always inactive).
 	/// Setting this value too small can cause ghost collisions with edges, setting it too big can cause depenetration artifacts (objects not depenetrating quickly).
 	/// Valid ranges are between cos(0 degrees) and cos(90 degrees). The default value is cos(5 degrees).
+	/// Negative values will make all edges active and causes EActiveEdgeMode::CollideOnlyWithActive to behave as EActiveEdgeMode::CollideWithAll.
+	/// This speeds up the build process but will require all bodies that can interact with the mesh to use BodyCreationSettings::mEnhancedInternalEdgeRemoval = true.
 	float							mActiveEdgeCosThresholdAngle = 0.996195f;					// cos(5 degrees)
 
 	/// When true, we store the user data coming from Triangle::mUserData or IndexedTriangle::mUserData in the mesh shape.
@@ -65,6 +67,15 @@ public:
 	/// Can be retrieved using MeshShape::GetTriangleUserData.
 	/// Turning this on increases the memory used by the MeshShape by roughly 25%.
 	bool							mPerTriangleUserData = false;
+
+	enum class EBuildQuality
+	{
+		FavorRuntimePerformance,																///< Favor runtime performance, takes more time to build the MeshShape but performs better
+		FavorBuildSpeed,																		///< Favor build speed, build the tree faster but the MeshShape will be slower
+	};
+
+	/// Determines the quality of the tree building process.
+	EBuildQuality					mBuildQuality = EBuildQuality::FavorRuntimePerformance;
 };
 
 /// A mesh shape, consisting of triangles. Mesh shapes are mostly used for static geometry.

+ 0 - 27
Jolt/TriangleGrouper/TriangleGrouper.h

@@ -1,27 +0,0 @@
-// 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 groups triangles in batches of N (according to closeness)
-class JPH_EXPORT TriangleGrouper : public NonCopyable
-{
-public:
-	/// Virtual destructor
-	virtual					~TriangleGrouper() = default;
-
-	/// Group a batch of indexed triangles
-	/// @param inVertices The list of vertices
-	/// @param inTriangles The list of indexed triangles (indexes into inVertices)
-	/// @param inGroupSize How big each group should be
-	/// @param outGroupedTriangleIndices An ordered list of indices (indexing into inTriangles), contains groups of inGroupSize large worth of indices to triangles that are grouped together. If the triangle count is not an exact multiple of inGroupSize the last batch will be smaller.
-	virtual void			Group(const VertexList &inVertices, const IndexedTriangleList &inTriangles, int inGroupSize, Array<uint> &outGroupedTriangleIndices) = 0;
-};
-
-JPH_NAMESPACE_END

+ 0 - 95
Jolt/TriangleGrouper/TriangleGrouperClosestCentroid.cpp

@@ -1,95 +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/TriangleGrouper/TriangleGrouperClosestCentroid.h>
-#include <Jolt/Geometry/MortonCode.h>
-#include <Jolt/Core/QuickSort.h>
-
-JPH_NAMESPACE_BEGIN
-
-void TriangleGrouperClosestCentroid::Group(const VertexList &inVertices, const IndexedTriangleList &inTriangles, int inGroupSize, Array<uint> &outGroupedTriangleIndices)
-{
-	const uint triangle_count = (uint)inTriangles.size();
-	const uint num_batches = (triangle_count + inGroupSize - 1) / inGroupSize;
-
-	Array<Vec3> centroids;
-	centroids.resize(triangle_count);
-
-	outGroupedTriangleIndices.resize(triangle_count);
-
-	for (uint t = 0; t < triangle_count; ++t)
-	{
-		// Store centroid
-		centroids[t] = inTriangles[t].GetCentroid(inVertices);
-
-		// Initialize sort table
-		outGroupedTriangleIndices[t] = t;
-	}
-
-	Array<uint>::const_iterator triangles_end = outGroupedTriangleIndices.end();
-
-	// Sort per batch
-	for (uint b = 0; b < num_batches - 1; ++b)
-	{
-		// Get iterators
-		Array<uint>::iterator batch_begin = outGroupedTriangleIndices.begin() + b * inGroupSize;
-		Array<uint>::iterator batch_end = batch_begin + inGroupSize;
-		Array<uint>::iterator batch_begin_plus_1 = batch_begin + 1;
-		Array<uint>::iterator batch_end_minus_1 = batch_end - 1;
-
-		// Find triangle with centroid with lowest X coordinate
-		Array<uint>::iterator lowest_iter = batch_begin;
-		float lowest_val = centroids[*lowest_iter].GetX();
-		for (Array<uint>::iterator other = batch_begin; other != triangles_end; ++other)
-		{
-			float val = centroids[*other].GetX();
-			if (val < lowest_val)
-			{
-				lowest_iter = other;
-				lowest_val = val;
-			}
-		}
-
-		// Make this triangle the first in a new batch
-		std::swap(*batch_begin, *lowest_iter);
-		Vec3 first_centroid = centroids[*batch_begin];
-
-		// Sort remaining triangles in batch on distance to first triangle
-		QuickSort(batch_begin_plus_1, batch_end,
-			[&first_centroid, &centroids](uint inLHS, uint inRHS)
-			{
-				return (centroids[inLHS] - first_centroid).LengthSq() < (centroids[inRHS] - first_centroid).LengthSq();
-			});
-
-		// Loop over remaining triangles
-		float furthest_dist = (centroids[*batch_end_minus_1] - first_centroid).LengthSq();
-		for (Array<uint>::iterator other = batch_end; other != triangles_end; ++other)
-		{
-			// Check if this triangle is closer than the furthest triangle in the batch
-			float dist = (centroids[*other] - first_centroid).LengthSq();
-			if (dist < furthest_dist)
-			{
-				// Replace furthest triangle
-				uint other_val = *other;
-				*other = *batch_end_minus_1;
-
-				// Find first element that is bigger than this one and insert the current item before it
-				Array<uint>::iterator upper = std::upper_bound(batch_begin_plus_1, batch_end, dist,
-					[&first_centroid, &centroids](float inLHS, uint inRHS)
-					{
-						return inLHS < (centroids[inRHS] - first_centroid).LengthSq();
-					});
-				std::copy_backward(upper, batch_end_minus_1, batch_end);
-				*upper = other_val;
-
-				// Calculate new furthest distance
-				furthest_dist = (centroids[*batch_end_minus_1] - first_centroid).LengthSq();
-			}
-		}
-	}
-}
-
-JPH_NAMESPACE_END

+ 0 - 21
Jolt/TriangleGrouper/TriangleGrouperClosestCentroid.h

@@ -1,21 +0,0 @@
-// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
-// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
-// SPDX-License-Identifier: MIT
-
-#pragma once
-
-#include <Jolt/TriangleGrouper/TriangleGrouper.h>
-
-JPH_NAMESPACE_BEGIN
-
-/// A class that groups triangles in batches of N.
-/// Starts with centroid with lowest X coordinate and finds N closest centroids, this repeats until all groups have been found.
-/// Time complexity: O(N^2)
-class JPH_EXPORT TriangleGrouperClosestCentroid : public TriangleGrouper
-{
-public:
-	// See: TriangleGrouper::Group
-	virtual void			Group(const VertexList &inVertices, const IndexedTriangleList &inTriangles, int inGroupSize, Array<uint> &outGroupedTriangleIndices) override;
-};
-
-JPH_NAMESPACE_END

+ 0 - 49
Jolt/TriangleGrouper/TriangleGrouperMorton.cpp

@@ -1,49 +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/TriangleGrouper/TriangleGrouperMorton.h>
-#include <Jolt/Geometry/MortonCode.h>
-#include <Jolt/Core/QuickSort.h>
-
-JPH_NAMESPACE_BEGIN
-
-void TriangleGrouperMorton::Group(const VertexList &inVertices, const IndexedTriangleList &inTriangles, int inGroupSize, Array<uint> &outGroupedTriangleIndices)
-{
-	const uint triangle_count = (uint)inTriangles.size();
-
-	Array<Vec3> centroids;
-	centroids.resize(triangle_count);
-
-	outGroupedTriangleIndices.resize(triangle_count);
-
-	for (uint t = 0; t < triangle_count; ++t)
-	{
-		// Store centroid
-		centroids[t] = inTriangles[t].GetCentroid(inVertices);
-
-		// Initialize sort table
-		outGroupedTriangleIndices[t] = t;
-	}
-
-	// Get bounding box of all centroids
-	AABox centroid_bounds;
-	for (uint t = 0; t < triangle_count; ++t)
-		centroid_bounds.Encapsulate(centroids[t]);
-
-	// Make sure box is not degenerate
-	centroid_bounds.EnsureMinimalEdgeLength(1.0e-5f);
-
-	// Calculate morton code for each centroid
-	Array<uint32> morton_codes;
-	morton_codes.resize(triangle_count);
-	for (uint t = 0; t < triangle_count; ++t)
-		morton_codes[t] = MortonCode::sGetMortonCode(centroids[t], centroid_bounds);
-
-	// Sort triangles based on morton code
-	QuickSort(outGroupedTriangleIndices.begin(), outGroupedTriangleIndices.end(), [&morton_codes](uint inLHS, uint inRHS) { return morton_codes[inLHS] < morton_codes[inRHS]; });
-}
-
-JPH_NAMESPACE_END

+ 0 - 20
Jolt/TriangleGrouper/TriangleGrouperMorton.h

@@ -1,20 +0,0 @@
-// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
-// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
-// SPDX-License-Identifier: MIT
-
-#pragma once
-
-#include <Jolt/TriangleGrouper/TriangleGrouper.h>
-
-JPH_NAMESPACE_BEGIN
-
-/// A class that groups triangles in batches of N according to morton code of centroid.
-/// Time complexity: O(N log(N))
-class JPH_EXPORT TriangleGrouperMorton : public TriangleGrouper
-{
-public:
-	// See: TriangleGrouper::Group
-	virtual void			Group(const VertexList &inVertices, const IndexedTriangleList &inTriangles, int inGroupSize, Array<uint> &outGroupedTriangleIndices) override;
-};
-
-JPH_NAMESPACE_END

+ 18 - 12
Jolt/TriangleSplitter/TriangleSplitter.cpp

@@ -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;
 }
 

+ 8 - 5
Jolt/TriangleSplitter/TriangleSplitterBinning.cpp

@@ -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));

+ 0 - 170
Jolt/TriangleSplitter/TriangleSplitterFixedLeafSize.cpp

@@ -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

+ 0 - 55
Jolt/TriangleSplitter/TriangleSplitterFixedLeafSize.h

@@ -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

+ 0 - 31
Jolt/TriangleSplitter/TriangleSplitterLongestAxis.cpp

@@ -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

+ 0 - 28
Jolt/TriangleSplitter/TriangleSplitterLongestAxis.h

@@ -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

+ 7 - 4
Jolt/TriangleSplitter/TriangleSplitterMean.cpp

@@ -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();

+ 0 - 63
Jolt/TriangleSplitter/TriangleSplitterMorton.cpp

@@ -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

+ 0 - 32
Jolt/TriangleSplitter/TriangleSplitterMorton.h

@@ -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