123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- /*
- 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;
- }
- //triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts,
- unsigned int* gfxbase = (unsigned int*)(indexbase + nodeTriangleIndex * indexstride);
- for (int j = 2; j >= 0; j--)
- {
- int graphicsindex;
- switch (indicestype) {
- case PHY_INTEGER: graphicsindex = gfxbase[j]; break;
- case PHY_SHORT: graphicsindex = ((unsigned short*)gfxbase)[j]; break;
- case PHY_UCHAR: graphicsindex = ((unsigned char*)gfxbase)[j]; break;
- default: b3Assert(0);
- }
- 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);
- }
|