PxU32 PxParticleExt::buildBoundsHash(PxU32* sortedParticleIndices, ParticleBounds* particleBounds, const PxStrideIterator<const PxVec3>& positionBuffer, const PxU32 validParticleRange, const PxU32* validParticleBitmap, const PxU32 hashSize, const PxU32 maxBounds, const PxReal gridSpacing) { // test if hash size is a multiple of 2 PX_ASSERT((((hashSize - 1) ^ hashSize) + 1) == (2 * hashSize)); PX_ASSERT(maxBounds <= hashSize); PxReal cellSizeInv = 1.0f / gridSpacing; Ps::Array<PxU32> particleToCellMap PX_DEBUG_EXP("buildBoundsHashCellMap"); particleToCellMap.resize(validParticleRange); // initialize cells Ps::Array<Cell> cells PX_DEBUG_EXP("buildBoundsCells"); cells.resize(hashSize); PxMemSet(cells.begin(), sInvalidIndex, sizeof(Cell) * hashSize); // count number of particles per cell PxU32 entryCounter = 0; if (validParticleRange > 0) { for (PxU32 w = 0; w <= (validParticleRange-1) >> 5; w++) for (PxU32 b = validParticleBitmap[w]; b; b &= b-1) { PxU32 index = (w<<5|Ps::lowestSetBit(b)); const PxVec3& position = positionBuffer[index]; PxU32& cellIndex = particleToCellMap[index]; cellIndex = sInvalidIndex; // initialize to invalid in case we reach maxBounds if (entryCounter < maxBounds) { CellCoords particleCoords; particleCoords.set(position, cellSizeInv); cellIndex = getEntry(particleCoords, hashSize, cells.begin()); PX_ASSERT(cellIndex != sInvalidIndex); Cell& cell = cells[cellIndex]; if (cell.size == sInvalidIndex) { // this is the first particle in this cell cell.coords = particleCoords; cell.aabb = PxBounds3(position, position); cell.size = 1; ++entryCounter; } else { // the cell is already occupied cell.aabb.include(position); ++cell.size; } } } } // accumulate start indices from cell size histogram and write to the user's particleBounds buffer PxU32 numBounds = 0; for (PxU32 i = 0, counter = 0; i < cells.size(); i++) { Cell& cell = cells[i]; if (cell.size != sInvalidIndex) { cell.start = counter; counter += cell.size; PxParticleExt::ParticleBounds& cellBounds = particleBounds[numBounds++]; PX_ASSERT(cell.aabb.isValid()); cellBounds.bounds = cell.aabb; cellBounds.firstParticle = cell.start; cellBounds.numParticles = cell.size; cell.size = 0; } } // sort output particle indices by cell if (validParticleRange > 0) { for (PxU32 w = 0; w <= (validParticleRange-1) >> 5; w++) for (PxU32 b = validParticleBitmap[w]; b; b &= b-1) { PxU32 index = (w<<5|Ps::lowestSetBit(b)); PxU32 cellIndex = particleToCellMap[index]; if (cellIndex != sInvalidIndex) { Cell& cell = cells[cellIndex]; PX_ASSERT(cell.start != sInvalidIndex && cell.size != sInvalidIndex); sortedParticleIndices[cell.start + cell.size] = index; ++cell.size; } } } return numBounds; }
void DeformableMesh::weldMesh() { mVertexToParticleMap.resize(mVertexPositions.size()); if (mPrimitiveType == PxDeformablePrimitiveType::eTRIANGLE && (mFlags & PxDeformableMeshFlag::eWELD_VERTICES) != 0) { Ps::Array<int> order PX_DEBUG_EXP("defoMeshOrder"); order.resize(mVertexPositions.size()); for (PxU32 i = 0; i < order.size(); i++) order[i] = i; // sort vertices by their x coordinate Ps::sort(order.begin(), order.size(), WeldComparator(mVertexPositions)); // generate permutation table which welds similar vertices for (PxU32 i = 0; i < mVertexPositions.size(); i++) mVertexToParticleMap[i] = PX_MAX_U32; int newNr = 0; PxReal mWeldingDistanceSq = mWeldingDistance * mWeldingDistance; for (PxU32 i = 0; i < mVertexPositions.size(); i++) { int oldNr = order[i]; if (mVertexToParticleMap[oldNr] != PX_MAX_U32) continue; mVertexToParticleMap[oldNr] = newNr; PxVec3 vi = mVertexPositions[oldNr]; PxU32 j = i+1; while (j < mVertexPositions.size() && PxAbs(vi.x - mVertexPositions[order[j]].x) <= mWeldingDistance) { oldNr = order[j]; if ((vi-mVertexPositions[oldNr]).magnitudeSquared() <= mWeldingDistanceSq) { if (mVertexToParticleMap[oldNr] == PX_MAX_U32) mVertexToParticleMap[oldNr] = newNr; } j++; } newNr++; } mNumWeldedVertices = newNr; } else { // Welding not enabled. We use an identity permutation. for (PxU32 i = 0; i < mVertexToParticleMap.size(); i++) mVertexToParticleMap[i] = i; #if 0 Ps::Array<int> order; order.resize(mVertexPositions.size()); for (PxU32 i = 0; i < order.size(); i++) order[i] = i; Ps::sort(order.begin(), order.size(), WeldComparator(mVertexPositions)); for (PxU32 i = 0; i < mVertexToParticleMap.size(); i++) mVertexToParticleMap[i] = order[i]; #endif mNumWeldedVertices = mVertexPositions.size(); } mWeldedVertices.resize(mNumWeldedVertices); for (PxU32 i = 0; i < mVertexPositions.size(); i++) mWeldedVertices[mVertexToParticleMap[i]] = mVertexPositions[i]; }