Added importer UI for usd vehicles

This commit is contained in:
Axel 2023-03-30 12:25:11 +02:00 committed by bernat
parent ade852e619
commit 359806f9b0
5 changed files with 450 additions and 1 deletions

View File

@ -0,0 +1,41 @@
#!/usr/bin/env python
"""
Script to add new vehicles to the vehicle factory and json file
"""
import unreal
import argparse
import json
argparser = argparse.ArgumentParser()
argparser.add_argument(
'-v', '--vehicle_blueprint_path',
metavar='V',
default='',
type=str,
help='Path to add to the vehicle blueprint')
argparser.add_argument(
'-n', '--name',
metavar='N',
default='',
type=str,
help='vehicle name')
args = argparser.parse_args()
# load vehicle and factory
vehicle_factory_path = '/Game/Carla/Blueprints/Vehicles/VehicleFactory.VehicleFactory_C'
vehicle_factory_class = unreal.load_object(None, vehicle_factory_path)
vehicle_factory_default_object = unreal.get_default_object(vehicle_factory_class)
vehicle_blueprint_path = args.vehicle_blueprint_path + '_C'
vehicle_blueprint = unreal.load_object(None, vehicle_blueprint_path)
vehicle_list = vehicle_factory_default_object.get_editor_property("Vehicles")
# generate the new field
new_vehicle_parameters = unreal.VehicleParameters()
new_vehicle_parameters.make = 'usd'
new_vehicle_parameters.model = args.name
new_vehicle_parameters.class_ = vehicle_blueprint
new_vehicle_parameters.generation = 2
new_vehicle_parameters.base_type = 'car'
# add to the vehicle list
vehicle_list.append(new_vehicle_parameters)

View File

@ -9,6 +9,16 @@
#include "IMeshMergeUtilities.h" #include "IMeshMergeUtilities.h"
#include "MeshMergeModule.h" #include "MeshMergeModule.h"
#include "Components/PrimitiveComponent.h" #include "Components/PrimitiveComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "Engine/Blueprint.h"
#include "ReferenceSkeleton.h"
#include "Components/SkeletalMeshComponent.h"
#include "PackageHelperFunctions.h"
#include "EditorAssetLibrary.h"
#include <unordered_map>
#include <string>
void UUSDImporterWidget::ImportUSDProp( void UUSDImporterWidget::ImportUSDProp(
@ -68,3 +78,292 @@ bool UUSDImporterWidget::MergeStaticMeshComponents(
MeshUtilities.MergeComponentsToStaticMesh(ComponentsToMerge, World, MeshMergeSettings, nullptr, nullptr, DestMesh, AssetsToSync, NewLocation, ScreenAreaSize, true); MeshUtilities.MergeComponentsToStaticMesh(ComponentsToMerge, World, MeshMergeSettings, nullptr, nullptr, DestMesh, AssetsToSync, NewLocation, ScreenAreaSize, true);
return true; return true;
} }
TArray<UObject*> UUSDImporterWidget::MergeMeshComponents(
TArray<UPrimitiveComponent*> ComponentsToMerge,
const FString& DestMesh)
{
if(!ComponentsToMerge.Num())
{
return {};
}
UWorld* World = ComponentsToMerge[0]->GetWorld();
const IMeshMergeUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshMergeModule>("MeshMergeUtilities").GetUtilities();
FMeshMergingSettings MeshMergeSettings;
TArray<UObject*> AssetsToSync;
const float ScreenAreaSize = TNumericLimits<float>::Max();
FVector NewLocation;
MeshUtilities.MergeComponentsToStaticMesh(ComponentsToMerge, World, MeshMergeSettings, nullptr, nullptr, DestMesh, AssetsToSync, NewLocation, ScreenAreaSize, true);
return AssetsToSync;
}
bool IsChildrenOf(USceneComponent* Component, FString StringInParent)
{
USceneComponent* CurrentComponent = Component;
while(CurrentComponent)
{
FString ComponentName = UKismetSystemLibrary::GetDisplayName(CurrentComponent);
if(ComponentName.Contains(StringInParent))
{
return true;
}
CurrentComponent = CurrentComponent->GetAttachParent();
}
return false;
}
FVehicleMeshParts UUSDImporterWidget::SplitVehicleParts(AActor* BlueprintActor)
{
FVehicleMeshParts Result;
TArray<UStaticMeshComponent*> MeshComponents;
BlueprintActor->GetComponents(MeshComponents, false);
FVector BodyLocation = FVector(0,0,0);
for (UStaticMeshComponent* Component : MeshComponents)
{
if (!Component->GetStaticMesh())
{
continue;
}
FString ComponentName = UKismetSystemLibrary::GetDisplayName(Component);
if (ComponentName.Contains("door_0"))
{
Result.DoorFL.Add(Component);
Result.Anchors.DoorFL = Component->GetComponentTransform().GetLocation();
}
else if (ComponentName.Contains("door_1"))
{
Result.DoorFR.Add(Component);
Result.Anchors.DoorFR = Component->GetComponentTransform().GetLocation();
}
else if (ComponentName.Contains("door_2"))
{
Result.DoorRL.Add(Component);
Result.Anchors.DoorRL = Component->GetComponentTransform().GetLocation();
}
else if (ComponentName.Contains("door_3"))
{
Result.DoorRR.Add(Component);
Result.Anchors.DoorRR = Component->GetComponentTransform().GetLocation();
}
else if (ComponentName.Contains("trunk"))
{
Result.Trunk.Add(Component);
Result.Anchors.Trunk = Component->GetComponentTransform().GetLocation();
}
else if (ComponentName.Contains("hood"))
{
Result.Hood.Add(Component);
Result.Anchors.Hood = Component->GetComponentTransform().GetLocation();
}
else if (IsChildrenOf(Component, "suspension_0"))
{
Result.WheelFL.Add(Component);
if (ComponentName.Contains("wheel"))
{
Result.Anchors.WheelFL = Component->GetComponentTransform().GetLocation();
}
}
else if (IsChildrenOf(Component, "suspension_1"))
{
Result.WheelFR.Add(Component);
if (ComponentName.Contains("wheel"))
{
Result.Anchors.WheelFR = Component->GetComponentTransform().GetLocation();
}
}
else if (IsChildrenOf(Component, "suspension_2"))
{
Result.WheelRL.Add(Component);
if (ComponentName.Contains("wheel"))
{
Result.Anchors.WheelRL = Component->GetComponentTransform().GetLocation();
}
}
else if (IsChildrenOf(Component, "suspension_3"))
{
Result.WheelRR.Add(Component);
if (ComponentName.Contains("wheel"))
{
Result.Anchors.WheelRR = Component->GetComponentTransform().GetLocation();
}
}
else if (ComponentName.Contains("Collision"))
{
}
else
{
Result.Body.Add(Component);
if (ComponentName.Contains("body"))
{
BodyLocation = Component->GetComponentTransform().GetLocation();
}
}
}
Result.Anchors.DoorFR -= BodyLocation;
Result.Anchors.DoorFL -= BodyLocation;
Result.Anchors.DoorRR -= BodyLocation;
Result.Anchors.DoorRL -= BodyLocation;
Result.Anchors.WheelFR -= BodyLocation;
Result.Anchors.WheelFL -= BodyLocation;
Result.Anchors.WheelRR -= BodyLocation;
Result.Anchors.WheelRL -= BodyLocation;
Result.Anchors.Hood -= BodyLocation;
Result.Anchors.Trunk -= BodyLocation;
return Result;
}
FMergedVehicleMeshParts UUSDImporterWidget::GenerateVehicleMeshes(
const FVehicleMeshParts& VehicleMeshParts, const FString& DestPath)
{
FMergedVehicleMeshParts Result;
auto MergePart =
[](TArray<UPrimitiveComponent*> Components, const FString& DestMeshPath)
-> UStaticMesh*
{
if (!Components.Num())
{
return nullptr;
}
TArray<UObject*> Output = MergeMeshComponents(Components, DestMeshPath);
if (Output.Num())
{
return Cast<UStaticMesh>(Output[0]);
}
else
{
return nullptr;
}
};
Result.DoorFR = MergePart(VehicleMeshParts.DoorFR, DestPath + "_door_fr");
Result.DoorFL = MergePart(VehicleMeshParts.DoorFL, DestPath + "_door_fl");
Result.DoorRR = MergePart(VehicleMeshParts.DoorRR, DestPath + "_door_rr");
Result.DoorRL = MergePart(VehicleMeshParts.DoorRL, DestPath + "_door_rl");
Result.Trunk = MergePart(VehicleMeshParts.Trunk, DestPath + "_trunk");
Result.Hood = MergePart(VehicleMeshParts.Hood, DestPath + "_hood");
Result.WheelFR = MergePart(VehicleMeshParts.WheelFR, DestPath + "_wheel_fr");
Result.WheelFL = MergePart(VehicleMeshParts.WheelFL, DestPath + "_wheel_fl");
Result.WheelRR = MergePart(VehicleMeshParts.WheelRR, DestPath + "_wheel_rr");
Result.WheelRL = MergePart(VehicleMeshParts.WheelRL, DestPath + "_wheel_rl");
Result.Body = MergePart(VehicleMeshParts.Body, DestPath + "_body");
Result.Anchors = VehicleMeshParts.Anchors;
return Result;
}
AActor* UUSDImporterWidget::GenerateNewVehicleBlueprint(
UWorld* World,
UClass* BaseClass,
USkeletalMesh* NewSkeletalMesh,
const FString &DestPath,
const FMergedVehicleMeshParts& VehicleMeshes)
{
std::unordered_map<std::string, std::pair<UStaticMesh*, FVector>> MeshMap = {
{"SM_DoorFR", {VehicleMeshes.DoorFR, VehicleMeshes.Anchors.DoorFR}},
{"SM_DoorFL", {VehicleMeshes.DoorFL, VehicleMeshes.Anchors.DoorFL}},
{"SM_DoorRR", {VehicleMeshes.DoorRR, VehicleMeshes.Anchors.DoorRR}},
{"SM_DoorRL", {VehicleMeshes.DoorRL, VehicleMeshes.Anchors.DoorRL}},
{"Trunk", {VehicleMeshes.Trunk, VehicleMeshes.Anchors.Trunk}},
{"Hood", {VehicleMeshes.Hood, VehicleMeshes.Anchors.Hood}},
{"Wheel_FR", {VehicleMeshes.WheelFR, FVector(0,0,0)}},
{"Wheel_FL", {VehicleMeshes.WheelFL, FVector(0,0,0)}},
{"Wheel_RR", {VehicleMeshes.WheelRR, FVector(0,0,0)}},
{"Wheel_RL", {VehicleMeshes.WheelRL, FVector(0,0,0)}},
{"Body", {VehicleMeshes.Body, FVector(0,0,0)}}
};
AActor* TemplateActor = World->SpawnActor<AActor>(BaseClass);
// Get an replace all static meshes with the appropiate mesh
TArray<UStaticMeshComponent*> MeshComponents;
TemplateActor->GetComponents(MeshComponents);
for (UStaticMeshComponent* Component : MeshComponents)
{
std::string ComponentName = TCHAR_TO_UTF8(*Component->GetName());
auto &MapElement = MeshMap[ComponentName];
UStaticMesh* ComponentMesh = MapElement.first;
FVector MeshLocation = MapElement.second;
if(ComponentMesh)
{
Component->SetStaticMesh(ComponentMesh);
Component->SetRelativeLocation(MeshLocation);
}
UE_LOG(LogCarlaTools, Log, TEXT("Component name %s, name %s"),
*UKismetSystemLibrary::GetDisplayName(Component), *Component->GetName());
}
// Get the skeletal mesh and modify it to match the vehicle parameters
USkeletalMeshComponent* SkeletalMeshComponent = Cast<USkeletalMeshComponent>(
TemplateActor->GetComponentByClass(USkeletalMeshComponent::StaticClass()));
if(!SkeletalMeshComponent)
{
UE_LOG(LogCarlaTools, Log, TEXT("Skeletal mesh component not found"));
return nullptr;
}
USkeletalMesh* SkeletalMesh = SkeletalMeshComponent->SkeletalMesh;
TMap<FString, FTransform> NewBoneTransform = {
{"Wheel_Front_Left", FTransform(VehicleMeshes.Anchors.WheelFL)},
{"Wheel_Front_Right", FTransform(VehicleMeshes.Anchors.WheelFR)},
{"Wheel_Rear_Right", FTransform(VehicleMeshes.Anchors.WheelRR)},
{"Wheel_Rear_Left", FTransform(VehicleMeshes.Anchors.WheelRL)}
};
if(!SkeletalMesh)
{
UE_LOG(LogCarlaTools, Log, TEXT("Mesh not generated, skeletal mesh missing"));
return nullptr;
}
bool bSuccess = EditSkeletalMeshBones(NewSkeletalMesh, NewBoneTransform);
if (!NewSkeletalMesh || !bSuccess)
{
UE_LOG(LogCarlaTools, Log, TEXT("Blueprint generation error"));
return nullptr;
}
SkeletalMeshComponent->SetSkeletalMesh(NewSkeletalMesh);
// Create the new blueprint vehicle
FKismetEditorUtilities::FCreateBlueprintFromActorParams Params;
Params.bReplaceActor = true;
Params.bKeepMobility = true;
Params.bDeferCompilation = false;
Params.bOpenBlueprint = false;
Params.ParentClassOverride = BaseClass;
FKismetEditorUtilities::CreateBlueprintFromActor(
DestPath,
TemplateActor,
Params);
return nullptr;
}
bool UUSDImporterWidget::EditSkeletalMeshBones(
USkeletalMesh* NewSkeletalMesh,
const TMap<FString, FTransform> &NewBoneTransforms)
{
if(!NewSkeletalMesh)
{
UE_LOG(LogCarlaTools, Log, TEXT("Skeletal mesh invalid"));
return false;
}
FReferenceSkeleton& ReferenceSkeleton = NewSkeletalMesh->RefSkeleton;
FReferenceSkeletonModifier SkeletonModifier(ReferenceSkeleton, NewSkeletalMesh->Skeleton);
for (auto& Element : NewBoneTransforms)
{
const FString& BoneName = Element.Key;
const FTransform& BoneTransform = Element.Value;
int32 BoneIdx = SkeletonModifier.FindBoneIndex(FName(*BoneName));
if (BoneIdx == INDEX_NONE)
{
UE_LOG(LogCarlaTools, Log, TEXT("Bone %s not found"), *BoneName);
}
UE_LOG(LogCarlaTools, Log, TEXT("Bone %s corresponds to index %d"), *BoneName, BoneIdx);
SkeletonModifier.UpdateRefPoseTransform(BoneIdx, BoneTransform);
}
// UE_LOG(LogCarlaTools, Log, TEXT("Creating new skeletal mesh in path %s"), *PackagePath);
// UPackage* NewPackage = CreatePackage(nullptr, *PackagePath);
// UObject* NewObject = DuplicateObject(Skeleton, NewPackage);
// SavePackageHelper(NewPackage, *PackagePath);
NewSkeletalMesh->MarkPackageDirty();
UPackage* Package = NewSkeletalMesh->GetOutermost();
return UPackage::SavePackage(
Package, NewSkeletalMesh,
EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
*(Package->GetName()), GError, nullptr, true, true, SAVE_NoError);
}

View File

@ -4,15 +4,106 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Blueprint/UserWidget.h" #include "Blueprint/UserWidget.h"
#include "Animation/Skeleton.h"
#include "USDImporterWidget.generated.h" #include "USDImporterWidget.generated.h"
USTRUCT(BlueprintType)
struct CARLATOOLS_API FVehicleMeshAnchorPoints
{
GENERATED_BODY();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector DoorFR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector DoorFL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector DoorRR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector DoorRL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector WheelFR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector WheelFL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector WheelRR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector WheelRL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector Hood;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVector Trunk;
};
USTRUCT(BlueprintType)
struct CARLATOOLS_API FVehicleMeshParts
{
GENERATED_BODY();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> DoorFR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> DoorFL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> DoorRR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> DoorRL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> Trunk;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> Hood;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> WheelFR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> WheelFL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> WheelRR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> WheelRL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
TArray<UPrimitiveComponent*> Body;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVehicleMeshAnchorPoints Anchors;
};
USTRUCT(BlueprintType)
struct CARLATOOLS_API FMergedVehicleMeshParts
{
GENERATED_BODY();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* DoorFR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* DoorFL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* DoorRR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* DoorRL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* Trunk;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* Hood;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* WheelFR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* WheelFL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* WheelRR;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* WheelRL;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
UStaticMesh* Body;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category="USD Importer")
FVehicleMeshAnchorPoints Anchors;
};
UCLASS() UCLASS()
class CARLATOOLS_API UUSDImporterWidget : public UUserWidget class CARLATOOLS_API UUSDImporterWidget : public UUserWidget
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
UFUNCTION(BlueprintCallable, Category="USD Importer") UFUNCTION(BlueprintCallable, Category="USD Importer")
void ImportUSDProp(const FString& USDPath, const FString& DestinationAssetPath, bool bAsBlueprint = true); void ImportUSDProp(const FString& USDPath, const FString& DestinationAssetPath, bool bAsBlueprint = true);
@ -22,4 +113,22 @@ class CARLATOOLS_API UUSDImporterWidget : public UUserWidget
static AActor* GetGeneratedBlueprint(UWorld* World, const FString& USDPath); static AActor* GetGeneratedBlueprint(UWorld* World, const FString& USDPath);
UFUNCTION(BlueprintCallable, Category="USD Importer") UFUNCTION(BlueprintCallable, Category="USD Importer")
static bool MergeStaticMeshComponents(TArray<AActor*> Actors, const FString& DestMesh); static bool MergeStaticMeshComponents(TArray<AActor*> Actors, const FString& DestMesh);
UFUNCTION(BlueprintCallable, Category="USD Importer")
static TArray<UObject*> MergeMeshComponents(TArray<UPrimitiveComponent*> Components, const FString& DestMesh);
UFUNCTION(BlueprintCallable, Category="USD Importer")
static FVehicleMeshParts SplitVehicleParts(AActor* BlueprintActor);
UFUNCTION(BlueprintCallable, Category="USD Importer")
static FMergedVehicleMeshParts GenerateVehicleMeshes(const FVehicleMeshParts& VehicleMeshParts, const FString& DestPath);
UFUNCTION(BlueprintCallable, Category="USD Importer")
static AActor* GenerateNewVehicleBlueprint(
UWorld* World,
UClass* BaseClass,
USkeletalMesh* NewSkeletalMesh,
const FString &DestPath,
const FMergedVehicleMeshParts& VehicleMeshes);
UFUNCTION(BlueprintCallable, Category="USD Importer")
static bool EditSkeletalMeshBones(
USkeletalMesh* Skeleton,
const TMap<FString, FTransform> &NewBoneTransforms);
}; };