/** * Perform any cleanup of physics engine resources. * This is deferred because when closing down the game, you want to make sure you are not destroying a mesh after the physics SDK has been shut down. */ void DeferredPhysResourceCleanup() { #if WITH_PHYSX // Release all tri meshes and reset array for(int32 MeshIdx=0; MeshIdx<GPhysXPendingKillTriMesh.Num(); MeshIdx++) { PxTriangleMesh* PTriMesh = GPhysXPendingKillTriMesh[MeshIdx]; check(PTriMesh); PTriMesh->release(); GPhysXPendingKillTriMesh[MeshIdx] = NULL; } GPhysXPendingKillTriMesh.Reset(); // Release all convex meshes and reset array for(int32 MeshIdx=0; MeshIdx<GPhysXPendingKillConvex.Num(); MeshIdx++) { PxConvexMesh* PConvexMesh = GPhysXPendingKillConvex[MeshIdx]; check(PConvexMesh); PConvexMesh->release(); GPhysXPendingKillConvex[MeshIdx] = NULL; } GPhysXPendingKillConvex.Reset(); // Release all heightfields and reset array for(int32 HfIdx=0; HfIdx<GPhysXPendingKillHeightfield.Num(); HfIdx++) { PxHeightField* PHeightfield = GPhysXPendingKillHeightfield[HfIdx]; check(PHeightfield); PHeightfield->release(); GPhysXPendingKillHeightfield[HfIdx] = NULL; } GPhysXPendingKillHeightfield.Reset(); // Release all materials and reset array for(int32 MeshIdx=0; MeshIdx<GPhysXPendingKillMaterial.Num(); MeshIdx++) { PxMaterial* PMaterial = GPhysXPendingKillMaterial[MeshIdx]; check(PMaterial); PMaterial->release(); GPhysXPendingKillMaterial[MeshIdx] = NULL; } GPhysXPendingKillMaterial.Reset(); #endif }
/** * Perform any cleanup of physics engine resources. * This is deferred because when closing down the game, you want to make sure you are not destroying a mesh after the physics SDK has been shut down. */ void DeferredPhysResourceCleanup() { #if WITH_PHYSX // Release all tri meshes and reset array for(int32 MeshIdx=0; MeshIdx<GPhysXPendingKillTriMesh.Num(); MeshIdx++) { PxTriangleMesh* PTriMesh = GPhysXPendingKillTriMesh[MeshIdx]; // Check this as it shouldn't be null, but then gate on it so we can // avoid a crash if we end up in this state in shipping check(PTriMesh); if(PTriMesh) { PTriMesh->release(); if(GPhysXPendingKillTriMesh.IsValidIndex(MeshIdx)) { GPhysXPendingKillTriMesh[MeshIdx] = NULL; } else { UE_LOG(LogPhysics, Warning, TEXT("DeferredPhysResourceCleanup found invalid index into GPhysXPendingKillTriMesh, another thread may have modified the array."), MeshIdx); } } else { UE_LOG(LogPhysics, Warning, TEXT("DeferredPhysResourceCleanup found null PxTriangleMesh in pending kill array, another thread may have modified the array."), MeshIdx); } } GPhysXPendingKillTriMesh.Reset(); // Release all convex meshes and reset array for(int32 MeshIdx=0; MeshIdx<GPhysXPendingKillConvex.Num(); MeshIdx++) { PxConvexMesh* PConvexMesh = GPhysXPendingKillConvex[MeshIdx]; // Check this as it shouldn't be null, but then gate on it so we can // avoid a crash if we end up in this state in shipping check(PConvexMesh); if(PConvexMesh) { PConvexMesh->release(); if(GPhysXPendingKillConvex.IsValidIndex(MeshIdx)) { GPhysXPendingKillConvex[MeshIdx] = NULL; } else { UE_LOG(LogPhysics, Warning, TEXT("DeferredPhysResourceCleanup found invalid index into GPhysXPendingKillConvex (%d), another thread may have modified the array."), MeshIdx); } } else { UE_LOG(LogPhysics, Warning, TEXT("DeferredPhysResourceCleanup found null PxConvexMesh in pending kill array (at %d), another thread may have modified the array."), MeshIdx); } } GPhysXPendingKillConvex.Reset(); // Release all heightfields and reset array for(int32 HfIdx=0; HfIdx<GPhysXPendingKillHeightfield.Num(); HfIdx++) { PxHeightField* PHeightfield = GPhysXPendingKillHeightfield[HfIdx]; // Check this as it shouldn't be null, but then gate on it so we can // avoid a crash if we end up in this state in shipping check(PHeightfield); if(PHeightfield) { PHeightfield->release(); if(GPhysXPendingKillHeightfield.IsValidIndex(HfIdx)) { GPhysXPendingKillHeightfield[HfIdx] = NULL; } else { UE_LOG(LogPhysics, Warning, TEXT("DeferredPhysResourceCleanup found invalid index into GPhysXPendingKillHeightfield (%d), another thread may have modified the array."), HfIdx); } } else { UE_LOG(LogPhysics, Warning, TEXT("DeferredPhysResourceCleanup found null PxHeightField in pending kill array (at %d), another thread may have modified the array."), HfIdx); } } GPhysXPendingKillHeightfield.Reset(); // Release all materials and reset array for(int32 MeshIdx=0; MeshIdx<GPhysXPendingKillMaterial.Num(); MeshIdx++) { PxMaterial* PMaterial = GPhysXPendingKillMaterial[MeshIdx]; // Check this as it shouldn't be null, but then gate on it so we can // avoid a crash if we end up in this state in shipping check(PMaterial); if(PMaterial) { PMaterial->release(); if(GPhysXPendingKillMaterial.IsValidIndex(MeshIdx)) { GPhysXPendingKillMaterial[MeshIdx] = NULL; } else { UE_LOG(LogPhysics, Warning, TEXT("DeferredPhysResourceCleanup found invalid index into GPhysXPendingKillMaterial(%d), another thread may have modified the array."), MeshIdx); } } else { UE_LOG(LogPhysics, Warning, TEXT("DeferredPhysResourceCleanup found null PxMaterial in pending kill array (at %d), another thread may have modified the array."), MeshIdx); } } GPhysXPendingKillMaterial.Reset(); #endif }
void PhysicalTile::updatePxHeight() { // do the physx update only when needed if (m_pxUpdateBox.maxColumn < m_pxUpdateBox.minColumn) return; PxHeightFieldGeometry geometry; bool result = m_pxShape->getHeightFieldGeometry(geometry); assert(result); if (!result) { glow::warning("TerrainInteractor::setPxHeight could not get height field geometry from physx shape"); return; } PxHeightField * hf = geometry.heightField; assert(m_pxUpdateBox.minRow <= m_pxUpdateBox.maxRow && m_pxUpdateBox.minColumn <= m_pxUpdateBox.maxColumn); unsigned int nbRows = m_pxUpdateBox.maxRow - m_pxUpdateBox.minRow + 1; unsigned int nbColumns = m_pxUpdateBox.maxColumn - m_pxUpdateBox.minColumn + 1; unsigned int fieldSize = nbRows * nbColumns; PxHeightFieldSample * samplesM = new PxHeightFieldSample[fieldSize]; for (unsigned int r = 0; r < nbRows; ++r) { unsigned int rowOffset = r * nbColumns; for (unsigned int c = 0; c < nbColumns; ++c) { const unsigned int index = c + rowOffset; const unsigned int tileValueIndex = (c + m_pxUpdateBox.minColumn) + (r + m_pxUpdateBox.minRow) * samplesPerAxis; const float terrainHeight = valueAt(tileValueIndex); samplesM[index].height = static_cast<PxI16>(terrainHeight / geometry.heightScale); samplesM[index].materialIndex0 = samplesM[index].materialIndex1 = elementIndexAt(tileValueIndex); } } PxHeightFieldDesc descM; descM.nbColumns = nbColumns; descM.nbRows = nbRows; descM.samples.data = samplesM; descM.format = hf->getFormat(); descM.samples.stride = hf->getSampleStride(); descM.thickness = hf->getThickness(); descM.convexEdgeThreshold = hf->getConvexEdgeThreshold(); descM.flags = hf->getFlags(); PhysicsWrapper::getInstance()->pauseGPUAcceleration(); bool success = hf->modifySamples(m_pxUpdateBox.minColumn, m_pxUpdateBox.minRow, descM); assert(success); if (!success) { glow::warning("TerrainInteractor::setPxHeight could not modify height field."); return; } PxHeightFieldGeometry newGeometry(hf, PxMeshGeometryFlags(), geometry.heightScale, geometry.rowScale, geometry.columnScale); assert(PxGetPhysics().getNbScenes() == 1); PxScene * pxScenePtrs[1]; PxGetPhysics().getScenes(pxScenePtrs, 1); pxScenePtrs[0]->lockWrite(); m_pxShape->setGeometry(newGeometry); pxScenePtrs[0]->unlockWrite(); PhysicsWrapper::getInstance()->restoreGPUAccelerated(); #ifdef PX_WINDOWS if (PhysicsWrapper::getInstance()->physxGpuAvailable()) { PxParticleGpu::releaseHeightFieldMirror(*hf); PxParticleGpu::createHeightFieldMirror(*hf, *PhysicsWrapper::getInstance()->cudaContextManager()); } #endif clearPxBufferUpdateRange(); }
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); } } }