UDestructibleMesh* ImportDestructibleMeshFromApexDestructibleAsset(UObject* InParent, NxDestructibleAsset& ApexDestructibleAsset, FName Name, EObjectFlags Flags, FSkeletalMeshImportData* OutData, EDestructibleImportOptions::Type Options) { // The APEX Destructible Asset contains an APEX Render Mesh Asset, get a pointer to this const physx::NxRenderMeshAsset* ApexRenderMesh = ApexDestructibleAsset.getRenderMeshAsset(); if (ApexRenderMesh == NULL) { return NULL; } // Number of submeshes (aka "elements" in Unreal) const physx::PxU32 SubmeshCount = ApexRenderMesh->getSubmeshCount(); if (SubmeshCount == 0) { return NULL; } // Make sure rendering is done - so we are not changing data being used by collision drawing. FlushRenderingCommands(); UDestructibleMesh* DestructibleMesh = FindObject<UDestructibleMesh>(InParent, *Name.ToString()); if (DestructibleMesh == NULL) { // Create the new UDestructibleMesh object if the one with the same name does not exist DestructibleMesh = NewObject<UDestructibleMesh>(InParent, Name, Flags); } if (!(Options & EDestructibleImportOptions::PreserveSettings)) { // Store the current file path and timestamp for re-import purposes // @todo AssetImportData make a data class for Apex destructible assets DestructibleMesh->AssetImportData = NewObject<UAssetImportData>(DestructibleMesh); DestructibleMesh->AssetImportData->Update(UFactory::CurrentFilename); DestructibleMesh->AssetImportData->bDirty = false; } DestructibleMesh->PreEditChange(NULL); // Build FractureSettings from ApexDestructibleAsset in case we want to re-fracture #if WITH_EDITORONLY_DATA DestructibleMesh->CreateFractureSettings(); DestructibleMesh->FractureSettings->BuildRootMeshFromApexDestructibleAsset(ApexDestructibleAsset, Options); // Fill materials DestructibleMesh->FractureSettings->Materials.Reset(DestructibleMesh->Materials.Num()); for (int32 MaterialIndex = 0; MaterialIndex < DestructibleMesh->Materials.Num(); ++MaterialIndex) { DestructibleMesh->FractureSettings->Materials.Insert(DestructibleMesh->Materials[MaterialIndex].MaterialInterface, MaterialIndex); } #endif // WITH_EDITORONLY_DATA if (!SetApexDestructibleAsset(*DestructibleMesh, ApexDestructibleAsset, OutData, Options)) { // should remove this destructible mesh. if not, this object causes a crash when ticking because it doesn't have proper rendering resources // @TODO : creates this destructible mesh after loading data completely DestructibleMesh->PostEditChange(); DestructibleMesh->ConditionalBeginDestroy(); return NULL; } return DestructibleMesh; }
UDestructibleMesh* ImportDestructibleMeshFromApexDestructibleAsset(UObject* InParent, NxDestructibleAsset& ApexDestructibleAsset, FName Name, EObjectFlags Flags, FSkeletalMeshImportData* OutData, EImportOptions::Type Options) { // The APEX Destructible Asset contains an APEX Render Mesh Asset, get a pointer to this const physx::NxRenderMeshAsset* ApexRenderMesh = ApexDestructibleAsset.getRenderMeshAsset(); if (ApexRenderMesh == NULL) { return NULL; } // Number of submeshes (aka "elements" in Unreal) const physx::PxU32 SubmeshCount = ApexRenderMesh->getSubmeshCount(); if (SubmeshCount == 0) { return NULL; } // Make sure rendering is done - so we are not changing data being used by collision drawing. FlushRenderingCommands(); UDestructibleMesh* DestructibleMesh = FindObject<UDestructibleMesh>(InParent, *Name.ToString()); if (DestructibleMesh == NULL) { // Create the new UDestructibleMesh object if the one with the same name does not exist DestructibleMesh = CastChecked<UDestructibleMesh>(StaticConstructObject(UDestructibleMesh::StaticClass(), InParent, Name, Flags)); } if (!(Options & EImportOptions::PreserveSettings)) { // Store the current file path and timestamp for re-import purposes // @todo AssetImportData make a data class for Apex destructible assets DestructibleMesh->AssetImportData = ConstructObject<UAssetImportData>(UAssetImportData::StaticClass(), DestructibleMesh); DestructibleMesh->AssetImportData->SourceFilePath = FReimportManager::SanitizeImportFilename(UFactory::CurrentFilename, DestructibleMesh); DestructibleMesh->AssetImportData->SourceFileTimestamp = IFileManager::Get().GetTimeStamp(*UFactory::CurrentFilename).ToString(); } DestructibleMesh->PreEditChange(NULL); // Build FractureSettings from ApexDestructibleAsset in case we want to re-fracture #if WITH_EDITORONLY_DATA DestructibleMesh->CreateFractureSettings(); DestructibleMesh->FractureSettings->BuildRootMeshFromApexDestructibleAsset(ApexDestructibleAsset, Options); // Fill materials DestructibleMesh->FractureSettings->Materials.Reset(DestructibleMesh->Materials.Num()); for (int32 MaterialIndex = 0; MaterialIndex < DestructibleMesh->Materials.Num(); ++MaterialIndex) { DestructibleMesh->FractureSettings->Materials.Insert(DestructibleMesh->Materials[MaterialIndex].MaterialInterface, MaterialIndex); } #endif // WITH_EDITORONLY_DATA if (!SetApexDestructibleAsset(*DestructibleMesh, ApexDestructibleAsset, OutData, Options)) { return NULL; } return DestructibleMesh; }
UNREALED_API bool BuildDestructibleMeshFromFractureSettings(UDestructibleMesh& DestructibleMesh, FSkeletalMeshImportData* OutData) { bool Success = false; #if WITH_APEX physx::NxDestructibleAsset* NewApexDestructibleAsset = NULL; #if WITH_EDITORONLY_DATA if (DestructibleMesh.FractureSettings != NULL) { TArray<UMaterialInterface*> OverrideMaterials; OverrideMaterials.Init(DestructibleMesh.Materials.Num()); //save old materials for (int32 MaterialIndex = 0; MaterialIndex < DestructibleMesh.Materials.Num(); ++MaterialIndex) { OverrideMaterials[MaterialIndex] = DestructibleMesh.Materials[MaterialIndex].MaterialInterface; } DestructibleMesh.Materials.Init(DestructibleMesh.FractureSettings->Materials.Num()); for (int32 MaterialIndex = 0; MaterialIndex < DestructibleMesh.Materials.Num(); ++MaterialIndex) { if (MaterialIndex < OverrideMaterials.Num()) //if user has overriden materials use it { DestructibleMesh.Materials[MaterialIndex].MaterialInterface = OverrideMaterials[MaterialIndex]; } else { DestructibleMesh.Materials[MaterialIndex].MaterialInterface = DestructibleMesh.FractureSettings->Materials[MaterialIndex]; } } NxDestructibleAssetCookingDesc DestructibleAssetCookingDesc; DestructibleMesh.FractureSettings->BuildDestructibleAssetCookingDesc(DestructibleAssetCookingDesc); NewApexDestructibleAsset = DestructibleMesh.FractureSettings->CreateApexDestructibleAsset(DestructibleAssetCookingDesc); } #endif // WITH_EDITORONLY_DATA if (NewApexDestructibleAsset != NULL) { Success = SetApexDestructibleAsset(DestructibleMesh, *NewApexDestructibleAsset, OutData, EDestructibleImportOptions::PreserveSettings); } #endif // WITH_APEX return Success; }
UNREALED_API bool BuildDestructibleMeshFromFractureSettings(UDestructibleMesh& DestructibleMesh, FSkeletalMeshImportData* OutData) { bool Success = false; #if WITH_APEX physx::NxDestructibleAsset* NewApexDestructibleAsset = NULL; #if WITH_EDITORONLY_DATA if (DestructibleMesh.FractureSettings != NULL) { NxDestructibleAssetCookingDesc DestructibleAssetCookingDesc; DestructibleMesh.FractureSettings->BuildDestructibleAssetCookingDesc(DestructibleAssetCookingDesc); NewApexDestructibleAsset = DestructibleMesh.FractureSettings->CreateApexDestructibleAsset(DestructibleAssetCookingDesc); } #endif // WITH_EDITORONLY_DATA if (NewApexDestructibleAsset != NULL) { Success = SetApexDestructibleAsset(DestructibleMesh, *NewApexDestructibleAsset, OutData, EImportOptions::PreserveSettings); } #endif // WITH_APEX return Success; }