FByteBulkData* UBodySetup::GetCookedData(FName Format) { if (IsTemplate()) { return NULL; } IInterface_CollisionDataProvider* CDP = Cast<IInterface_CollisionDataProvider>(GetOuter()); // If there is nothing to cook or if we are reading data from a cooked package for an asset with no collision, // we want to return here if ((AggGeom.ConvexElems.Num() == 0 && CDP == NULL) || !bHasCookedCollisionData) { return NULL; } FFormatContainer* UseCookedData = CookedFormatDataOverride ? CookedFormatDataOverride : &CookedFormatData; bool bContainedData = UseCookedData->Contains(Format); FByteBulkData* Result = &UseCookedData->GetFormat(Format); #if WITH_PHYSX if (!bContainedData) { if (FPlatformProperties::RequiresCookedData()) { UE_LOG(LogPhysics, Error, TEXT("Attempt to build physics data for %s when we are unable to. This platform requires cooked packages."), *GetPathName()); } if (AggGeom.ConvexElems.Num() == 0 && (CDP == NULL || CDP->ContainsPhysicsTriMeshData(bMeshCollideAll) == false)) { return NULL; } #if WITH_RUNTIME_PHYSICS_COOKING || WITH_EDITOR TArray<uint8> OutData; FDerivedDataPhysXCooker* DerivedPhysXData = new FDerivedDataPhysXCooker(Format, this); if (DerivedPhysXData->CanBuild()) { #if WITH_EDITOR GetDerivedDataCacheRef().GetSynchronous(DerivedPhysXData, OutData); #elif WITH_RUNTIME_PHYSICS_COOKING DerivedPhysXData->Build(OutData); #endif if (OutData.Num()) { Result->Lock(LOCK_READ_WRITE); FMemory::Memcpy(Result->Realloc(OutData.Num()), OutData.GetData(), OutData.Num()); Result->Unlock(); } } else #endif { UE_LOG(LogPhysics, Warning, TEXT("Attempt to build physics data for %s when we are unable to."), *GetPathName()); } } #endif // WITH_PHYSX check(Result); return Result->GetBulkDataSize() > 0 ? Result : NULL; // we don't return empty bulk data...but we save it to avoid thrashing the DDC }
bool FDerivedDataPhysXCooker::ShouldGenerateTriMeshData(bool InUseAllTriData) { check(Cooker != NULL); IInterface_CollisionDataProvider* CDP = Cast<IInterface_CollisionDataProvider>(CollisionDataProvider); const bool bPerformCook = ( CDP != NULL ) ? CDP->ContainsPhysicsTriMeshData(InUseAllTriData) : false; return bPerformCook; }
bool FDerivedDataPhysXCooker::BuildTriMesh( TArray<uint8>& OutData, bool bInMirrored, bool InUseAllTriData ) { check(Cooker != NULL); bool bResult = false; FTriMeshCollisionData TriangleMeshDesc; IInterface_CollisionDataProvider* CDP = Cast<IInterface_CollisionDataProvider>(CollisionDataProvider); check(CDP != NULL); // It's all been checked before getting into this function bool bHaveTriMeshData = CDP->GetPhysicsTriMeshData(&TriangleMeshDesc, InUseAllTriData); if(bHaveTriMeshData) { // If any of the below checks gets hit this usually means // IInterface_CollisionDataProvider::ContainsPhysicsTriMeshData did not work properly. const int32 NumIndices = TriangleMeshDesc.Indices.Num(); const int32 NumVerts = TriangleMeshDesc.Vertices.Num(); if(NumIndices == 0 || NumVerts == 0 || TriangleMeshDesc.MaterialIndices.Num() > NumIndices) { UE_LOG(LogPhysics, Warning, TEXT("FDerivedDataPhysXCooker::BuildTriMesh: Triangle data from '%s' invalid (%d verts, %d indices)."), *CollisionDataProvider->GetPathName(), NumVerts, NumIndices ); return bResult; } TArray<FVector>* MeshVertices = NULL; TArray<FVector> MirroredVerts; if( bInMirrored ) { MirroredVerts.AddUninitialized(NumVerts); for(int32 VertIdx=0; VertIdx<NumVerts; VertIdx++) { MirroredVerts[VertIdx] = TriangleMeshDesc.Vertices[VertIdx] * FVector(-1,1,1); } MeshVertices = &MirroredVerts; } else { MeshVertices = &TriangleMeshDesc.Vertices; } UE_LOG(LogPhysics, Log, TEXT("Cook TriMesh: %s (FlipX: %d)"), *CollisionDataProvider->GetPathName(), bInMirrored); bool bPerPolySkeletalMesh = false; if (USkeletalMesh* SkeletalMesh = Cast<USkeletalMesh>(CollisionDataProvider)) { ensure(SkeletalMesh->bEnablePerPolyCollision); bPerPolySkeletalMesh = true; } bResult = Cooker->CookTriMesh( Format, *MeshVertices, TriangleMeshDesc.Indices, TriangleMeshDesc.MaterialIndices, bInMirrored ? !TriangleMeshDesc.bFlipNormals : TriangleMeshDesc.bFlipNormals, OutData, bPerPolySkeletalMesh ); if( !bResult ) { UE_LOG(LogPhysics, Warning, TEXT("Failed to cook TriMesh: %s (FlipX:%d)."), *CollisionDataProvider->GetPathName(), bInMirrored ); } } return bResult; }
FDerivedDataNavCollisionCooker::FDerivedDataNavCollisionCooker(FName InFormat, UNavCollision* InInstance) : NavCollisionInstance(InInstance) , CollisionDataProvider( NULL ) , Format( InFormat ) { check(NavCollisionInstance != NULL); CollisionDataProvider = NavCollisionInstance->GetOuter(); DataGuid = NavCollisionInstance->GetGuid(); IInterface_CollisionDataProvider* CDP = Cast<IInterface_CollisionDataProvider>(CollisionDataProvider); if (CDP) { CDP->GetMeshId(MeshId); } }
FDerivedDataPhysXCooker::FDerivedDataPhysXCooker( FName InFormat, UBodySetup* InBodySetup ) : BodySetup( InBodySetup ) , CollisionDataProvider( NULL ) , Format( InFormat ) , Cooker( NULL ) { check( BodySetup != NULL ); CollisionDataProvider = BodySetup->GetOuter(); DataGuid = BodySetup->BodySetupGuid; bGenerateNormalMesh = BodySetup->bGenerateNonMirroredCollision; bGenerateMirroredMesh = BodySetup->bGenerateMirroredCollision; IInterface_CollisionDataProvider* CDP = Cast<IInterface_CollisionDataProvider>(CollisionDataProvider); if (CDP) { CDP->GetMeshId(MeshId); } InitCooker(); }
int32 FDerivedDataPhysXCooker::BuildTriMesh( TArray<uint8>& OutData, bool InUseAllTriData ) { check(Cooker != NULL); bool bResult = false; FTriMeshCollisionData TriangleMeshDesc; IInterface_CollisionDataProvider* CDP = Cast<IInterface_CollisionDataProvider>(CollisionDataProvider); check(CDP != NULL); // It's all been checked before getting into this function bool bHaveTriMeshData = CDP->GetPhysicsTriMeshData(&TriangleMeshDesc, InUseAllTriData); if(bHaveTriMeshData) { // If any of the below checks gets hit this usually means // IInterface_CollisionDataProvider::ContainsPhysicsTriMeshData did not work properly. const int32 NumIndices = TriangleMeshDesc.Indices.Num(); const int32 NumVerts = TriangleMeshDesc.Vertices.Num(); if(NumIndices == 0 || NumVerts == 0 || TriangleMeshDesc.MaterialIndices.Num() > NumIndices) { UE_LOG(LogPhysics, Warning, TEXT("FDerivedDataPhysXCooker::BuildTriMesh: Triangle data from '%s' invalid (%d verts, %d indices)."), *CollisionDataProvider->GetPathName(), NumVerts, NumIndices ); return bResult; } TArray<FVector>* MeshVertices = NULL; MeshVertices = &TriangleMeshDesc.Vertices; UE_LOG(LogPhysics, Log, TEXT("Cook TriMesh: %s"), *CollisionDataProvider->GetPathName()); bool bDeformableMesh = CollisionDataProvider->IsA(USplineMeshComponent::StaticClass()); if (USkeletalMesh* SkeletalMesh = Cast<USkeletalMesh>(CollisionDataProvider)) { ensure(SkeletalMesh->bEnablePerPolyCollision); bDeformableMesh = true; } bResult = Cooker->CookTriMesh( Format, RuntimeCookFlags, *MeshVertices, TriangleMeshDesc.Indices, TriangleMeshDesc.MaterialIndices, TriangleMeshDesc.bFlipNormals, OutData, bDeformableMesh ); if( !bResult ) { UE_LOG(LogPhysics, Warning, TEXT("Failed to cook TriMesh: %s."), *CollisionDataProvider->GetPathName()); } } return bResult == true ? 1 : 0; //the cooker only generates 1 or 0 trimeshes. We return an int because we support multiple trimeshes for welding and we might want to do this per static mesh in the future. }
bool FDerivedDataPhysXCooker::ShouldGenerateNegXTriMeshData() { IInterface_CollisionDataProvider* CDP = Cast<IInterface_CollisionDataProvider>(CollisionDataProvider); const bool bWantsNegX = ( CDP != NULL ) ? CDP->WantsNegXTriMesh() : false; return bWantsNegX; }