mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-04 07:31:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			358 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			358 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
Bullet Continuous Collision Detection and Physics Library
 | 
						|
Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org
 | 
						|
 | 
						|
This software is provided 'as-is', without any express or implied warranty.
 | 
						|
In no event will the authors be held liable for any damages arising from the use of this software.
 | 
						|
Permission is granted to anyone to use this software for any purpose, 
 | 
						|
including commercial applications, and to alter it and redistribute it freely, 
 | 
						|
subject to the following restrictions:
 | 
						|
 | 
						|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
 | 
						|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
 | 
						|
3. This notice may not be removed or altered from any source distribution.
 | 
						|
*/
 | 
						|
 | 
						|
#include "b3OptimizedBvh.h"
 | 
						|
#include "b3StridingMeshInterface.h"
 | 
						|
#include "Bullet3Geometry/b3AabbUtil.h"
 | 
						|
 | 
						|
b3OptimizedBvh::b3OptimizedBvh()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
b3OptimizedBvh::~b3OptimizedBvh()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void b3OptimizedBvh::build(b3StridingMeshInterface* triangles, bool useQuantizedAabbCompression, const b3Vector3& bvhAabbMin, const b3Vector3& bvhAabbMax)
 | 
						|
{
 | 
						|
	m_useQuantization = useQuantizedAabbCompression;
 | 
						|
 | 
						|
	// NodeArray	triangleNodes;
 | 
						|
 | 
						|
	struct NodeTriangleCallback : public b3InternalTriangleIndexCallback
 | 
						|
	{
 | 
						|
		NodeArray& m_triangleNodes;
 | 
						|
 | 
						|
		NodeTriangleCallback& operator=(NodeTriangleCallback& other)
 | 
						|
		{
 | 
						|
			m_triangleNodes.copyFromArray(other.m_triangleNodes);
 | 
						|
			return *this;
 | 
						|
		}
 | 
						|
 | 
						|
		NodeTriangleCallback(NodeArray& triangleNodes)
 | 
						|
			: m_triangleNodes(triangleNodes)
 | 
						|
		{
 | 
						|
		}
 | 
						|
 | 
						|
		virtual void internalProcessTriangleIndex(b3Vector3* triangle, int partId, int triangleIndex)
 | 
						|
		{
 | 
						|
			b3OptimizedBvhNode node;
 | 
						|
			b3Vector3 aabbMin, aabbMax;
 | 
						|
			aabbMin.setValue(b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT));
 | 
						|
			aabbMax.setValue(b3Scalar(-B3_LARGE_FLOAT), b3Scalar(-B3_LARGE_FLOAT), b3Scalar(-B3_LARGE_FLOAT));
 | 
						|
			aabbMin.setMin(triangle[0]);
 | 
						|
			aabbMax.setMax(triangle[0]);
 | 
						|
			aabbMin.setMin(triangle[1]);
 | 
						|
			aabbMax.setMax(triangle[1]);
 | 
						|
			aabbMin.setMin(triangle[2]);
 | 
						|
			aabbMax.setMax(triangle[2]);
 | 
						|
 | 
						|
			//with quantization?
 | 
						|
			node.m_aabbMinOrg = aabbMin;
 | 
						|
			node.m_aabbMaxOrg = aabbMax;
 | 
						|
 | 
						|
			node.m_escapeIndex = -1;
 | 
						|
 | 
						|
			//for child nodes
 | 
						|
			node.m_subPart = partId;
 | 
						|
			node.m_triangleIndex = triangleIndex;
 | 
						|
			m_triangleNodes.push_back(node);
 | 
						|
		}
 | 
						|
	};
 | 
						|
	struct QuantizedNodeTriangleCallback : public b3InternalTriangleIndexCallback
 | 
						|
	{
 | 
						|
		QuantizedNodeArray& m_triangleNodes;
 | 
						|
		const b3QuantizedBvh* m_optimizedTree;  // for quantization
 | 
						|
 | 
						|
		QuantizedNodeTriangleCallback& operator=(QuantizedNodeTriangleCallback& other)
 | 
						|
		{
 | 
						|
			m_triangleNodes.copyFromArray(other.m_triangleNodes);
 | 
						|
			m_optimizedTree = other.m_optimizedTree;
 | 
						|
			return *this;
 | 
						|
		}
 | 
						|
 | 
						|
		QuantizedNodeTriangleCallback(QuantizedNodeArray& triangleNodes, const b3QuantizedBvh* tree)
 | 
						|
			: m_triangleNodes(triangleNodes), m_optimizedTree(tree)
 | 
						|
		{
 | 
						|
		}
 | 
						|
 | 
						|
		virtual void internalProcessTriangleIndex(b3Vector3* triangle, int partId, int triangleIndex)
 | 
						|
		{
 | 
						|
			// The partId and triangle index must fit in the same (positive) integer
 | 
						|
			b3Assert(partId < (1 << MAX_NUM_PARTS_IN_BITS));
 | 
						|
			b3Assert(triangleIndex < (1 << (31 - MAX_NUM_PARTS_IN_BITS)));
 | 
						|
			//negative indices are reserved for escapeIndex
 | 
						|
			b3Assert(triangleIndex >= 0);
 | 
						|
 | 
						|
			b3QuantizedBvhNode node;
 | 
						|
			b3Vector3 aabbMin, aabbMax;
 | 
						|
			aabbMin.setValue(b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT));
 | 
						|
			aabbMax.setValue(b3Scalar(-B3_LARGE_FLOAT), b3Scalar(-B3_LARGE_FLOAT), b3Scalar(-B3_LARGE_FLOAT));
 | 
						|
			aabbMin.setMin(triangle[0]);
 | 
						|
			aabbMax.setMax(triangle[0]);
 | 
						|
			aabbMin.setMin(triangle[1]);
 | 
						|
			aabbMax.setMax(triangle[1]);
 | 
						|
			aabbMin.setMin(triangle[2]);
 | 
						|
			aabbMax.setMax(triangle[2]);
 | 
						|
 | 
						|
			//PCK: add these checks for zero dimensions of aabb
 | 
						|
			const b3Scalar MIN_AABB_DIMENSION = b3Scalar(0.002);
 | 
						|
			const b3Scalar MIN_AABB_HALF_DIMENSION = b3Scalar(0.001);
 | 
						|
			if (aabbMax.getX() - aabbMin.getX() < MIN_AABB_DIMENSION)
 | 
						|
			{
 | 
						|
				aabbMax.setX(aabbMax.getX() + MIN_AABB_HALF_DIMENSION);
 | 
						|
				aabbMin.setX(aabbMin.getX() - MIN_AABB_HALF_DIMENSION);
 | 
						|
			}
 | 
						|
			if (aabbMax.getY() - aabbMin.getY() < MIN_AABB_DIMENSION)
 | 
						|
			{
 | 
						|
				aabbMax.setY(aabbMax.getY() + MIN_AABB_HALF_DIMENSION);
 | 
						|
				aabbMin.setY(aabbMin.getY() - MIN_AABB_HALF_DIMENSION);
 | 
						|
			}
 | 
						|
			if (aabbMax.getZ() - aabbMin.getZ() < MIN_AABB_DIMENSION)
 | 
						|
			{
 | 
						|
				aabbMax.setZ(aabbMax.getZ() + MIN_AABB_HALF_DIMENSION);
 | 
						|
				aabbMin.setZ(aabbMin.getZ() - MIN_AABB_HALF_DIMENSION);
 | 
						|
			}
 | 
						|
 | 
						|
			m_optimizedTree->quantize(&node.m_quantizedAabbMin[0], aabbMin, 0);
 | 
						|
			m_optimizedTree->quantize(&node.m_quantizedAabbMax[0], aabbMax, 1);
 | 
						|
 | 
						|
			node.m_escapeIndexOrTriangleIndex = (partId << (31 - MAX_NUM_PARTS_IN_BITS)) | triangleIndex;
 | 
						|
 | 
						|
			m_triangleNodes.push_back(node);
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	int numLeafNodes = 0;
 | 
						|
 | 
						|
	if (m_useQuantization)
 | 
						|
	{
 | 
						|
		//initialize quantization values
 | 
						|
		setQuantizationValues(bvhAabbMin, bvhAabbMax);
 | 
						|
 | 
						|
		QuantizedNodeTriangleCallback callback(m_quantizedLeafNodes, this);
 | 
						|
 | 
						|
		triangles->InternalProcessAllTriangles(&callback, m_bvhAabbMin, m_bvhAabbMax);
 | 
						|
 | 
						|
		//now we have an array of leafnodes in m_leafNodes
 | 
						|
		numLeafNodes = m_quantizedLeafNodes.size();
 | 
						|
 | 
						|
		m_quantizedContiguousNodes.resize(2 * numLeafNodes);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		NodeTriangleCallback callback(m_leafNodes);
 | 
						|
 | 
						|
		b3Vector3 aabbMin = b3MakeVector3(b3Scalar(-B3_LARGE_FLOAT), b3Scalar(-B3_LARGE_FLOAT), b3Scalar(-B3_LARGE_FLOAT));
 | 
						|
		b3Vector3 aabbMax = b3MakeVector3(b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT));
 | 
						|
 | 
						|
		triangles->InternalProcessAllTriangles(&callback, aabbMin, aabbMax);
 | 
						|
 | 
						|
		//now we have an array of leafnodes in m_leafNodes
 | 
						|
		numLeafNodes = m_leafNodes.size();
 | 
						|
 | 
						|
		m_contiguousNodes.resize(2 * numLeafNodes);
 | 
						|
	}
 | 
						|
 | 
						|
	m_curNodeIndex = 0;
 | 
						|
 | 
						|
	buildTree(0, numLeafNodes);
 | 
						|
 | 
						|
	///if the entire tree is small then subtree size, we need to create a header info for the tree
 | 
						|
	if (m_useQuantization && !m_SubtreeHeaders.size())
 | 
						|
	{
 | 
						|
		b3BvhSubtreeInfo& subtree = m_SubtreeHeaders.expand();
 | 
						|
		subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[0]);
 | 
						|
		subtree.m_rootNodeIndex = 0;
 | 
						|
		subtree.m_subtreeSize = m_quantizedContiguousNodes[0].isLeafNode() ? 1 : m_quantizedContiguousNodes[0].getEscapeIndex();
 | 
						|
	}
 | 
						|
 | 
						|
	//PCK: update the copy of the size
 | 
						|
	m_subtreeHeaderCount = m_SubtreeHeaders.size();
 | 
						|
 | 
						|
	//PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary
 | 
						|
	m_quantizedLeafNodes.clear();
 | 
						|
	m_leafNodes.clear();
 | 
						|
}
 | 
						|
 | 
						|
void b3OptimizedBvh::refit(b3StridingMeshInterface* meshInterface, const b3Vector3& aabbMin, const b3Vector3& aabbMax)
 | 
						|
{
 | 
						|
	if (m_useQuantization)
 | 
						|
	{
 | 
						|
		setQuantizationValues(aabbMin, aabbMax);
 | 
						|
 | 
						|
		updateBvhNodes(meshInterface, 0, m_curNodeIndex, 0);
 | 
						|
 | 
						|
		///now update all subtree headers
 | 
						|
 | 
						|
		int i;
 | 
						|
		for (i = 0; i < m_SubtreeHeaders.size(); i++)
 | 
						|
		{
 | 
						|
			b3BvhSubtreeInfo& subtree = m_SubtreeHeaders[i];
 | 
						|
			subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void b3OptimizedBvh::refitPartial(b3StridingMeshInterface* meshInterface, const b3Vector3& aabbMin, const b3Vector3& aabbMax)
 | 
						|
{
 | 
						|
	//incrementally initialize quantization values
 | 
						|
	b3Assert(m_useQuantization);
 | 
						|
 | 
						|
	b3Assert(aabbMin.getX() > m_bvhAabbMin.getX());
 | 
						|
	b3Assert(aabbMin.getY() > m_bvhAabbMin.getY());
 | 
						|
	b3Assert(aabbMin.getZ() > m_bvhAabbMin.getZ());
 | 
						|
 | 
						|
	b3Assert(aabbMax.getX() < m_bvhAabbMax.getX());
 | 
						|
	b3Assert(aabbMax.getY() < m_bvhAabbMax.getY());
 | 
						|
	b3Assert(aabbMax.getZ() < m_bvhAabbMax.getZ());
 | 
						|
 | 
						|
	///we should update all quantization values, using updateBvhNodes(meshInterface);
 | 
						|
	///but we only update chunks that overlap the given aabb
 | 
						|
 | 
						|
	unsigned short quantizedQueryAabbMin[3];
 | 
						|
	unsigned short quantizedQueryAabbMax[3];
 | 
						|
 | 
						|
	quantize(&quantizedQueryAabbMin[0], aabbMin, 0);
 | 
						|
	quantize(&quantizedQueryAabbMax[0], aabbMax, 1);
 | 
						|
 | 
						|
	int i;
 | 
						|
	for (i = 0; i < this->m_SubtreeHeaders.size(); i++)
 | 
						|
	{
 | 
						|
		b3BvhSubtreeInfo& subtree = m_SubtreeHeaders[i];
 | 
						|
 | 
						|
		//PCK: unsigned instead of bool
 | 
						|
		unsigned overlap = b3TestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin, quantizedQueryAabbMax, subtree.m_quantizedAabbMin, subtree.m_quantizedAabbMax);
 | 
						|
		if (overlap != 0)
 | 
						|
		{
 | 
						|
			updateBvhNodes(meshInterface, subtree.m_rootNodeIndex, subtree.m_rootNodeIndex + subtree.m_subtreeSize, i);
 | 
						|
 | 
						|
			subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void b3OptimizedBvh::updateBvhNodes(b3StridingMeshInterface* meshInterface, int firstNode, int endNode, int index)
 | 
						|
{
 | 
						|
	(void)index;
 | 
						|
 | 
						|
	b3Assert(m_useQuantization);
 | 
						|
 | 
						|
	int curNodeSubPart = -1;
 | 
						|
 | 
						|
	//get access info to trianglemesh data
 | 
						|
	const unsigned char* vertexbase = 0;
 | 
						|
	int numverts = 0;
 | 
						|
	PHY_ScalarType type = PHY_INTEGER;
 | 
						|
	int stride = 0;
 | 
						|
	const unsigned char* indexbase = 0;
 | 
						|
	int indexstride = 0;
 | 
						|
	int numfaces = 0;
 | 
						|
	PHY_ScalarType indicestype = PHY_INTEGER;
 | 
						|
 | 
						|
	b3Vector3 triangleVerts[3];
 | 
						|
	b3Vector3 aabbMin, aabbMax;
 | 
						|
	const b3Vector3& meshScaling = meshInterface->getScaling();
 | 
						|
 | 
						|
	int i;
 | 
						|
	for (i = endNode - 1; i >= firstNode; i--)
 | 
						|
	{
 | 
						|
		b3QuantizedBvhNode& curNode = m_quantizedContiguousNodes[i];
 | 
						|
		if (curNode.isLeafNode())
 | 
						|
		{
 | 
						|
			//recalc aabb from triangle data
 | 
						|
			int nodeSubPart = curNode.getPartId();
 | 
						|
			int nodeTriangleIndex = curNode.getTriangleIndex();
 | 
						|
			if (nodeSubPart != curNodeSubPart)
 | 
						|
			{
 | 
						|
				if (curNodeSubPart >= 0)
 | 
						|
					meshInterface->unLockReadOnlyVertexBase(curNodeSubPart);
 | 
						|
				meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase, numverts, type, stride, &indexbase, indexstride, numfaces, indicestype, nodeSubPart);
 | 
						|
 | 
						|
				curNodeSubPart = nodeSubPart;
 | 
						|
				b3Assert(indicestype == PHY_INTEGER || indicestype == PHY_SHORT);
 | 
						|
			}
 | 
						|
			//triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts,
 | 
						|
 | 
						|
			unsigned int* gfxbase = (unsigned int*)(indexbase + nodeTriangleIndex * indexstride);
 | 
						|
 | 
						|
			for (int j = 2; j >= 0; j--)
 | 
						|
			{
 | 
						|
				int graphicsindex = indicestype == PHY_SHORT ? ((unsigned short*)gfxbase)[j] : gfxbase[j];
 | 
						|
				if (type == PHY_FLOAT)
 | 
						|
				{
 | 
						|
					float* graphicsbase = (float*)(vertexbase + graphicsindex * stride);
 | 
						|
					triangleVerts[j] = b3MakeVector3(
 | 
						|
						graphicsbase[0] * meshScaling.getX(),
 | 
						|
						graphicsbase[1] * meshScaling.getY(),
 | 
						|
						graphicsbase[2] * meshScaling.getZ());
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					double* graphicsbase = (double*)(vertexbase + graphicsindex * stride);
 | 
						|
					triangleVerts[j] = b3MakeVector3(b3Scalar(graphicsbase[0] * meshScaling.getX()), b3Scalar(graphicsbase[1] * meshScaling.getY()), b3Scalar(graphicsbase[2] * meshScaling.getZ()));
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			aabbMin.setValue(b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT), b3Scalar(B3_LARGE_FLOAT));
 | 
						|
			aabbMax.setValue(b3Scalar(-B3_LARGE_FLOAT), b3Scalar(-B3_LARGE_FLOAT), b3Scalar(-B3_LARGE_FLOAT));
 | 
						|
			aabbMin.setMin(triangleVerts[0]);
 | 
						|
			aabbMax.setMax(triangleVerts[0]);
 | 
						|
			aabbMin.setMin(triangleVerts[1]);
 | 
						|
			aabbMax.setMax(triangleVerts[1]);
 | 
						|
			aabbMin.setMin(triangleVerts[2]);
 | 
						|
			aabbMax.setMax(triangleVerts[2]);
 | 
						|
 | 
						|
			quantize(&curNode.m_quantizedAabbMin[0], aabbMin, 0);
 | 
						|
			quantize(&curNode.m_quantizedAabbMax[0], aabbMax, 1);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			//combine aabb from both children
 | 
						|
 | 
						|
			b3QuantizedBvhNode* leftChildNode = &m_quantizedContiguousNodes[i + 1];
 | 
						|
 | 
						|
			b3QuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? &m_quantizedContiguousNodes[i + 2] : &m_quantizedContiguousNodes[i + 1 + leftChildNode->getEscapeIndex()];
 | 
						|
 | 
						|
			{
 | 
						|
				for (int i = 0; i < 3; i++)
 | 
						|
				{
 | 
						|
					curNode.m_quantizedAabbMin[i] = leftChildNode->m_quantizedAabbMin[i];
 | 
						|
					if (curNode.m_quantizedAabbMin[i] > rightChildNode->m_quantizedAabbMin[i])
 | 
						|
						curNode.m_quantizedAabbMin[i] = rightChildNode->m_quantizedAabbMin[i];
 | 
						|
 | 
						|
					curNode.m_quantizedAabbMax[i] = leftChildNode->m_quantizedAabbMax[i];
 | 
						|
					if (curNode.m_quantizedAabbMax[i] < rightChildNode->m_quantizedAabbMax[i])
 | 
						|
						curNode.m_quantizedAabbMax[i] = rightChildNode->m_quantizedAabbMax[i];
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (curNodeSubPart >= 0)
 | 
						|
		meshInterface->unLockReadOnlyVertexBase(curNodeSubPart);
 | 
						|
}
 | 
						|
 | 
						|
///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place'
 | 
						|
b3OptimizedBvh* b3OptimizedBvh::deSerializeInPlace(void* i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian)
 | 
						|
{
 | 
						|
	b3QuantizedBvh* bvh = b3QuantizedBvh::deSerializeInPlace(i_alignedDataBuffer, i_dataBufferSize, i_swapEndian);
 | 
						|
 | 
						|
	//we don't add additional data so just do a static upcast
 | 
						|
	return static_cast<b3OptimizedBvh*>(bvh);
 | 
						|
}
 |