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;
}
void FDestructibleMeshEditorViewportClient::Fracture()
{
#if WITH_APEX
	UDestructibleMesh* DestructibleMesh = DestructibleMeshEditorPtr.Pin()->GetDestructibleMesh();
	if (DestructibleMesh != NULL)
	{
		TComponentReregisterContext<USkinnedMeshComponent> ReregisterContext;

		DestructibleMesh->ReleaseResources();
		DestructibleMesh->ReleaseResourcesFence.Wait();

		if (DestructibleMesh->SourceStaticMesh)
		{
			DestructibleMesh->BuildFractureSettingsFromStaticMesh(DestructibleMesh->SourceStaticMesh);
		}
		else if (DestructibleMesh->ApexDestructibleAsset != NULL)
		{
			DestructibleMesh = ImportDestructibleMeshFromApexDestructibleAsset(DestructibleMesh->GetOuter(), *DestructibleMesh->ApexDestructibleAsset, DestructibleMesh->GetFName(), DestructibleMesh->GetFlags(), NULL,
 																			   EDestructibleImportOptions::PreserveSettings);
		}
		
		DestructibleMesh->FractureSettings->CreateVoronoiSitesInRootMesh();
		DestructibleMesh->FractureSettings->VoronoiSplitMesh();
		
		BuildDestructibleMeshFromFractureSettings(*DestructibleMesh, NULL);
	}
	
	DestructibleMeshEditorPtr.Pin()->RefreshTool();
	DestructibleMeshEditorPtr.Pin()->SetCurrentPreviewDepth(0xFFFFFFFF);	// This will get clamped to the max depth
#endif // WITH_APEX
}
void FDestructibleMeshEditorViewportClient::RefreshFromStaticMesh()
{
#if WITH_APEX
	UDestructibleMesh* DestructibleMesh = DestructibleMeshEditorPtr.Pin()->GetDestructibleMesh();
	
	DestructibleMesh->BuildFromStaticMesh(*DestructibleMesh->SourceStaticMesh);
	Fracture();
#endif // WITH_APEX
}
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;
}
bool SetApexDestructibleAsset(UDestructibleMesh& DestructibleMesh, NxDestructibleAsset& ApexDestructibleAsset, FSkeletalMeshImportData* OutData, EDestructibleImportOptions::Type Options)
{
	DestructibleMesh.PreEditChange(NULL);

	ExistingDestMeshData * ExistDestMeshDataPtr = SaveExistingDestMeshData(&DestructibleMesh);
	
	// The asset is going away, which will destroy any actors created from it.  We must destroy the physics state of any destructible mesh components before we release the asset.
	for(TObjectIterator<UDestructibleComponent> It; It; ++It)
	{
		UDestructibleComponent* DestructibleComponent = *It;
		if(DestructibleComponent->SkeletalMesh == &DestructibleMesh && DestructibleComponent->IsPhysicsStateCreated())
		{
			DestructibleComponent->DestroyPhysicsState();
		}
	}

	// Release old NxDestructibleAsset if it exists
	if (DestructibleMesh.ApexDestructibleAsset != NULL && DestructibleMesh.ApexDestructibleAsset != &ApexDestructibleAsset)
	{
		GPhysCommandHandler->DeferredRelease(DestructibleMesh.ApexDestructibleAsset);
	}

	// BRGTODO - need to remove the render data from the ApexDestructibleAsset, no longer need it
	// Removing const cast ... we'll have to make it non-const anyway when we modify it
	DestructibleMesh.ApexDestructibleAsset = &ApexDestructibleAsset;

	if ( !(Options&EDestructibleImportOptions::PreserveSettings) )
	{
		// Resize the depth parameters array to the appropriate size
		DestructibleMesh.DefaultDestructibleParameters.DepthParameters.Init(FDestructibleDepthParameters(), ApexDestructibleAsset.getDepthCount());

		// Resize the fracture effects array to the appropriate size
		DestructibleMesh.FractureEffects.AddZeroed(ApexDestructibleAsset.getDepthCount());

		// Load the UnrealEd-editable parameters from the destructible asset
		DestructibleMesh.LoadDefaultDestructibleParametersFromApexAsset();
	}
		
	// Create body setup for the destructible mesh
	DestructibleMesh.CreateBodySetup();

#if 0	// BRGTODO
	// warning for missing smoothing group info
	CheckSmoothingInfo(FbxMesh);
#endif
	
	FSkeletalMeshImportData TempData;
	// Fill with data from buffer
	FSkeletalMeshImportData* SkelMeshImportDataPtr = &TempData;
	if( OutData )
	{
		SkelMeshImportDataPtr = OutData;
	}
	
	// Get all material names here
	ImportMaterialsForSkelMesh(*SkelMeshImportDataPtr, ApexDestructibleAsset);

	// Import animation hierarchy, although this is trivial for an Apex Destructible Asset
	CreateBones(*SkelMeshImportDataPtr, ApexDestructibleAsset);

	// Import graphics data
	bool bHaveNormals, bHaveTangents;
	if (!FillSkelMeshImporterFromApexDestructibleAsset(*SkelMeshImportDataPtr, ApexDestructibleAsset, bHaveNormals, bHaveTangents))
	{
		return false;
	}

#if 0	// BRGTODO - what is this?
	if( SkelMeshImportDataPtr->Materials.Num() == FbxMatList.Num() )
	{
		// reorder material according to "SKinXX" in material name
		SetMaterialSkinXXOrder(*SkelMeshImportDataPtr, FbxMatList );
	}
#endif

#if 0	// BRGTODO - what is this?
	if( ImportOptions->bSplitNonMatchingTriangles )
	{
		DoUnSmoothVerts(*SkelMeshImportDataPtr);
	}
#endif

	// process materials from import data
	ProcessImportMeshMaterials( DestructibleMesh.Materials,*SkelMeshImportDataPtr );
	
	// process reference skeleton from import data
	int32 SkeletalDepth=0;
	if(!ProcessImportMeshSkeleton(DestructibleMesh.RefSkeleton, SkeletalDepth, *SkelMeshImportDataPtr))
	{
		return false;
	}
	UE_LOG(LogApexDestructibleAssetImport, Warning, TEXT("Bones digested - %i  Depth of hierarchy - %i"), DestructibleMesh.RefSkeleton.GetNum(), SkeletalDepth);

	// process bone influences from import data
	ProcessImportMeshInfluences(*SkelMeshImportDataPtr);

	FSkeletalMeshResource& DestructibleMeshResource = *DestructibleMesh.GetImportedResource();
	check(DestructibleMeshResource.LODModels.Num() == 0);
	DestructibleMeshResource.LODModels.Empty();
	new(DestructibleMeshResource.LODModels)FStaticLODModel();

	DestructibleMesh.LODInfo.Empty();
	DestructibleMesh.LODInfo.AddZeroed();
	DestructibleMesh.LODInfo[0].LODHysteresis = 0.02f;

	// Create initial bounding box based on expanded version of reference pose for meshes without physics assets. Can be overridden by artist.
	FBox BoundingBox(SkelMeshImportDataPtr->Points.GetData(), SkelMeshImportDataPtr->Points.Num());
	DestructibleMesh.Bounds= FBoxSphereBounds(BoundingBox);

	// Store whether or not this mesh has vertex colors
	DestructibleMesh.bHasVertexColors = SkelMeshImportDataPtr->bHasVertexColors;

	FStaticLODModel& LODModel = DestructibleMeshResource.LODModels[0];
	
	// Pass the number of texture coordinate sets to the LODModel.  Ensure there is at least one UV coord
	LODModel.NumTexCoords = FMath::Max<uint32>(1,SkelMeshImportDataPtr->NumTexCoords);
//	if( bCreateRenderData )	// We always create render data
	{
		// copy vertex data needed to generate skinning streams for LOD
		TArray<FVector> LODPoints;
		TArray<FMeshWedge> LODWedges;
		TArray<FMeshFace> LODFaces;
		TArray<FVertInfluence> LODInfluences;
		TArray<int32> LODPointToRawMap;
		SkelMeshImportDataPtr->CopyLODImportData(LODPoints,LODWedges,LODFaces,LODInfluences,LODPointToRawMap);

		IMeshUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshUtilities>("MeshUtilities");

		// Create actual rendering data.
		if (!MeshUtilities.BuildSkeletalMesh(DestructibleMeshResource.LODModels[0], DestructibleMesh.RefSkeleton, LODInfluences,LODWedges,LODFaces,LODPoints,LODPointToRawMap,false,!bHaveNormals,!bHaveTangents))
		{
			DestructibleMesh.MarkPendingKill();
			return false;
		}

		// Presize the per-section shadow casting array with the number of sections in the imported LOD.
		const int32 NumSections = LODModel.Sections.Num();

		for ( int32 SectionIndex = 0 ; SectionIndex < NumSections ; ++SectionIndex )
		{
			DestructibleMesh.LODInfo[0].TriangleSortSettings.AddZeroed();
		}

		if (ExistDestMeshDataPtr)
		{
			RestoreExistingDestMeshData(ExistDestMeshDataPtr, &DestructibleMesh);
			delete ExistDestMeshDataPtr;
			ExistDestMeshDataPtr = NULL;
		}

		DestructibleMesh.CalculateInvRefMatrices();
		DestructibleMesh.PostEditChange();
		DestructibleMesh.MarkPackageDirty();

#if 0 // BRGTODO : Check, we don't need this, do we?
		// We have to go and fix any AnimSetMeshLinkup objects that refer to this skeletal mesh, as the reference skeleton has changed.
		for(TObjectIterator<UAnimSet> It;It;++It)
		{
			UAnimSet* AnimSet = *It;

			// Get DestructibleMesh path name
			FName SkelMeshName = FName( *DestructibleMesh.GetPathName() );

			// See if we have already cached this Skeletal Mesh.
			const int32* IndexPtr = AnimSet->SkelMesh2LinkupCache.Find( SkelMeshName );

			if( IndexPtr )
			{
				AnimSet->LinkupCache( *IndexPtr ).BuildLinkup( &DestructibleMesh, AnimSet );
			}
		}
#endif

		// Now iterate over all skeletal mesh components re-initialising them.
		for(TObjectIterator<UDestructibleComponent> It; It; ++It)
		{
			UDestructibleComponent* DestructibleComponent = *It;
			if(DestructibleComponent->SkeletalMesh == &DestructibleMesh)
			{
				FComponentReregisterContext ReregisterContext(DestructibleComponent);
			}
		}
	}

#if INVERT_Y_AND_V
	// Apply transformation for Y inversion
	const physx::PxMat44 MirrorY = physx::PxMat44(physx::PxVec4(1.0f, -1.0f, 1.0f, 1.0f));
#if !USE_TEMPORARY_TRANSFORMATION_FUNCTION
	ApexDestructibleAsset.applyTransformation(MirrorY, 1.0f);
#else
	ApplyTransformationToApexDestructibleAsset( ApexDestructibleAsset, MirrorY );
#endif
#endif

	return true;
}
Пример #6
0
void UDestructibleComponent::CreatePhysicsState()
{
	// to avoid calling PrimitiveComponent, I'm just calling ActorComponent::CreatePhysicsState
	// @todo lh - fix me based on the discussion with Bryan G
	UActorComponent::CreatePhysicsState();
	bPhysicsStateCreated = true;

	// What we want to do with BodySetup is simply use it to store a PhysicalMaterial, and possibly some other relevant fields.  Set up pointers from the BodyInstance to the BodySetup and this component
	UBodySetup* BodySetup = GetBodySetup();
	BodyInstance.OwnerComponent	= this;
	BodyInstance.BodySetup = BodySetup;
	BodyInstance.InstanceBodyIndex = 0;

#if WITH_APEX
	if( SkeletalMesh == NULL )
	{
		return;
	}

	FPhysScene* PhysScene = World->GetPhysicsScene();
	check(PhysScene);

	if( GApexModuleDestructible == NULL )
	{
		UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::CreatePhysicsState(): APEX must be enabled to init UDestructibleComponent physics.") );
		return;
	}

	if( ApexDestructibleActor != NULL )
	{
		UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::CreatePhysicsState(): NxDestructibleActor already created.") );
		return;
	}

	UDestructibleMesh* TheDestructibleMesh = GetDestructibleMesh();
	if( TheDestructibleMesh == NULL || TheDestructibleMesh->ApexDestructibleAsset == NULL)
	{
		UE_LOG(LogPhysics, Log, TEXT("UDestructibleComponent::CreatePhysicsState(): No DestructibleMesh or missing ApexDestructibleAsset.") );
		return;
	}

	int32 ChunkCount = TheDestructibleMesh->ApexDestructibleAsset->getChunkCount();
	// Ensure the chunks start off invisible.  RefreshBoneTransforms should make them visible.
	for (int32 ChunkIndex = 0; ChunkIndex < ChunkCount; ++ChunkIndex)
	{
		SetChunkVisible(ChunkIndex, false);
	}

#if WITH_EDITOR
	if (GIsEditor && !World->IsGameWorld())
	{
		// In the editor, only set the 0 chunk to be visible.
		if (TheDestructibleMesh->ApexDestructibleAsset->getChunkCount() > 0)
		{
			SetChunkVisible(0, true);
		}
		return;
	}
#endif	// WITH_EDITOR

	// Only create physics in the game
	if( !World->IsGameWorld() )
	{
		return;
	}

	// Set template actor/body/shape properties

	// Find the PhysicalMaterial we need to apply to the physics bodies.
	UPhysicalMaterial* PhysMat = BodyInstance.GetSimplePhysicalMaterial();

	// Get the default actor descriptor NxParameterized data from the asset
	NxParameterized::Interface* ActorParams = TheDestructibleMesh->GetDestructibleActorDesc(PhysMat);

	// Create PhysX transforms from ComponentToWorld
	const PxMat44 GlobalPose(PxMat33(U2PQuat(ComponentToWorld.GetRotation())), U2PVector(ComponentToWorld.GetTranslation()));
	const PxVec3 Scale = U2PVector(ComponentToWorld.GetScale3D());

	// Set the transform in the actor descriptor
	verify( NxParameterized::setParamMat44(*ActorParams,"globalPose",GlobalPose) );
	verify( NxParameterized::setParamVec3(*ActorParams,"scale",Scale) );

	// Set the (initially) dynamic flag in the actor descriptor
	// See if we are 'static'
	verify( NxParameterized::setParamBool(*ActorParams,"dynamic", BodyInstance.bSimulatePhysics != false) );

	// Set the sleep velocity frame decay constant (was sleepVelocitySmoothingFactor) - a new feature that should help sleeping in large piles
	verify( NxParameterized::setParamF32(*ActorParams,"sleepVelocityFrameDecayConstant", 20.0f) );

	// Set up the shape desc template

	// Get collision channel and response
	PxFilterData PQueryFilterData, PSimFilterData;
	uint8 MoveChannel = GetCollisionObjectType();
	FCollisionResponseContainer CollResponse;
	if(IsCollisionEnabled())
	{
		// Only enable a collision response if collision is enabled
		CollResponse = GetCollisionResponseToChannels();

		LargeChunkCollisionResponse.SetCollisionResponseContainer(CollResponse);
		SmallChunkCollisionResponse.SetCollisionResponseContainer(CollResponse);
		SmallChunkCollisionResponse.SetResponse(ECC_Pawn, ECR_Overlap);
	}
	else
	{
		// now since by default it will all block, if collision is disabled, we need to set to ignore
		MoveChannel = ECC_WorldStatic;
		CollResponse.SetAllChannels(ECR_Ignore);
		LargeChunkCollisionResponse.SetAllChannels(ECR_Ignore);
		SmallChunkCollisionResponse.SetAllChannels(ECR_Ignore);
	}

	const bool bEnableImpactDamage = IsImpactDamageEnabled(TheDestructibleMesh, 0);
	const bool bEnableContactModification = TheDestructibleMesh->DefaultDestructibleParameters.DamageParameters.bCustomImpactResistance && TheDestructibleMesh->DefaultDestructibleParameters.DamageParameters.ImpactResistance > 0.f;

	// Passing AssetInstanceID = 0 so we'll have self-collision
	AActor* Owner = GetOwner();
	CreateShapeFilterData(MoveChannel, GetUniqueID(), CollResponse, 0, 0, PQueryFilterData, PSimFilterData, BodyInstance.bUseCCD, bEnableImpactDamage, false, bEnableContactModification);

	// Build filterData variations for complex and simple
	PSimFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision;
	PQueryFilterData.word3 |= EPDF_SimpleCollision | EPDF_ComplexCollision;

	// Set the filterData in the shape descriptor
	verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.simulationFilterData.word0", PSimFilterData.word0 ) );
	verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.simulationFilterData.word1", PSimFilterData.word1 ) );
	verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.simulationFilterData.word2", PSimFilterData.word2 ) );
	verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.simulationFilterData.word3", PSimFilterData.word3 ) );
	verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.queryFilterData.word0", PQueryFilterData.word0 ) );
	verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.queryFilterData.word1", PQueryFilterData.word1 ) );
	verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.queryFilterData.word2", PQueryFilterData.word2 ) );
	verify( NxParameterized::setParamU32(*ActorParams,"p3ShapeDescTemplate.queryFilterData.word3", PQueryFilterData.word3 ) );

	// Set the PhysX material in the shape descriptor
	PxMaterial* PMaterial = PhysMat->GetPhysXMaterial();
	verify( NxParameterized::setParamU64(*ActorParams,"p3ShapeDescTemplate.material", (physx::PxU64)PMaterial) );

	// Set the rest depth to match the skin width in the shape descriptor
	const physx::PxCookingParams& CookingParams = GApexSDK->getCookingInterface()->getParams();
	verify( NxParameterized::setParamF32(*ActorParams,"p3ShapeDescTemplate.restOffset", -CookingParams.skinWidth) );

	// Set the PhysX material in the actor descriptor
	verify( NxParameterized::setParamBool(*ActorParams,"p3ActorDescTemplate.flags.eDISABLE_GRAVITY",false) );
	verify( NxParameterized::setParamBool(*ActorParams,"p3ActorDescTemplate.flags.eVISUALIZATION",true) );

	// Set the PxActor's and PxShape's userData fields to this component's body instance
	verify( NxParameterized::setParamU64(*ActorParams,"p3ActorDescTemplate.userData", 0 ) );

	// All shapes created by this DestructibleActor will have the userdata of the owning component.
	// We need this, as in some cases APEX is moving shapes accross actors ( ex. FormExtended structures )
	verify( NxParameterized::setParamU64(*ActorParams,"p3ShapeDescTemplate.userData", (PxU64)&PhysxUserData ) );

	// Set up the body desc template in the actor descriptor
	verify( NxParameterized::setParamF32(*ActorParams,"p3BodyDescTemplate.angularDamping", BodyInstance.AngularDamping ) );
	verify( NxParameterized::setParamF32(*ActorParams,"p3BodyDescTemplate.linearDamping", BodyInstance.LinearDamping ) );
	const PxTolerancesScale& PScale = GPhysXSDK->getTolerancesScale();
	PxF32 SleepEnergyThreshold = 0.00005f*PScale.speed*PScale.speed;	// 1/1000 Default, since the speed scale is quite high
	if (BodyInstance.SleepFamily == ESleepFamily::Sensitive)
	{
		SleepEnergyThreshold /= 20.0f;
	}
	verify( NxParameterized::setParamF32(*ActorParams,"p3BodyDescTemplate.sleepThreshold", SleepEnergyThreshold) );
//	NxParameterized::setParamF32(*ActorParams,"bodyDescTemplate.sleepDamping", SleepDamping );
	verify( NxParameterized::setParamF32(*ActorParams,"p3BodyDescTemplate.density", 0.001f*PhysMat->Density) );	// Convert from g/cm^3 to kg/cm^3
	// Enable CCD if requested
	verify( NxParameterized::setParamBool(*ActorParams,"p3BodyDescTemplate.flags.eENABLE_CCD", BodyInstance.bUseCCD != 0) );
	// Ask the actor to create chunk events, for more efficient visibility updates
	verify( NxParameterized::setParamBool(*ActorParams,"createChunkEvents", true) );

	// Enable hard sleeping if requested
	verify( NxParameterized::setParamBool(*ActorParams,"useHardSleeping", bEnableHardSleeping) );

	

	// Destructibles are always dynamic or kinematic, and therefore only go into one of the scenes
	const uint32 SceneType = BodyInstance.UseAsyncScene(PhysScene) ? PST_Async : PST_Sync;
	NxApexScene* ApexScene = PhysScene->GetApexScene(SceneType);
	PxScene* PScene = PhysScene->GetPhysXScene(SceneType);

	BodyInstance.SceneIndexSync = SceneType == PST_Sync ? PhysScene->PhysXSceneIndex[PST_Sync] : 0;
	BodyInstance.SceneIndexAsync = SceneType == PST_Async ? PhysScene->PhysXSceneIndex[PST_Async] : 0;
	check(ApexScene);

	ChunkInfos.Reset(ChunkCount);
	ChunkInfos.AddZeroed(ChunkCount);
	PhysxChunkUserData.Reset(ChunkCount);
	PhysxChunkUserData.AddZeroed(ChunkCount);

	// Create an APEX NxDestructibleActor from the Destructible asset and actor descriptor
	ApexDestructibleActor = static_cast<NxDestructibleActor*>(TheDestructibleMesh->ApexDestructibleAsset->createApexActor(*ActorParams, *ApexScene));
	check(ApexDestructibleActor);

	// Make a backpointer to this component
	PhysxUserData = FPhysxUserData(this);
	ApexDestructibleActor->userData = &PhysxUserData;

	// Cache cooked collision data
	// BRGTODO : cook in asset
	ApexDestructibleActor->cacheModuleData();

	// BRGTODO : Per-actor LOD setting
//	ApexDestructibleActor->forcePhysicalLod( DestructibleActor->LOD );

	// Start asleep if requested
	PxRigidDynamic* PRootActor = ApexDestructibleActor->getChunkPhysXActor(0);


	//  Put to sleep or wake up only if the component is physics-simulated
	if (PRootActor != NULL && BodyInstance.bSimulatePhysics)
	{
		SCOPED_SCENE_WRITE_LOCK(PScene);	//Question, since apex is defer adding actors do we need to lock? Locking the async scene is expensive!

		PRootActor->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, !BodyInstance.bEnableGravity);

		// Sleep/wake up as appropriate
		if (!BodyInstance.bStartAwake)
		{
			ApexDestructibleActor->setChunkPhysXActorAwakeState(0, false);
		}
		}

	UpdateBounds();
#endif	// #if WITH_APEX
}
void FDestructibleMeshEditorViewportClient::ImportFBXChunks()
{
	// Get the FBX that we want to import
	TArray<FString> OpenFilenames;
	IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
	bool bOpened = false;
	if (DesktopPlatform != NULL)
	{
		bOpened = DesktopPlatform->OpenFileDialog(
			NULL, 
			NSLOCTEXT("UnrealEd", "ImportMatineeSequence", "Import UnrealMatinee Sequence").ToString(),
			*(FEditorDirectories::Get().GetLastDirectory(ELastDirectory::GENERIC_IMPORT)),
			TEXT(""),
			TEXT("FBX document|*.fbx"),
			EFileDialogFlags::None, 
			OpenFilenames);
	}

	if (bOpened)
	{
		// Get the filename from dialog
		FString ImportFilename = OpenFilenames[0];
		FString FileName = OpenFilenames[0];
		FEditorDirectories::Get().SetLastDirectory(ELastDirectory::GENERIC_IMPORT, FPaths::GetPath(FileName)); // Save path as default for next time.

		const FString FileExtension = FPaths::GetExtension(FileName);
		const bool bIsFBX = FCString::Stricmp(*FileExtension, TEXT("FBX")) == 0;

		if (bIsFBX)
		{
			FlushRenderingCommands();

			UnFbx::FFbxImporter* FFbxImporter = UnFbx::FFbxImporter::GetInstance();
			if (FFbxImporter->ImportFromFile( *ImportFilename, FPaths::GetExtension( ImportFilename ) ) )
			{
				TArray<FbxNode*> FbxMeshArray;
				FFbxImporter->FillFbxMeshArray(FFbxImporter->Scene->GetRootNode(), FbxMeshArray, FFbxImporter);

				UFbxStaticMeshImportData* ImportData = NewObject<UFbxStaticMeshImportData>(GetTransientPackage(), NAME_None, RF_NoFlags, NULL);

				TArray<UStaticMesh*> ChunkMeshes;

				for (int32 i=0; i < FbxMeshArray.Num(); ++i)
				{
					UStaticMesh* TempStaticMesh = NULL;
					TempStaticMesh = (UStaticMesh*)FFbxImporter->ImportStaticMesh(GetTransientPackage(), FbxMeshArray[i], NAME_None, RF_NoFlags, ImportData, 0);

					ChunkMeshes.Add(TempStaticMesh);
				}

				UDestructibleMesh* DestructibleMesh = DestructibleMeshEditorPtr.Pin()->GetDestructibleMesh();
				if (DestructibleMesh)
				{
					DestructibleMesh->SetupChunksFromStaticMeshes(ChunkMeshes);
				}
			}

			FFbxImporter->ReleaseScene();

			// Update the viewport
			DestructibleMeshEditorPtr.Pin()->RefreshTool();
			DestructibleMeshEditorPtr.Pin()->SetCurrentPreviewDepth(0xFFFFFFFF);	// This will get clamped to the max depth
		}
		else
		{
			// Invalid filename 
		}
	}
#if WITH_APEX
#endif // WITH_APEX
}