// Copyright Epic Games, Inc. All Rights Reserved. #include "ModelingToolTargetUtil.h" #include "ToolTargets/ToolTarget.h" #include "TargetInterfaces/MaterialProvider.h" #include "TargetInterfaces/MeshDescriptionCommitter.h" #include "TargetInterfaces/MeshDescriptionProvider.h" #include "TargetInterfaces/PrimitiveComponentBackedTarget.h" #include "TargetInterfaces/DynamicMeshSource.h" #include "ModelingObjectsCreationAPI.h" #include "Components/PrimitiveComponent.h" #include "Components/StaticMeshComponent.h" #include "GameFramework/Volume.h" #include "Components/DynamicMeshComponent.h" #include "MeshConversionOptions.h" #include "MeshDescriptionToDynamicMesh.h" #include "DynamicMeshToMeshDescription.h" #define LOCTEXT_NAMESPACE "ModelingToolTargetUtil" using namespace UE::Geometry; AActor* UE::ToolTarget::GetTargetActor(UToolTarget* Target) { IPrimitiveComponentBackedTarget* TargetComponent = Cast(Target); if (TargetComponent) { return TargetComponent->GetOwnerActor(); } ensure(false); return nullptr; } UPrimitiveComponent* UE::ToolTarget::GetTargetComponent(UToolTarget* Target) { IPrimitiveComponentBackedTarget* TargetComponent = Cast(Target); if (TargetComponent) { return TargetComponent->GetOwnerComponent(); } ensure(false); return nullptr; } bool UE::ToolTarget::HideSourceObject(UToolTarget* Target) { IPrimitiveComponentBackedTarget* TargetComponent = Cast(Target); if (TargetComponent) { TargetComponent->SetOwnerVisibility(false); return true; } ensure(false); return false; } bool UE::ToolTarget::ShowSourceObject(UToolTarget* Target) { IPrimitiveComponentBackedTarget* TargetComponent = Cast(Target); if (TargetComponent) { TargetComponent->SetOwnerVisibility(true); return true; } ensure(false); return false; } bool UE::ToolTarget::SetSourceObjectVisible(UToolTarget* Target, bool bVisible) { if (bVisible) { return ShowSourceObject(Target); } else { return HideSourceObject(Target); } } FTransform3d UE::ToolTarget::GetLocalToWorldTransform(UToolTarget* Target) { IPrimitiveComponentBackedTarget* TargetComponent = Cast(Target); if (TargetComponent) { return (FTransform3d)TargetComponent->GetWorldTransform(); } ensure(false); return FTransform3d(); } FComponentMaterialSet UE::ToolTarget::GetMaterialSet(UToolTarget* Target, bool bPreferAssetMaterials) { FComponentMaterialSet MaterialSet; IMaterialProvider* MaterialProvider = Cast(Target); if (ensure(MaterialProvider)) { MaterialProvider->GetMaterialSet(MaterialSet, bPreferAssetMaterials); } return MaterialSet; } bool UE::ToolTarget::CommitMaterialSetUpdate( UToolTarget* Target, const FComponentMaterialSet& UpdatedMaterials, bool bApplyToAsset) { IMaterialProvider* MaterialProvider = Cast(Target); if (MaterialProvider) { return MaterialProvider->CommitMaterialSetUpdate(UpdatedMaterials, bApplyToAsset); } return false; } const FMeshDescription* UE::ToolTarget::GetMeshDescription(UToolTarget* Target) { static FMeshDescription EmptyMeshDescription; IMeshDescriptionProvider* MeshDescriptionProvider = Cast(Target); if (MeshDescriptionProvider) { return MeshDescriptionProvider->GetMeshDescription(); } ensure(false); return &EmptyMeshDescription; } FMeshDescription UE::ToolTarget::GetMeshDescriptionCopy(UToolTarget* Target, bool bWantMeshTangents) { IMeshDescriptionProvider* MeshDescriptionProvider = Cast(Target); if (MeshDescriptionProvider) { FMeshDescription NewMeshDescription = *MeshDescriptionProvider->GetMeshDescription(); if (bWantMeshTangents) { MeshDescriptionProvider->CalculateAutoGeneratedAttributes(NewMeshDescription); } return NewMeshDescription; } ensure(false); return FMeshDescription(); } FDynamicMesh3 UE::ToolTarget::GetDynamicMeshCopy(UToolTarget* Target, bool bWantMeshTangents) { IPersistentDynamicMeshSource* DynamicMeshSource = Cast(Target); if (DynamicMeshSource) { UDynamicMesh* DynamicMesh = DynamicMeshSource->GetDynamicMeshContainer(); FDynamicMesh3 Mesh; DynamicMesh->ProcessMesh([&](const FDynamicMesh3& ReadMesh) { Mesh = ReadMesh; }); return Mesh; } IMeshDescriptionProvider* MeshDescriptionProvider = Cast(Target); FDynamicMesh3 Mesh(EMeshComponents::FaceGroups); Mesh.EnableAttributes(); if (MeshDescriptionProvider) { FMeshDescriptionToDynamicMesh Converter; if (bWantMeshTangents) { // Currently to auto-calculate attributes we must make a copy, because they are written // directly to the input mesh FMeshDescription MeshDescriptionCopy( *MeshDescriptionProvider->GetMeshDescription() ); MeshDescriptionProvider->CalculateAutoGeneratedAttributes(MeshDescriptionCopy); Converter.Convert(&MeshDescriptionCopy, Mesh, bWantMeshTangents); } else { Converter.Convert(MeshDescriptionProvider->GetMeshDescription(), Mesh, bWantMeshTangents); } return Mesh; } ensure(false); return Mesh; } UE::ToolTarget::EDynamicMeshUpdateResult UE::ToolTarget::CommitMeshDescriptionUpdate(UToolTarget* Target, const FMeshDescription* UpdatedMesh, const FComponentMaterialSet* UpdatedMaterials) { IMeshDescriptionCommitter* MeshDescriptionCommitter = Cast(Target); if (!ensure(MeshDescriptionCommitter)) { return EDynamicMeshUpdateResult::Failed; } if (UpdatedMaterials != nullptr) { CommitMaterialSetUpdate(Target, *UpdatedMaterials, true); } EDynamicMeshUpdateResult Result = EDynamicMeshUpdateResult::Failed; MeshDescriptionCommitter->CommitMeshDescription([UpdatedMesh, &Result](const IMeshDescriptionCommitter::FCommitterParams& CommitParams) { *CommitParams.MeshDescriptionOut = *UpdatedMesh; Result = EDynamicMeshUpdateResult::Ok; }); return Result; } UE::ToolTarget::EDynamicMeshUpdateResult UE::ToolTarget::CommitDynamicMeshUpdate( UToolTarget* Target, const FDynamicMesh3& UpdatedMesh, bool bHaveModifiedTopology, const FConversionToMeshDescriptionOptions& ConversionOptions, const FComponentMaterialSet* UpdatedMaterials) { if (UpdatedMaterials != nullptr) { CommitMaterialSetUpdate(Target, *UpdatedMaterials, true); } IPersistentDynamicMeshSource* DynamicMeshSource = Cast(Target); if (DynamicMeshSource) { UDynamicMesh* DynamicMesh = DynamicMeshSource->GetDynamicMeshContainer(); TUniquePtr CurrentMesh = DynamicMesh->ExtractMesh(); TSharedPtr CurrentMeshShared(CurrentMesh.Release()); DynamicMesh->EditMesh([&](FDynamicMesh3& EditMesh) { EditMesh = UpdatedMesh; }); TSharedPtr NewMeshShared = MakeShared(); DynamicMesh->ProcessMesh([&](const FDynamicMesh3& ReadMesh) { *NewMeshShared = ReadMesh; }); TUniquePtr ReplaceChange = MakeUnique(CurrentMeshShared, NewMeshShared); DynamicMeshSource->CommitDynamicMeshChange(MoveTemp(ReplaceChange), LOCTEXT("CommitDynamicMeshUpdate_MeshSource", "Edit Mesh")); // todo support bModifiedTopology flag? return EDynamicMeshUpdateResult::Ok; } IMeshDescriptionCommitter* MeshDescriptionCommitter = Cast(Target); if (MeshDescriptionCommitter) { EDynamicMeshUpdateResult Result = EDynamicMeshUpdateResult::Failed; MeshDescriptionCommitter->CommitMeshDescription([&](const IMeshDescriptionCommitter::FCommitterParams& CommitParams) { FMeshDescription* MeshDescription = CommitParams.MeshDescriptionOut; FDynamicMeshToMeshDescription Converter(ConversionOptions); if (!bHaveModifiedTopology) { Converter.UpdateUsingConversionOptions(&UpdatedMesh, *MeshDescription); Result = EDynamicMeshUpdateResult::Ok; } else { Converter.Convert(&UpdatedMesh, *MeshDescription); Result = EDynamicMeshUpdateResult::Ok; } }); return Result; } ensure(false); return EDynamicMeshUpdateResult::Failed; } UE::ToolTarget::EDynamicMeshUpdateResult UE::ToolTarget::CommitDynamicMeshUVUpdate(UToolTarget* Target, const UE::Geometry::FDynamicMesh3* UpdatedMesh) { IPersistentDynamicMeshSource* DynamicMeshSource = Cast(Target); if (DynamicMeshSource) { // todo actually only update UVs? UDynamicMesh* DynamicMesh = DynamicMeshSource->GetDynamicMeshContainer(); DynamicMesh->EditMesh([&](FDynamicMesh3& EditMesh) { EditMesh = *UpdatedMesh; }); return EDynamicMeshUpdateResult::Ok; } IMeshDescriptionCommitter* MeshDescriptionCommitter = Cast(Target); if (!ensure(MeshDescriptionCommitter)) { return EDynamicMeshUpdateResult::Failed; } EDynamicMeshUpdateResult Result = EDynamicMeshUpdateResult::Failed; MeshDescriptionCommitter->CommitMeshDescription([UpdatedMesh, &Result](const IMeshDescriptionCommitter::FCommitterParams& CommitParams) { FMeshDescription* MeshDescription = CommitParams.MeshDescriptionOut; bool bVerticesOnly = false; bool bAttributesOnly = true; if (FDynamicMeshToMeshDescription::HaveMatchingElementCounts(UpdatedMesh, MeshDescription, bVerticesOnly, bAttributesOnly)) { FDynamicMeshToMeshDescription Converter; Converter.UpdateAttributes(UpdatedMesh, *MeshDescription, false, false, true/*update uvs*/); Result = EDynamicMeshUpdateResult::Ok; } else { // must have been duplicate tris in the mesh description; we can't count on 1-to-1 mapping of TriangleIDs. Just convert FDynamicMeshToMeshDescription Converter; Converter.Convert(UpdatedMesh, *MeshDescription); Result = EDynamicMeshUpdateResult::Ok_ForcedFullUpdate; } }); return Result; } bool UE::ToolTarget::ConfigureCreateMeshObjectParams(UToolTarget* SourceTarget, FCreateMeshObjectParams& DerivedParamsOut) { IPrimitiveComponentBackedTarget* ComponentTarget = Cast(SourceTarget); if (ComponentTarget) { if (Cast(ComponentTarget->GetOwnerComponent()) != nullptr) { DerivedParamsOut.TypeHint = ECreateObjectTypeHint::StaticMesh; return true; } if (Cast(ComponentTarget->GetOwnerComponent()) != nullptr) { DerivedParamsOut.TypeHint = ECreateObjectTypeHint::DynamicMeshActor; return true; } AVolume* VolumeActor = Cast(ComponentTarget->GetOwnerActor()); if (VolumeActor != nullptr) { DerivedParamsOut.TypeHint = ECreateObjectTypeHint::Volume; DerivedParamsOut.TypeHintClass = VolumeActor->GetClass(); return true; } } return false; } #undef LOCTEXT_NAMESPACE