PxQuat slerp(const PxReal t, const PxQuat& left, const PxQuat& right) { const PxReal quatEpsilon = (PxReal(1.0e-8f)); PxReal cosine = left.dot(right); PxReal sign = PxReal(1); if (cosine < 0) { cosine = -cosine; sign = PxReal(-1); } PxReal sine = PxReal(1) - cosine*cosine; if(sine>=quatEpsilon*quatEpsilon) { sine = PxSqrt(sine); const PxReal angle = PxAtan2(sine, cosine); const PxReal i_sin_angle = PxReal(1) / sine; const PxReal leftw = PxSin(angle*(PxReal(1)-t)) * i_sin_angle; const PxReal rightw = PxSin(angle * t) * i_sin_angle * sign; return left * leftw + right * rightw; } return left; }
void FixedStepper::substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize) { if(mAccumulator > mFixedSubStepSize) mAccumulator = 0.0f; // don't step less than the step size, just accumulate mAccumulator += stepSize; if(mAccumulator < mFixedSubStepSize) { substepCount = 0; return; } substepSize = mFixedSubStepSize; substepCount = PxMin(PxU32(mAccumulator/mFixedSubStepSize), mMaxSubSteps); mAccumulator -= PxReal(substepCount)*substepSize; }
void VariableStepper::substepStrategy(const PxReal stepSize, PxU32& substepCount, PxReal& substepSize) { if(mAccumulator > mMaxSubStepSize) mAccumulator = 0.0f; // don't step less than the min step size, just accumulate mAccumulator += stepSize; if(mAccumulator < mMinSubStepSize) { substepCount = 0; return; } substepCount = PxMin(PxU32(PxCeil(mAccumulator/mMaxSubStepSize)), mMaxSubSteps); substepSize = PxMin(mAccumulator/substepCount, mMaxSubStepSize); mAccumulator -= PxReal(substepCount)*substepSize; }
void PxsFluidDynamics::updatePacketLocalHash(PxsSphUpdateType updateType, PxVec3* forceBuf, PxsFluidParticle* particles, const PxsParticleCell& packet, const PxsFluidPacketSections& packetSections, const PxsFluidPacketHaloRegions& haloRegions, PxsFluidDynamicsTempBuffers& tempBuffers) { // Particle index lists for local hash of particle cells (for two subpackets A and B). PxU32* particleIndicesSpA = tempBuffers.indicesSubpacketA; PxU32* particleIndicesSpB = tempBuffers.indicesSubpacketB; // Local hash tables for particle cells (for two subpackets A and B). PxsParticleCell* particleCellsSpA = tempBuffers.cellHashTableSubpacketA; PxsParticleCell* particleCellsSpB = tempBuffers.cellHashTableSubpacketB; PxVec3 packetCorner = PxVec3(PxReal(packet.coords.x), PxReal(packet.coords.y), PxReal(packet.coords.z)) * mParams.packetSize; PxU32 particlesLeftA0 = packet.numParticles; PxsFluidParticle* particlesSpA0 = particles + packet.firstParticle; PxVec3* forceBufA0 = forceBuf + packet.firstParticle; while (particlesLeftA0) { PxU32 numParticlesSpA = PxMin(particlesLeftA0, static_cast<PxU32>(PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY)); // Make sure the number of hash buckets is a power of 2 (requirement for the used hash function) const PxU32 numCellHashBucketsSpA = Ps::nextPowerOfTwo(numParticlesSpA + 1); PX_ASSERT(numCellHashBucketsSpA <= tempBuffers.cellHashMaxSize); // Get local cell hash for the current subpacket PxsFluidSpatialHash::buildLocalHash(particlesSpA0, numParticlesSpA, particleCellsSpA, particleIndicesSpA, tempBuffers.hashKeys, numCellHashBucketsSpA, mParams.cellSizeInv, packetCorner); //--------------------------------------------------------------------------------------------------- // // Compute particle interactions between particles within the current subpacket. // updateCellsSubpacket(updateType, forceBufA0, particlesSpA0, particleCellsSpA, particleIndicesSpA, numCellHashBucketsSpA, mParams, tempBuffers); //--------------------------------------------------------------------------------------------------- // // Compute particle interactions between particles of current subpacket and particles // of other subpackets within the same packet (i.e., we process all subpacket pairs). // PxU32 particlesLeftB = particlesLeftA0 - numParticlesSpA; PxsFluidParticle* particlesSpB = particlesSpA0 + numParticlesSpA; PxVec3* forceBufB = forceBufA0 + numParticlesSpA; while (particlesLeftB) { PxU32 numParticlesSpB = PxMin(particlesLeftB, static_cast<PxU32>(PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY)); // Make sure the number of hash buckets is a power of 2 (requirement for the used hash function) const PxU32 numCellHashBucketsSpB = Ps::nextPowerOfTwo(numParticlesSpB + 1); PX_ASSERT(numCellHashBucketsSpB <= tempBuffers.cellHashMaxSize); // Get local cell hash for other subpacket PxsFluidSpatialHash::buildLocalHash(particlesSpB, numParticlesSpB, particleCellsSpB, particleIndicesSpB, tempBuffers.hashKeys, numCellHashBucketsSpB, mParams.cellSizeInv, packetCorner); // For the cells of subpacket A, find neighboring cells in the subpacket B and compute particle interactions. updateCellsSubpacketPair(updateType, forceBufA0, forceBufB, particlesSpA0, particlesSpB, particleCellsSpA, particleCellsSpB, particleIndicesSpA, particleIndicesSpB, numCellHashBucketsSpA, numCellHashBucketsSpB, true, mParams, tempBuffers, numParticlesSpA < numParticlesSpB); particlesLeftB -= numParticlesSpB; particlesSpB += numParticlesSpB; forceBufB += numParticlesSpB; } particlesLeftA0 -= numParticlesSpA; particlesSpA0 += numParticlesSpA; forceBufA0 += numParticlesSpA; } //--------------------------------------------------------------------------------------------------- // // Compute particle interactions between particles of sections of the current packet and particles of neighboring // halo regions // PX_ASSERT(PXS_FLUID_BRUTE_FORCE_PARTICLE_THRESHOLD_HALO_VS_SECTION <= PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY); if (haloRegions.maxNumParticles != 0) { for(PxU32 s=0; s < 26; s++) { PxU32 numSectionParticles = packetSections.numParticles[s]; if (numSectionParticles == 0) continue; bool sectionEnablesBruteForce = (numSectionParticles <= PXS_FLUID_BRUTE_FORCE_PARTICLE_THRESHOLD_HALO_VS_SECTION); SectionToHaloTable& neighborHaloRegions = sSectionToHaloTable[s]; PxU32 numHaloNeighbors = neighborHaloRegions.numHaloRegions; PxU32 particlesLeftA = numSectionParticles; PxsFluidParticle* particlesSpA = particles + packetSections.firstParticle[s]; PxVec3* forceBufA = forceBuf + packetSections.firstParticle[s]; while (particlesLeftA) { PxU32 numParticlesSpA = PxMin(particlesLeftA, static_cast<PxU32>(PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY)); // Compute particle interactions between particles of the current subpacket (of the section) // and particles of neighboring halo regions relevant. //Process halo regions which need local hash building first. bool isLocalHashValid = false; // Make sure the number of hash buckets is a power of 2 (requirement for the used hash function) const PxU32 numCellHashBucketsSpA = Ps::nextPowerOfTwo(numParticlesSpA + 1); PX_ASSERT(numCellHashBucketsSpA <= tempBuffers.cellHashMaxSize); #if MERGE_HALO_REGIONS //Read halo region particles into temporary buffer PxU32 numMergedHaloParticles = 0; for(PxU32 h = 0; h < numHaloNeighbors; h++) { PxU32 haloRegionIdx = neighborHaloRegions.haloRegionIndices[h]; PxU32 numHaloParticles = haloRegions.numParticles[haloRegionIdx]; // chunk regions into subpackets! PxU32 particlesLeftB = numHaloParticles; PxsFluidParticle* particlesSpB = particles + haloRegions.firstParticle[haloRegionIdx]; PxVec3* forceBufB = forceBuf + haloRegions.firstParticle[haloRegionIdx]; while (particlesLeftB) { PxU32 numParticlesSpB = PxMin(particlesLeftB, static_cast<PxU32>(PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY)); // if there are plenty of particles already, don't bother to do the copy for merging. if (numParticlesSpB > PXS_FLUID_BRUTE_FORCE_PARTICLE_THRESHOLD_HALO_VS_SECTION) { updateSubpacketPairHalo(forceBufA, particlesSpA, numParticlesSpA, particleCellsSpA, particleIndicesSpA, isLocalHashValid, numCellHashBucketsSpA, forceBufB, particlesSpB, numParticlesSpB, particleCellsSpB, particleIndicesSpB, packetCorner, updateType, hashKeyArray, tempBuffers); } else { if (numMergedHaloParticles + numParticlesSpB > PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY) { //flush updateSubpacketPairHalo(forceBufA, particlesSpA, numParticlesSpA, particleCellsSpA, particleIndicesSpA, isLocalHashValid, numCellHashBucketsSpA, tempBuffers.mergedHaloRegions, numMergedHaloParticles, particleCellsSpB, particleIndicesSpB, packetCorner, updateType, hashKeyArray, tempBuffers); numMergedHaloParticles = 0; } for (PxU32 k = 0; k < numParticlesSpB; ++k) tempBuffers.mergedHaloRegions[numMergedHaloParticles++] = particlesSpB[k]; } particlesLeftB -= numParticlesSpB; particlesSpB += numParticlesSpB; } } //flush updateSubpacketPairHalo(forceBufA, particlesSpA, numParticlesSpA, particleCellsSpA, particleIndicesSpA, isLocalHashValid, numCellHashBucketsSpA, tempBuffers.mergedHaloRegions, numMergedHaloParticles, particleCellsSpB, particleIndicesSpB, packetCorner, updateType, hashKeyArray, tempBuffers); #else // MERGE_HALO_REGIONS for(PxU32 h = 0; h < numHaloNeighbors; h++) { PxU32 haloRegionIdx = neighborHaloRegions.haloRegionIndices[h]; PxU32 numHaloParticles = haloRegions.numParticles[haloRegionIdx]; bool haloRegionEnablesBruteForce = (numHaloParticles <= PXS_FLUID_BRUTE_FORCE_PARTICLE_THRESHOLD_HALO_VS_SECTION); if (sectionEnablesBruteForce && haloRegionEnablesBruteForce) continue; if (!isLocalHashValid) { // Get local cell hash for the current subpacket PxsFluidSpatialHash::buildLocalHash(particlesSpA, numParticlesSpA, particleCellsSpA, particleIndicesSpA, tempBuffers.hashKeys, numCellHashBucketsSpA, mParams.cellSizeInv, packetCorner); isLocalHashValid = true; } PxU32 particlesLeftB = numHaloParticles; PxsFluidParticle* particlesSpB = particles + haloRegions.firstParticle[haloRegionIdx]; while (particlesLeftB) { PxU32 numParticlesSpB = PxMin(particlesLeftB, static_cast<PxU32>(PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY)); // It is important that no data is written to particles in halo regions since they belong to // a neighboring packet. The interaction effect of the current packet on the neighboring packet will be // considered when the neighboring packet is processed. // Make sure the number of hash buckets is a power of 2 (requirement for the used hash function) const PxU32 numCellHashBucketsSpB = Ps::nextPowerOfTwo(numParticlesSpB + 1); PX_ASSERT(numCellHashBucketsSpB <= tempBuffers.cellHashMaxSize); // Get local cell hash for other subpacket PxsFluidSpatialHash::buildLocalHash(particlesSpB, numParticlesSpB, particleCellsSpB, particleIndicesSpB, tempBuffers.hashKeys, numCellHashBucketsSpB, mParams.cellSizeInv, packetCorner); // For the cells of subpacket A, find neighboring cells in the subpacket B and compute particle interactions. updateCellsSubpacketPair(updateType, forceBufA, NULL, particlesSpA, particlesSpB, particleCellsSpA, particleCellsSpB, particleIndicesSpA, particleIndicesSpB, numCellHashBucketsSpA, numCellHashBucketsSpB, false, mParams, tempBuffers, numParticlesSpA > numParticlesSpB); particlesLeftB -= numParticlesSpB; particlesSpB += numParticlesSpB; } } //Now process halo regions which don't need local hash building. PxU32 mergedIndexCount = 0; for(PxU32 h = 0; h < numHaloNeighbors; h++) { PxU32 haloRegionIdx = neighborHaloRegions.haloRegionIndices[h]; PxU32 numHaloParticles = haloRegions.numParticles[haloRegionIdx]; if (numHaloParticles == 0) continue; bool haloRegionEnablesBruteForce = (numHaloParticles <= PXS_FLUID_BRUTE_FORCE_PARTICLE_THRESHOLD_HALO_VS_SECTION); if (!sectionEnablesBruteForce || !haloRegionEnablesBruteForce) continue; // The section and the halo region do not have enough particles to make it worth // building a local cell hash --> use brute force approach // This is given by the brute force condition (haloRegionEnablesBruteForce). Its necessary to // make sure a halo region alone fits into the merge buffer. PX_ASSERT(numHaloParticles <= PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY); if (mergedIndexCount + numHaloParticles > PXS_FLUID_SUBPACKET_PARTICLE_LIMIT_FORCE_DENSITY) { updateParticleGroupPair(forceBufA, NULL, particlesSpA, particles, tempBuffers.orderedIndicesSubpacket, numSectionParticles, tempBuffers.mergedIndices, mergedIndexCount, false, updateType == PXS_SPH_DENSITY, mParams, tempBuffers.simdPositionsSubpacket, tempBuffers.indexStream); mergedIndexCount = 0; } PxU32 hpIndex = haloRegions.firstParticle[haloRegionIdx]; for (PxU32 k = 0; k < numHaloParticles; k++) tempBuffers.mergedIndices[mergedIndexCount++] = hpIndex++; } if (mergedIndexCount > 0) { updateParticleGroupPair(forceBufA, NULL, particlesSpA, particles, tempBuffers.orderedIndicesSubpacket, numSectionParticles, tempBuffers.mergedIndices, mergedIndexCount, false, updateType == PXS_SPH_DENSITY, mParams, tempBuffers.simdPositionsSubpacket, tempBuffers.indexStream); } #endif // MERGE_HALO_REGIONS particlesLeftA -= numParticlesSpA; particlesSpA += numParticlesSpA; forceBufA += numParticlesSpA; } } } }
void CreateTerrainGeomtry(LevelGeometry &lg) { const int PATCH_SIZE = 64; if (!Terrain) return; PxHeightFieldGeometry g = Terrain->GetHFShape(); const float colScale = g.columnScale; const float rowScale = g.rowScale; const float heightScale = g.heightScale; PxHeightField *physHF = g.heightField; PxU32 nbCols = physHF->getNbColumns(); PxU32 nbRows = physHF->getNbRows(); PxU32 patchCols = static_cast<PxU32>(ceilf(nbCols / static_cast<float>(PATCH_SIZE))); PxU32 patchRows = static_cast<PxU32>(ceilf(nbRows / static_cast<float>(PATCH_SIZE))); lg.meshes.Resize(patchCols * patchRows); lg.meshStartObjectsIdx = lg.meshes.Count(); for (PxU32 pi = 0; pi < patchCols; ++pi) { for (PxU32 pj = 0; pj < patchRows; ++pj) { // Fill patch vertices first. LevelGeometry::Mesh &p = lg.meshes[pi * patchRows + pj]; PxU32 startCol = pi * PATCH_SIZE; PxU32 startRow = pj * PATCH_SIZE; PxU32 endCol = (pi + 1) * PATCH_SIZE; PxU32 endRow = (pj + 1) * PATCH_SIZE; PxU32 w = std::min(endCol - startCol + 1, nbCols - startCol); PxU32 h = std::min(endRow - startRow + 1, nbRows - startRow); p.vertices.Resize(w * h); for(PxU32 i = 0; i < w; ++i) { for(PxU32 j = 0; j < h; ++j) { PxReal x = PxReal(i + startCol); PxReal z = PxReal(j + startRow); PxReal y = physHF->getHeight(x, z) * heightScale; PxU32 idx = i * h + j; p.vertices[idx] = r3dVector(x * colScale, y, z * rowScale); } } // Now triangulate patch const PxU32 nbFaces = (w - 1) * (h - 1) * 2; p.indices.Resize(nbFaces * 3); int * indices = &p.indices.GetFirst(); for (PxU32 i = 0; i < (w - 1); ++i) { for (PxU32 j = 0; j < (h - 1); ++j) { // first triangle uint32_t baseIdx = 6 * (i * (h - 1) + j); indices[baseIdx + 0] = (i + 1) * h + j; indices[baseIdx + 1] = i * h + j; indices[baseIdx + 2] = i * h + j + 1; // second triangle indices[baseIdx + 3] = (i + 1) * h + j + 1; indices[baseIdx + 4] = (i + 1) * h + j; indices[baseIdx + 5] = i * h + j + 1; } } // Filter outside triangles uint32_t indicesCount = gConvexRegionsManager.FilterOutsideTriangles(&p.vertices.GetFirst(), &p.indices.GetFirst(), p.indices.Count()); p.indices.Resize(indicesCount); } } }