Browse Source

Improving AABBTree build speed (#1333)

* Avoid lots of individual memory allocations in AABBTreeBuilder.  Instead allocate nodes and leaf triangles from single Arrays.
* Using Array instead of Deque in AABBTreeToBuffer.  Avoids a lot of allocations.

Co-authored-by: Ono-Sendai <[email protected]>
Jorrit Rouwe 9 months ago
parent
commit
88de579d67

+ 63 - 60
Jolt/AABBTree/AABBTreeBuilder.cpp

@@ -8,84 +8,72 @@
 
 
 JPH_NAMESPACE_BEGIN
 JPH_NAMESPACE_BEGIN
 
 
-AABBTreeBuilder::Node::Node()
-{
-	mChild[0] = nullptr;
-	mChild[1] = nullptr;
-}
-
-AABBTreeBuilder::Node::~Node()
-{
-	delete mChild[0];
-	delete mChild[1];
-}
-
-uint AABBTreeBuilder::Node::GetMinDepth() const
+uint AABBTreeBuilder::Node::GetMinDepth(const Array<Node> &inNodes) const
 {
 {
 	if (HasChildren())
 	if (HasChildren())
 	{
 	{
-		uint left = mChild[0]->GetMinDepth();
-		uint right = mChild[1]->GetMinDepth();
+		uint left = inNodes[mChild[0]].GetMinDepth(inNodes);
+		uint right = inNodes[mChild[1]].GetMinDepth(inNodes);
 		return min(left, right) + 1;
 		return min(left, right) + 1;
 	}
 	}
 	else
 	else
 		return 1;
 		return 1;
 }
 }
 
 
-uint AABBTreeBuilder::Node::GetMaxDepth() const
+uint AABBTreeBuilder::Node::GetMaxDepth(const Array<Node> &inNodes) const
 {
 {
 	if (HasChildren())
 	if (HasChildren())
 	{
 	{
-		uint left = mChild[0]->GetMaxDepth();
-		uint right = mChild[1]->GetMaxDepth();
+		uint left = inNodes[mChild[0]].GetMaxDepth(inNodes);
+		uint right = inNodes[mChild[1]].GetMaxDepth(inNodes);
 		return max(left, right) + 1;
 		return max(left, right) + 1;
 	}
 	}
 	else
 	else
 		return 1;
 		return 1;
 }
 }
 
 
-uint AABBTreeBuilder::Node::GetNodeCount() const
+uint AABBTreeBuilder::Node::GetNodeCount(const Array<Node> &inNodes) const
 {
 {
 	if (HasChildren())
 	if (HasChildren())
-		return mChild[0]->GetNodeCount() + mChild[1]->GetNodeCount() + 1;
+		return inNodes[mChild[0]].GetNodeCount(inNodes) + inNodes[mChild[1]].GetNodeCount(inNodes) + 1;
 	else
 	else
 		return 1;
 		return 1;
 }
 }
 
 
-uint AABBTreeBuilder::Node::GetLeafNodeCount() const
+uint AABBTreeBuilder::Node::GetLeafNodeCount(const Array<Node> &inNodes) const
 {
 {
 	if (HasChildren())
 	if (HasChildren())
-		return mChild[0]->GetLeafNodeCount() + mChild[1]->GetLeafNodeCount();
+		return inNodes[mChild[0]].GetLeafNodeCount(inNodes) + inNodes[mChild[1]].GetLeafNodeCount(inNodes);
 	else
 	else
 		return 1;
 		return 1;
 }
 }
 
 
-uint AABBTreeBuilder::Node::GetTriangleCountInTree() const
+uint AABBTreeBuilder::Node::GetTriangleCountInTree(const Array<Node> &inNodes) const
 {
 {
 	if (HasChildren())
 	if (HasChildren())
-		return mChild[0]->GetTriangleCountInTree() + mChild[1]->GetTriangleCountInTree();
+		return inNodes[mChild[0]].GetTriangleCountInTree(inNodes) + inNodes[mChild[1]].GetTriangleCountInTree(inNodes);
 	else
 	else
 		return GetTriangleCount();
 		return GetTriangleCount();
 }
 }
 
 
-void AABBTreeBuilder::Node::GetTriangleCountPerNode(float &outAverage, uint &outMin, uint &outMax) const
+void AABBTreeBuilder::Node::GetTriangleCountPerNode(const Array<Node> &inNodes, float &outAverage, uint &outMin, uint &outMax) const
 {
 {
 	outMin = INT_MAX;
 	outMin = INT_MAX;
 	outMax = 0;
 	outMax = 0;
 	outAverage = 0;
 	outAverage = 0;
 	uint avg_divisor = 0;
 	uint avg_divisor = 0;
-	GetTriangleCountPerNodeInternal(outAverage, avg_divisor, outMin, outMax);
+	GetTriangleCountPerNodeInternal(inNodes, outAverage, avg_divisor, outMin, outMax);
 	if (avg_divisor > 0)
 	if (avg_divisor > 0)
 		outAverage /= avg_divisor;
 		outAverage /= avg_divisor;
 }
 }
 
 
-float AABBTreeBuilder::Node::CalculateSAHCost(float inCostTraversal, float inCostLeaf) const
+float AABBTreeBuilder::Node::CalculateSAHCost(const Array<Node> &inNodes, float inCostTraversal, float inCostLeaf) const
 {
 {
 	float surface_area = mBounds.GetSurfaceArea();
 	float surface_area = mBounds.GetSurfaceArea();
-	return surface_area > 0.0f? CalculateSAHCostInternal(inCostTraversal / surface_area, inCostLeaf / surface_area) : 0.0f;
+	return surface_area > 0.0f? CalculateSAHCostInternal(inNodes, inCostTraversal / surface_area, inCostLeaf / surface_area) : 0.0f;
 }
 }
 
 
-void AABBTreeBuilder::Node::GetNChildren(uint inN, Array<const Node *> &outChildren) const
+void AABBTreeBuilder::Node::GetNChildren(const Array<Node> &inNodes, uint inN, Array<const Node*> &outChildren) const
 {
 {
 	JPH_ASSERT(outChildren.empty());
 	JPH_ASSERT(outChildren.empty());
 
 
@@ -94,8 +82,8 @@ void AABBTreeBuilder::Node::GetNChildren(uint inN, Array<const Node *> &outChild
 		return;
 		return;
 
 
 	// Start with the children of this node
 	// Start with the children of this node
-	outChildren.push_back(mChild[0]);
-	outChildren.push_back(mChild[1]);
+	outChildren.push_back(&inNodes[mChild[0]]);
+	outChildren.push_back(&inNodes[mChild[1]]);
 
 
 	size_t next = 0;
 	size_t next = 0;
 	bool all_triangles = true;
 	bool all_triangles = true;
@@ -116,8 +104,8 @@ void AABBTreeBuilder::Node::GetNChildren(uint inN, Array<const Node *> &outChild
 		if (to_expand->HasChildren())
 		if (to_expand->HasChildren())
 		{
 		{
 			outChildren.erase(outChildren.begin() + next);
 			outChildren.erase(outChildren.begin() + next);
-			outChildren.push_back(to_expand->mChild[0]);
-			outChildren.push_back(to_expand->mChild[1]);
+			outChildren.push_back(&inNodes[to_expand->mChild[0]]);
+			outChildren.push_back(&inNodes[to_expand->mChild[1]]);
 			all_triangles = false;
 			all_triangles = false;
 		}
 		}
 		else
 		else
@@ -127,22 +115,22 @@ void AABBTreeBuilder::Node::GetNChildren(uint inN, Array<const Node *> &outChild
 	}
 	}
 }
 }
 
 
-float AABBTreeBuilder::Node::CalculateSAHCostInternal(float inCostTraversalDivSurfaceArea, float inCostLeafDivSurfaceArea) const
+float AABBTreeBuilder::Node::CalculateSAHCostInternal(const Array<Node> &inNodes, float inCostTraversalDivSurfaceArea, float inCostLeafDivSurfaceArea) const
 {
 {
 	if (HasChildren())
 	if (HasChildren())
 		return inCostTraversalDivSurfaceArea * mBounds.GetSurfaceArea()
 		return inCostTraversalDivSurfaceArea * mBounds.GetSurfaceArea()
-			+ mChild[0]->CalculateSAHCostInternal(inCostTraversalDivSurfaceArea, inCostLeafDivSurfaceArea)
-			+ mChild[1]->CalculateSAHCostInternal(inCostTraversalDivSurfaceArea, inCostLeafDivSurfaceArea);
+			+ inNodes[mChild[0]].CalculateSAHCostInternal(inNodes, inCostTraversalDivSurfaceArea, inCostLeafDivSurfaceArea)
+			+ inNodes[mChild[1]].CalculateSAHCostInternal(inNodes, inCostTraversalDivSurfaceArea, inCostLeafDivSurfaceArea);
 	else
 	else
 		return inCostLeafDivSurfaceArea * mBounds.GetSurfaceArea() * GetTriangleCount();
 		return inCostLeafDivSurfaceArea * mBounds.GetSurfaceArea() * GetTriangleCount();
 }
 }
 
 
-void AABBTreeBuilder::Node::GetTriangleCountPerNodeInternal(float &outAverage, uint &outAverageDivisor, uint &outMin, uint &outMax) const
+void AABBTreeBuilder::Node::GetTriangleCountPerNodeInternal(const Array<Node> &inNodes, float &outAverage, uint &outAverageDivisor, uint &outMin, uint &outMax) const
 {
 {
 	if (HasChildren())
 	if (HasChildren())
 	{
 	{
-		mChild[0]->GetTriangleCountPerNodeInternal(outAverage, outAverageDivisor, outMin, outMax);
-		mChild[1]->GetTriangleCountPerNodeInternal(outAverage, outAverageDivisor, outMin, outMax);
+		inNodes[mChild[0]].GetTriangleCountPerNodeInternal(inNodes, outAverage, outAverageDivisor, outMin, outMax);
+		inNodes[mChild[1]].GetTriangleCountPerNodeInternal(inNodes, outAverage, outAverageDivisor, outMin, outMax);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -162,28 +150,36 @@ AABBTreeBuilder::AABBTreeBuilder(TriangleSplitter &inSplitter, uint inMaxTriangl
 AABBTreeBuilder::Node *AABBTreeBuilder::Build(AABBTreeBuilderStats &outStats)
 AABBTreeBuilder::Node *AABBTreeBuilder::Build(AABBTreeBuilderStats &outStats)
 {
 {
 	TriangleSplitter::Range initial = mTriangleSplitter.GetInitialRange();
 	TriangleSplitter::Range initial = mTriangleSplitter.GetInitialRange();
-	Node *root = BuildInternal(initial);
 
 
+	// Worst case for number of nodes: 1 leaf node per triangle. At each level above, the number of nodes is half that of the level below.
+	// This means that at most we'll be allocating 2x the number of triangles in nodes.
+	mNodes.reserve(2 * initial.Count());
+	mTriangles.reserve(initial.Count());
+
+	// Build the tree
+	Node &root = mNodes[BuildInternal(initial)];
+
+	// Collect stats
 	float avg_triangles_per_leaf;
 	float avg_triangles_per_leaf;
 	uint min_triangles_per_leaf, max_triangles_per_leaf;
 	uint min_triangles_per_leaf, max_triangles_per_leaf;
-	root->GetTriangleCountPerNode(avg_triangles_per_leaf, min_triangles_per_leaf, max_triangles_per_leaf);
+	root.GetTriangleCountPerNode(mNodes, avg_triangles_per_leaf, min_triangles_per_leaf, max_triangles_per_leaf);
 
 
 	mTriangleSplitter.GetStats(outStats.mSplitterStats);
 	mTriangleSplitter.GetStats(outStats.mSplitterStats);
 
 
-	outStats.mSAHCost = root->CalculateSAHCost(1.0f, 1.0f);
-	outStats.mMinDepth = root->GetMinDepth();
-	outStats.mMaxDepth = root->GetMaxDepth();
-	outStats.mNodeCount = root->GetNodeCount();
-	outStats.mLeafNodeCount = root->GetLeafNodeCount();
+	outStats.mSAHCost = root.CalculateSAHCost(mNodes, 1.0f, 1.0f);
+	outStats.mMinDepth = root.GetMinDepth(mNodes);
+	outStats.mMaxDepth = root.GetMaxDepth(mNodes);
+	outStats.mNodeCount = root.GetNodeCount(mNodes);
+	outStats.mLeafNodeCount = root.GetLeafNodeCount(mNodes);
 	outStats.mMaxTrianglesPerLeaf = mMaxTrianglesPerLeaf;
 	outStats.mMaxTrianglesPerLeaf = mMaxTrianglesPerLeaf;
 	outStats.mTreeMinTrianglesPerLeaf = min_triangles_per_leaf;
 	outStats.mTreeMinTrianglesPerLeaf = min_triangles_per_leaf;
 	outStats.mTreeMaxTrianglesPerLeaf = max_triangles_per_leaf;
 	outStats.mTreeMaxTrianglesPerLeaf = max_triangles_per_leaf;
 	outStats.mTreeAvgTrianglesPerLeaf = avg_triangles_per_leaf;
 	outStats.mTreeAvgTrianglesPerLeaf = avg_triangles_per_leaf;
 
 
-	return root;
+	return &root;
 }
 }
 
 
-AABBTreeBuilder::Node *AABBTreeBuilder::BuildInternal(const TriangleSplitter::Range &inTriangles)
+uint AABBTreeBuilder::BuildInternal(const TriangleSplitter::Range &inTriangles)
 {
 {
 	// Check if there are too many triangles left
 	// Check if there are too many triangles left
 	if (inTriangles.Count() > mMaxTrianglesPerLeaf)
 	if (inTriangles.Count() > mMaxTrianglesPerLeaf)
@@ -214,26 +210,33 @@ AABBTreeBuilder::Node *AABBTreeBuilder::BuildInternal(const TriangleSplitter::Ra
 		}
 		}
 
 
 		// Recursively build
 		// Recursively build
-		Node *node = new Node();
-		node->mChild[0] = BuildInternal(left);
-		node->mChild[1] = BuildInternal(right);
-		node->mBounds = node->mChild[0]->mBounds;
-		node->mBounds.Encapsulate(node->mChild[1]->mBounds);
-		return node;
+		const uint node_index = (uint)mNodes.size();
+		mNodes.push_back(Node());
+		uint left_index = BuildInternal(left);
+		uint right_index = BuildInternal(right);
+		Node &node = mNodes[node_index];
+		node.mChild[0] = left_index;
+		node.mChild[1] = right_index;
+		node.mBounds = mNodes[node.mChild[0]].mBounds;
+		node.mBounds.Encapsulate(mNodes[node.mChild[1]].mBounds);
+		return node_index;
 	}
 	}
 
 
 	// Create leaf node
 	// Create leaf node
-	Node *node = new Node();
-	node->mTriangles.reserve(inTriangles.Count());
+	const uint node_index = (uint)mNodes.size();
+	mNodes.push_back(Node());
+	Node &node = mNodes.back();
+	node.mTrianglesBegin = (uint)mTriangles.size();
+	node.mNumTriangles = inTriangles.mEnd - inTriangles.mBegin;
+	const VertexList &v = mTriangleSplitter.GetVertices();
 	for (uint i = inTriangles.mBegin; i < inTriangles.mEnd; ++i)
 	for (uint i = inTriangles.mBegin; i < inTriangles.mEnd; ++i)
 	{
 	{
 		const IndexedTriangle &t = mTriangleSplitter.GetTriangle(i);
 		const IndexedTriangle &t = mTriangleSplitter.GetTriangle(i);
-		const VertexList &v = mTriangleSplitter.GetVertices();
-		node->mTriangles.push_back(t);
-		node->mBounds.Encapsulate(v, t);
+		mTriangles.push_back(t);
+		node.mBounds.Encapsulate(v, t);
 	}
 	}
 
 
-	return node;
+	return node_index;
 }
 }
 
 
 JPH_NAMESPACE_END
 JPH_NAMESPACE_END

+ 28 - 20
Jolt/AABBTree/AABBTreeBuilder.h

@@ -36,62 +36,62 @@ class JPH_EXPORT AABBTreeBuilder
 {
 {
 public:
 public:
 	/// A node in the tree, contains the AABox for the tree and any child nodes or triangles
 	/// A node in the tree, contains the AABox for the tree and any child nodes or triangles
-	class Node : public NonCopyable
+	class Node
 	{
 	{
 	public:
 	public:
 		JPH_OVERRIDE_NEW_DELETE
 		JPH_OVERRIDE_NEW_DELETE
 
 
-		/// Constructor
-							Node();
-							~Node();
+		/// Indicates that there is no child
+		static constexpr uint cInvalidNodeIndex = ~uint(0);
 
 
 		/// Get number of triangles in this node
 		/// Get number of triangles in this node
-		inline uint			GetTriangleCount() const				{ return uint(mTriangles.size()); }
+		inline uint			GetTriangleCount() const				{ return mNumTriangles; }
 
 
 		/// Check if this node has any children
 		/// Check if this node has any children
-		inline bool			HasChildren() const						{ return mChild[0] != nullptr || mChild[1] != nullptr; }
+		inline bool			HasChildren() const						{ return mChild[0] != cInvalidNodeIndex || mChild[1] != cInvalidNodeIndex; }
 
 
 		/// Min depth of tree
 		/// Min depth of tree
-		uint				GetMinDepth() const;
+		uint				GetMinDepth(const Array<Node> &inNodes) const;
 
 
 		/// Max depth of tree
 		/// Max depth of tree
-		uint				GetMaxDepth() const;
+		uint				GetMaxDepth(const Array<Node> &inNodes) const;
 
 
 		/// Number of nodes in tree
 		/// Number of nodes in tree
-		uint				GetNodeCount() const;
+		uint				GetNodeCount(const Array<Node> &inNodes) const;
 
 
 		/// Number of leaf nodes in tree
 		/// Number of leaf nodes in tree
-		uint				GetLeafNodeCount() const;
+		uint				GetLeafNodeCount(const Array<Node> &inNodes) const;
 
 
 		/// Get triangle count in tree
 		/// Get triangle count in tree
-		uint				GetTriangleCountInTree() const;
+		uint				GetTriangleCountInTree(const Array<Node> &inNodes) const;
 
 
 		/// Calculate min and max triangles per node
 		/// Calculate min and max triangles per node
-		void				GetTriangleCountPerNode(float &outAverage, uint &outMin, uint &outMax) const;
+		void				GetTriangleCountPerNode(const Array<Node> &inNodes, float &outAverage, uint &outMin, uint &outMax) const;
 
 
 		/// Calculate the total cost of the tree using the surface area heuristic
 		/// Calculate the total cost of the tree using the surface area heuristic
-		float				CalculateSAHCost(float inCostTraversal, float inCostLeaf) const;
+		float				CalculateSAHCost(const Array<Node> &inNodes, float inCostTraversal, float inCostLeaf) const;
 
 
 		/// Recursively get children (breadth first) to get in total inN children (or less if there are no more)
 		/// Recursively get children (breadth first) to get in total inN children (or less if there are no more)
-		void				GetNChildren(uint inN, Array<const Node *> &outChildren) const;
+		void				GetNChildren(const Array<Node> &inNodes, uint inN, Array<const Node *> &outChildren) const;
 
 
 		/// Bounding box
 		/// Bounding box
 		AABox				mBounds;
 		AABox				mBounds;
 
 
 		/// Triangles (if no child nodes)
 		/// Triangles (if no child nodes)
-		IndexedTriangleList mTriangles;
+		uint				mTrianglesBegin; // Index into mTriangles
+		uint				mNumTriangles = 0;
 
 
-		/// Child nodes (if no triangles)
-		Node *				mChild[2];
+		/// Child node indices (if no triangles)
+		uint				mChild[2] = { cInvalidNodeIndex, cInvalidNodeIndex };
 
 
 	private:
 	private:
 		friend class AABBTreeBuilder;
 		friend class AABBTreeBuilder;
 
 
 		/// Recursive helper function to calculate cost of the tree
 		/// Recursive helper function to calculate cost of the tree
-		float				CalculateSAHCostInternal(float inCostTraversalDivSurfaceArea, float inCostLeafDivSurfaceArea) const;
+		float				CalculateSAHCostInternal(const Array<Node> &inNodes, float inCostTraversalDivSurfaceArea, float inCostLeafDivSurfaceArea) const;
 
 
 		/// Recursive helper function to calculate min and max triangles per node
 		/// Recursive helper function to calculate min and max triangles per node
-		void				GetTriangleCountPerNodeInternal(float &outAverage, uint &outAverageDivisor, uint &outMin, uint &outMax) const;
+		void				GetTriangleCountPerNodeInternal(const Array<Node> &inNodes, float &outAverage, uint &outAverageDivisor, uint &outMin, uint &outMax) const;
 	};
 	};
 
 
 	/// Constructor
 	/// Constructor
@@ -100,11 +100,19 @@ public:
 	/// Recursively build tree, returns the root node of the tree
 	/// Recursively build tree, returns the root node of the tree
 	Node *					Build(AABBTreeBuilderStats &outStats);
 	Node *					Build(AABBTreeBuilderStats &outStats);
 
 
+	/// Get all nodes
+	const Array<Node> &		GetNodes() const						{ return mNodes; }
+
+	/// Get all triangles
+	const Array<IndexedTriangle> &GetTriangles() const				{ return mTriangles; }
+
 private:
 private:
-	Node *					BuildInternal(const TriangleSplitter::Range &inTriangles);
+	uint					BuildInternal(const TriangleSplitter::Range &inTriangles);
 
 
 	TriangleSplitter &		mTriangleSplitter;
 	TriangleSplitter &		mTriangleSplitter;
 	const uint				mMaxTrianglesPerLeaf;
 	const uint				mMaxTrianglesPerLeaf;
+	Array<Node>				mNodes;
+	Array<IndexedTriangle>	mTriangles;
 };
 };
 
 
 JPH_NAMESPACE_END
 JPH_NAMESPACE_END

+ 7 - 13
Jolt/AABBTree/AABBTreeToBuffer.h

@@ -8,14 +8,8 @@
 #include <Jolt/Core/ByteBuffer.h>
 #include <Jolt/Core/ByteBuffer.h>
 #include <Jolt/Geometry/IndexedTriangle.h>
 #include <Jolt/Geometry/IndexedTriangle.h>
 
 
-JPH_SUPPRESS_WARNINGS_STD_BEGIN
-#include <deque>
-JPH_SUPPRESS_WARNINGS_STD_END
-
 JPH_NAMESPACE_BEGIN
 JPH_NAMESPACE_BEGIN
 
 
-template <class T> using Deque = std::deque<T, STLAllocator<T>>;
-
 /// Conversion algorithm that converts an AABB tree to an optimized binary buffer
 /// Conversion algorithm that converts an AABB tree to an optimized binary buffer
 template <class TriangleCodec, class NodeCodec>
 template <class TriangleCodec, class NodeCodec>
 class AABBTreeToBuffer
 class AABBTreeToBuffer
@@ -37,14 +31,14 @@ public:
 	static const int TriangleHeaderSize = TriangleCodec::TriangleHeaderSize;
 	static const int TriangleHeaderSize = TriangleCodec::TriangleHeaderSize;
 
 
 	/// Convert AABB tree. Returns false if failed.
 	/// Convert AABB tree. Returns false if failed.
-	bool							Convert(const VertexList &inVertices, const AABBTreeBuilder::Node *inRoot, bool inStoreUserData, const char *&outError)
+	bool							Convert(const Array<IndexedTriangle> &inTriangles, const Array<AABBTreeBuilder::Node> &inNodes, const VertexList &inVertices, const AABBTreeBuilder::Node *inRoot, bool inStoreUserData, const char *&outError)
 	{
 	{
 		const typename NodeCodec::EncodingContext node_ctx;
 		const typename NodeCodec::EncodingContext node_ctx;
 		typename TriangleCodec::EncodingContext tri_ctx(inVertices);
 		typename TriangleCodec::EncodingContext tri_ctx(inVertices);
 
 
 		// Estimate the amount of memory required
 		// Estimate the amount of memory required
-		uint tri_count = inRoot->GetTriangleCountInTree();
-		uint node_count = inRoot->GetNodeCount();
+		uint tri_count = inRoot->GetTriangleCountInTree(inNodes);
+		uint node_count = inRoot->GetNodeCount(inNodes);
 		uint nodes_size = node_ctx.GetPessimisticMemoryEstimate(node_count);
 		uint nodes_size = node_ctx.GetPessimisticMemoryEstimate(node_count);
 		uint total_size = HeaderSize + TriangleHeaderSize + nodes_size + tri_ctx.GetPessimisticMemoryEstimate(tri_count, inStoreUserData);
 		uint total_size = HeaderSize + TriangleHeaderSize + nodes_size + tri_ctx.GetPessimisticMemoryEstimate(tri_count, inStoreUserData);
 		mTree.reserve(total_size);
 		mTree.reserve(total_size);
@@ -70,8 +64,8 @@ public:
 			uint *							mParentTrianglesStart = nullptr;			// Where to store mTriangleStart (to patch mChildTrianglesStart of my parent)
 			uint *							mParentTrianglesStart = nullptr;			// Where to store mTriangleStart (to patch mChildTrianglesStart of my parent)
 		};
 		};
 
 
-		Deque<NodeData *> to_process;
-		Deque<NodeData *> to_process_triangles;
+		Array<NodeData *> to_process;
+		Array<NodeData *> to_process_triangles;
 		Array<NodeData> node_list;
 		Array<NodeData> node_list;
 
 
 		node_list.reserve(node_count); // Needed to ensure that array is not reallocated, so we can keep pointers in the array
 		node_list.reserve(node_count); // Needed to ensure that array is not reallocated, so we can keep pointers in the array
@@ -100,7 +94,7 @@ public:
 
 
 				// Collect the first NumChildrenPerNode sub-nodes in the tree
 				// Collect the first NumChildrenPerNode sub-nodes in the tree
 				child_nodes.clear(); // Won't free the memory
 				child_nodes.clear(); // Won't free the memory
-				node_data->mNode->GetNChildren(NumChildrenPerNode, child_nodes);
+				node_data->mNode->GetNChildren(inNodes, NumChildrenPerNode, child_nodes);
 				node_data->mNumChildren = (uint)child_nodes.size();
 				node_data->mNumChildren = (uint)child_nodes.size();
 
 
 				// Fill in default child bounds
 				// Fill in default child bounds
@@ -157,7 +151,7 @@ public:
 				else
 				else
 				{
 				{
 					// Add triangles
 					// Add triangles
-					node_data->mTriangleStart = tri_ctx.Pack(node_data->mNode->mTriangles, inStoreUserData, mTree, outError);
+					node_data->mTriangleStart = tri_ctx.Pack(&inTriangles[node_data->mNode->mTrianglesBegin], node_data->mNode->mNumTriangles, inStoreUserData, mTree, outError);
 					if (node_data->mTriangleStart == uint(-1))
 					if (node_data->mTriangleStart == uint(-1))
 						return false;
 						return false;
 				}
 				}

+ 10 - 9
Jolt/AABBTree/TriangleCodec/TriangleCodecIndexed8BitPackSOA4Flags.h

@@ -149,20 +149,21 @@ public:
 
 
 		/// Pack the triangles in inContainer to ioBuffer. This stores the mMaterialIndex of a triangle in the 8 bit flags.
 		/// Pack the triangles in inContainer to ioBuffer. This stores the mMaterialIndex of a triangle in the 8 bit flags.
 		/// Returns uint(-1) on error.
 		/// Returns uint(-1) on error.
-		uint						Pack(const IndexedTriangleList &inTriangles, bool inStoreUserData, ByteBuffer &ioBuffer, const char *&outError)
+		uint						Pack(const IndexedTriangle *inTriangles, uint inNumTriangles, bool inStoreUserData, ByteBuffer &ioBuffer, const char *&outError)
 		{
 		{
+			JPH_ASSERT(inNumTriangles > 0);
+
 			// Determine position of triangles start
 			// Determine position of triangles start
 			uint offset = (uint)ioBuffer.size();
 			uint offset = (uint)ioBuffer.size();
 
 
 			// Update stats
 			// Update stats
-			uint tri_count = (uint)inTriangles.size();
-			mNumTriangles += tri_count;
+			mNumTriangles += inNumTriangles;
 
 
 			// Allocate triangle block header
 			// Allocate triangle block header
 			TriangleBlockHeader *header = ioBuffer.Allocate<TriangleBlockHeader>();
 			TriangleBlockHeader *header = ioBuffer.Allocate<TriangleBlockHeader>();
 
 
 			// Compute first vertex that this batch will use (ensuring there's enough room if none of the vertices are shared)
 			// Compute first vertex that this batch will use (ensuring there's enough room if none of the vertices are shared)
-			uint start_vertex = Clamp((int)mVertices.size() - 256 + (int)tri_count * 3, 0, (int)mVertices.size());
+			uint start_vertex = Clamp((int)mVertices.size() - 256 + (int)inNumTriangles * 3, 0, (int)mVertices.size());
 
 
 			// Store the start vertex offset, this will later be patched to give the delta offset relative to the triangle block
 			// Store the start vertex offset, this will later be patched to give the delta offset relative to the triangle block
 			mOffsetsToPatch.push_back(uint((uint8 *)&header->mFlags - &ioBuffer[0]));
 			mOffsetsToPatch.push_back(uint((uint8 *)&header->mFlags - &ioBuffer[0]));
@@ -170,7 +171,7 @@ public:
 			JPH_ASSERT(header->mFlags <= OFFSET_TO_VERTICES_MASK, "Offset to vertices doesn't fit");
 			JPH_ASSERT(header->mFlags <= OFFSET_TO_VERTICES_MASK, "Offset to vertices doesn't fit");
 
 
 			// When we store user data we need to store the offset to the user data in TriangleBlocks
 			// When we store user data we need to store the offset to the user data in TriangleBlocks
-			uint padded_triangle_count = AlignUp(tri_count, 4);
+			uint padded_triangle_count = AlignUp(inNumTriangles, 4);
 			if (inStoreUserData)
 			if (inStoreUserData)
 			{
 			{
 				uint32 num_blocks = padded_triangle_count >> 2;
 				uint32 num_blocks = padded_triangle_count >> 2;
@@ -186,8 +187,8 @@ public:
 					for (uint block_tri_idx = 0; block_tri_idx < 4; ++block_tri_idx)
 					for (uint block_tri_idx = 0; block_tri_idx < 4; ++block_tri_idx)
 					{
 					{
 						// Fetch vertex index. Create degenerate triangles for padding triangles.
 						// Fetch vertex index. Create degenerate triangles for padding triangles.
-						bool triangle_available = t + block_tri_idx < tri_count;
-						uint32 src_vertex_index = triangle_available? inTriangles[t + block_tri_idx].mIdx[vertex_nr] : inTriangles[tri_count - 1].mIdx[0];
+						bool triangle_available = t + block_tri_idx < inNumTriangles;
+						uint32 src_vertex_index = triangle_available? inTriangles[t + block_tri_idx].mIdx[vertex_nr] : inTriangles[inNumTriangles - 1].mIdx[0];
 
 
 						// Check if we've seen this vertex before and if it is in the range that we can encode
 						// Check if we've seen this vertex before and if it is in the range that we can encode
 						uint32 &vertex_index = mVertexMap[src_vertex_index];
 						uint32 &vertex_index = mVertexMap[src_vertex_index];
@@ -221,8 +222,8 @@ public:
 			// Store user data
 			// Store user data
 			if (inStoreUserData)
 			if (inStoreUserData)
 			{
 			{
-				uint32 *user_data = ioBuffer.Allocate<uint32>(tri_count);
-				for (uint t = 0; t < tri_count; ++t)
+				uint32 *user_data = ioBuffer.Allocate<uint32>(inNumTriangles);
+				for (uint t = 0; t < inNumTriangles; ++t)
 					user_data[t] = inTriangles[t].mUserData;
 					user_data[t] = inTriangles[t].mUserData;
 			}
 			}
 
 

+ 1 - 4
Jolt/Physics/Collision/Shape/MeshShape.cpp

@@ -200,16 +200,13 @@ MeshShape::MeshShape(const MeshShapeSettings &inSettings, ShapeResult &outResult
 	// Convert to buffer
 	// Convert to buffer
 	AABBTreeToBuffer<TriangleCodec, NodeCodec> buffer;
 	AABBTreeToBuffer<TriangleCodec, NodeCodec> buffer;
 	const char *error = nullptr;
 	const char *error = nullptr;
-	if (!buffer.Convert(inSettings.mTriangleVertices, root, inSettings.mPerTriangleUserData, error))
+	if (!buffer.Convert(builder.GetTriangles(), builder.GetNodes(), inSettings.mTriangleVertices, root, inSettings.mPerTriangleUserData, error))
 	{
 	{
 		outResult.SetError(error);
 		outResult.SetError(error);
 		delete root;
 		delete root;
 		return;
 		return;
 	}
 	}
 
 
-	// Kill tree
-	delete root;
-
 	// Move data to this class
 	// Move data to this class
 	mTree.swap(buffer.GetBuffer());
 	mTree.swap(buffer.GetBuffer());