FBX Imported ready

This commit is contained in:
Daniel 2019-04-30 16:08:04 +02:00 committed by Manish
parent 7aaa2683f3
commit 57e34021c7
4 changed files with 416 additions and 8 deletions

View File

@ -0,0 +1,141 @@
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "FBXExporterPreparatorCommandlet.h"
#include "GameFramework/WorldSettings.h"
#include "UObject/MetaData.h"
//#include "CommandletPluginPrivate.h"
UFBXExporterPreparatorCommandlet::UFBXExporterPreparatorCommandlet()
{
IsClient = false;
IsEditor = false;
IsServer = false;
LogToConsole = true;
}
#if WITH_EDITORONLY_DATA
bool UFBXExporterPreparatorCommandlet::ParseParams(const FString& InParams)
{
Params = InParams;
ParseCommandLine(*Params, Tokens, Switches);
return true;
}
void UFBXExporterPreparatorCommandlet::LoadWorld(FAssetData &AssetData)
{
FString SeedMap;
FParse::Value( *Params, TEXT("SourceMap="), SeedMap);
UE_LOG(LogTemp, Display, TEXT("DANIEL: %s"), *SeedMap);
MapObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), false, GIsEditor);
MapObjectLibrary->AddToRoot();
MapObjectLibrary->LoadAssetDataFromPath(*SeedMap);
MapObjectLibrary->LoadAssetsFromAssetData();
MapObjectLibrary->GetAssetDataList(AssetDatas);
if (AssetDatas.Num() > 0)
{
AssetData = AssetDatas.Pop();
}
}
void UFBXExporterPreparatorCommandlet::AddMeshesToWorld()
{
TArray<FString> CmdLineDirEntries;
const FString CookDirPrefix = TEXT("MESHESDIR=");
for (int32 SwitchIdx = 0; SwitchIdx < Switches.Num(); SwitchIdx++)
{
const FString& Switch = Switches[SwitchIdx];
if (Switch.StartsWith(CookDirPrefix))
{
FString DirToCook = Switch.Right(Switch.Len() - 10);
// Allow support for -COOKDIR=Dir1+Dir2+Dir3 as well as -COOKDIR=Dir1 -COOKDIR=Dir2
for (int32 PlusIdx = DirToCook.Find(TEXT("+")); PlusIdx != INDEX_NONE; PlusIdx = DirToCook.Find(TEXT("+")))
{
FString DirName = DirToCook.Left(PlusIdx);
// The dir may be contained within quotes
DirName = DirName.TrimQuotes();
FPaths::NormalizeDirectoryName(DirName);
CmdLineDirEntries.Add(DirName);
DirToCook = DirToCook.Right(DirToCook.Len() - (PlusIdx + 1));
DirToCook = DirToCook.TrimQuotes();
UE_LOG(LogTemp, Display, TEXT("DANIEL: %s"), *DirName);
}
// The dir may be contained within quotes
}
}
AssetsObjectLibrary = UObjectLibrary::CreateLibrary(UStaticMesh::StaticClass(), false, GIsEditor);
AssetsObjectLibrary->AddToRoot();
AssetsObjectLibrary->LoadAssetDataFromPaths(CmdLineDirEntries);
AssetsObjectLibrary->LoadAssetsFromAssetData();
const FTransform zeroTransform = FTransform();
FVector initialVector = FVector(0, 0, 0);
FRotator initialRotator = FRotator(0, 180, 0);
FActorSpawnParameters SpawnInfo;
MapContents.Empty();
AssetsObjectLibrary->GetAssetDataList(MapContents);
UStaticMesh *MeshAsset;
AStaticMeshActor *MeshActor;
for (auto MapAsset : MapContents)
{
MeshAsset = CastChecked<UStaticMesh>(MapAsset.GetAsset());
MeshActor = World->SpawnActor<AStaticMeshActor>(AStaticMeshActor::StaticClass(),
initialVector,
initialRotator);
MeshActor->GetStaticMeshComponent()->SetStaticMesh(CastChecked<UStaticMesh>(MeshAsset));
}
World->MarkPackageDirty();
}
bool UFBXExporterPreparatorCommandlet::SaveWorld(FAssetData &AssetData)
{
FString DestPath;
FParse::Value( *Params, TEXT("DestMapPath="), DestPath);
FString WorldName;
FParse::Value( *Params, TEXT("DestMapName="), WorldName);
FString PackageName = DestPath + "/" + WorldName;
UPackage *Package = AssetData.GetPackage();
Package->SetFolderName(*DestPath);
Package->FullyLoad();
Package->MarkPackageDirty();
FAssetRegistryModule::AssetCreated(World);
// Renaming stuff for the map
World->Rename(*WorldName, World->GetOuter());
FAssetRegistryModule::AssetRenamed(World, *PackageName);
World->MarkPackageDirty();
World->GetOuter()->MarkPackageDirty();
// Saving the package
FString PackageFileName = FPackageName::LongPackageNameToFilename(PackageName,
FPackageName::GetMapPackageExtension());
return UPackage::SavePackage(Package, World, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone,
*PackageFileName, GError, nullptr, true, true, SAVE_NoError);
}
int32 UFBXExporterPreparatorCommandlet::Main(const FString &ParamsIn)
{
ParseParams(ParamsIn);
FAssetData AssetData;
LoadWorld(AssetData);
World = CastChecked<UWorld>(AssetData.GetAsset());
AddMeshesToWorld();
SaveWorld(AssetData);
return 0;
}
#endif

View File

@ -0,0 +1,107 @@
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Commandlets/Commandlet.h"
#include <Engine/World.h>
#include <UObject/Package.h>
#include <Misc/PackageName.h>
#include "CoreMinimal.h"
#include <Runtime/Engine/Classes/Engine/ObjectLibrary.h>
#include <OpenDriveActor.h>
#if WITH_EDITORONLY_DATA
#include <Developer/AssetTools/Public/IAssetTools.h>
#include <Developer/AssetTools/Public/AssetToolsModule.h>
#include <AssetRegistry/Public/AssetRegistryModule.h>
#endif //WITH_EDITORONLY_DATA
#include <Runtime/Engine/Classes/Engine/StaticMeshActor.h>
#include "FBXExporterPreparatorCommandlet.generated.h"
UCLASS()
class UFBXExporterPreparatorCommandlet
: public UCommandlet
{
GENERATED_BODY()
public:
/** Default constructor. */
UFBXExporterPreparatorCommandlet();
#if WITH_EDITORONLY_DATA
/**
* Parses the command line parameters
* @param InParams - The parameters to parse
*/
bool ParseParams(const FString& InParams);
/**
* Move meshes from one folder to another. It only works with StaticMeshes
* @param SrcPath - Source folder from which the StaticMeshes will be obtained
* @param DestPath - Posible folder in which the Meshes will be ordered following
* the semantic segmentation. It follows ROAD_INDEX, MARKINGLINE_INDEX, TERRAIN_INDEX
* for the position in which each path will be stored.
*/
void MoveMeshes(const FString &SrcPath, const TArray<FString> &DestPath);
/**
* Loads a UWorld object from a given path into a asset data structure.
* @param SrcPath - Folder in which the world is located.
* @param AssetData - Structure in which the loaded UWorld will be saved.
*/
void LoadWorld(FAssetData& AssetData);
/**
* Add StaticMeshes from a folder into the World loaded as UPROPERTY.
* @param SrcPath - Array containing the folders from which the Assets will be loaded
* @param bMaterialWorkaround - Flag that will trigger a change in the materials to fix a known bug
* in RoadRunner.
*/
void AddMeshesToWorld();
/**
* Save a given Asset containing a World into a given path with a given name.
* @param AssetData - Contains all the info about the World to be saved
* @param DestPath - Path in which the asset will be saved.
* @param WorldName - Name for the saved world.
*/
bool SaveWorld(FAssetData& AssetData);
public:
/**
* Main method and entry of the commandlet
* @param Params - Parameters of the commandlet.
*/
virtual int32 Main(const FString &Params) override;
#endif //WITH_EDITORONLY_DATA
private:
UPROPERTY()
bool bOverrideMaterials;
//UProperties are necesary or else the GC will eat everything up
UPROPERTY()
FString MapName;
UPROPERTY()
UObjectLibrary* MapObjectLibrary;
UPROPERTY()
TArray<FAssetData> AssetDatas;
UPROPERTY()
UWorld* World;
UPROPERTY()
UObjectLibrary* AssetsObjectLibrary;
UPROPERTY()
TArray<FAssetData> MapContents;
/** All commandline tokens */
TArray<FString> Tokens;
/** All commandline switches */
TArray<FString> Switches;
/** All commandline params */
FString Params;
};

125
Util/BuildTools/ExportFBX.sh Executable file
View File

@ -0,0 +1,125 @@
#! /bin/bash
# ==============================================================================
# -- Set up environment --------------------------------------------------------
# ==============================================================================
source $(dirname "$0")/Environment.sh
if [ ! -d "${UE4_ROOT}" ]; then
fatal_error "UE4_ROOT is not defined, or points to a non-existant directory, please set this environment variable."
else
log "Using Unreal Engine at '$UE4_ROOT'"
fi
# ==============================================================================
# -- Parse arguments -----------------------------------------------------------
# ==============================================================================
DOC_STRING="Build and packs CarlaUE4's ExportedMaps"
USAGE_STRING="Usage: $0 [--help] [-d|--dir] <outdir> [-f|--file] <filename> [-p|--maps] <maps_to_cook>"
OUTPUT_DIRECTORY=""
FILE_NAME=""
PATHS_TO_COOK=""
OPTS=`getopt -o h --long help,dir:,file:,maps: -n 'parse-options' -- "$@"`
if [ $? != 0 ] ; then echo "$USAGE_STRING" ; exit 2; fi
eval set -- "$OPTS"
while true; do
case "$1" in
--dir )
OUTPUT_DIRECTORY="$2"
shift 2;;
--file )
FILE_NAME="$2"
shift 2;;
--maps )
MAP_TO_COOK="$2"
shift 2;;
--help )
echo "$DOC_STRING"
echo "$USAGE_STRING"
exit 1
;;
* )
break ;;
esac
done
if [ -z "${OUTPUT_DIRECTORY}" ]; then
OUTPUT_DIRECTORY="${PWD}/ExportedMaps"
fi
if [ -z "${FILE_NAME}" ]; then
FILE_NAME="CookedExportedMaps"
fi
# ==============================================================================
# -- Package project -----------------------------------------------------------
# ==============================================================================
REPOSITORY_TAG=$(get_git_repository_version)
BUILD_FOLDER=${OUTPUT_DIRECTORY}
log "Packaging user content from version '$REPOSITORY_TAG'."
#rm -Rf ${BUILD_FOLDER}
mkdir -p ${BUILD_FOLDER}
pushd "${CARLAUE4_ROOT_FOLDER}" > /dev/null
log "Current project directory: '${PWD}'"
${UE4_ROOT}/Engine/Binaries/Linux/UE4Editor "${PWD}/CarlaUE4.uproject" -run=cook -cooksinglepackage -Map=${MAP_TO_COOK} -targetplatform="LinuxNoEditor" -OutputDir="${BUILD_FOLDER}/Cooked"
popd >/dev/null
# ==============================================================================
# -- Zip the project -----------------------------------------------------------
# ==============================================================================
DESTINATION=${BUILD_FOLDER}/${FILE_NAME}.tar.gz
SOURCE=${BUILD_FOLDER}/Cooked
pushd "${SOURCE}" >/dev/null
log "Packaging build."
#rm -Rf ./Engine
rm -Rf ./CarlaUE4/Metadata
rm -Rf ./CarlaUE4/Plugins
#@TODO: Instead of this hardcoded path, we need to pick the ${MAPS_TO_COOK} path
#rm -Rf ./CarlaUE4/${MAPS_TO_COOK_But_instead_of_"game"_the_folder_is_content}.uexp
#rm -Rf ./CarlaUE4/${MAPS_TO_COOK_But_instead_of_"game"_the_folder_is_content}.umap
#rm -Rf ./CarlaUE4/Content/Carla/Maps/BaseMap/TEMPMAP.uexp
#rm -Rf ./CarlaUE4/Content/Carla/Maps/BaseMap/TEMPMAP.umap
rm ./CarlaUE4/AssetRegistry.bin
tar -czvf ${DESTINATION} *
popd > /dev/null
# ==============================================================================
# -- Remove intermediate files and return everything to normal------------------
# ==============================================================================
log "Removing intermediate build."
rm -Rf ${BUILD_FOLDER}/Cooked
# ==============================================================================
# -- ...and we are done --------------------------------------------------------
# ==============================================================================
log "ExportedMaps created at ${DESTINATION}"
log "Success!"

View File

@ -13,6 +13,7 @@ import json
import subprocess
import shutil
import argparse
import re
if os.name == 'nt':
@ -24,20 +25,38 @@ elif os.name == 'posix':
def main():
try:
args = parse_arguments()
import_all_fbx_in_folder(args.folder)
folder_list = []
import_all_fbx_in_folder(args.folder, folder_list)
finally:
print('\ndone.')
def import_all_fbx_in_folder(fbx_folder):
def import_all_fbx_in_folder(fbx_folder, folder_list):
dirname = os.getcwd()
fbx_place = os.path.join(dirname, "..", fbx_folder)
for file in os.listdir(fbx_place):
if file.endswith(".PropRegistry.json"):
with open(os.path.join(dirname, "..", fbx_folder, file)) as json_file:
data = json.load(json_file)
import_assets_commandlet(data, fbx_folder)
# This will take all the fbx registerd in the provided json files
# and place it inside unreal in the provided path (by the json file)
import_assets_commandlet(data, fbx_folder, folder_list)
# This part will just gather all the folders in which an fbx has been placed
if(len(folder_list)>0):
final_list = ""
for folder in folder_list:
if folder not in final_list:
final_list += folder + "+"
final_list = final_list[:-1]
print(final_list)
#Destination map (the one that will be cooked)
dest_map_path = "/Game/Carla/Maps/BaseMap"
dest_map_name = "TEMPMAP"
# This should be a folder, because the commandlet will take anything inside.
# It is better if there is only one map inside
src_map_folder = "/Game/Carla/Maps/EmptyMap"
prepare_cook_commandlet(final_list, src_map_folder, dest_map_path, dest_map_name)
launch_bash_script("BuildTools/ExportFBX.sh", "--maps=%s/%s" % (dest_map_path, dest_map_name))
def parse_arguments():
argparser = argparse.ArgumentParser(
@ -50,12 +69,17 @@ def parse_arguments():
help='FBX containing folder')
return argparser.parse_args()
def prepare_cook_commandlet(folder_list, source_map, dest_map_path, dest_map_name):
commandlet_name = "FBXExporterPreparator"
commandlet_arguments = "-MeshesDir=%s -SourceMap=%s -DestMapPath=%s -DestMapName=%s" % (folder_list, source_map, dest_map_path, dest_map_name)
invoke_commandlet(commandlet_name, commandlet_arguments)
def import_assets_commandlet(json_data, fbx_folder):
def import_assets_commandlet(json_data, fbx_folder, folder_list):
importfile = "importsetting.json"
if os.path.exists(importfile):
os.remove(importfile)
generate_json(json_data, fbx_folder, importfile)
populate_json_and_data(json_data, fbx_folder, importfile, folder_list)
dirname = os.getcwd()
commandlet_name = "ImportAssets"
import_settings = os.path.join(dirname, importfile)
@ -73,8 +97,13 @@ def invoke_commandlet(name, arguments):
full_command = "%s %s -run=%s %s" % (editor_path, uproject_path, name, arguments)
subprocess.check_call([full_command], shell=True)
def launch_bash_script(script_path, arguments):
dirname = os.getcwd()
full_command = "%s %s" % (os.path.join(dirname, script_path), arguments)
print("Executing: " + full_command)
subprocess.check_call([full_command], shell=True)
def generate_json(json_data, fbx_folder, json_file):
def populate_json_and_data(json_data, fbx_folder, json_file, folder_list):
with open(json_file, "w+") as fh:
import_groups = []
file_names = []
@ -104,12 +133,18 @@ def generate_json(json_data, fbx_folder, json_file):
import_groups.append({
"ImportSettings": import_settings,
"FactoryName": "FbxFactory",
"DestinationPath": os.path.dirname(prop["path"]),
"DestinationPath": prop["path"],
"bReplaceExisting": "true",
"FileNames": file_names
})
#second_folder = os.path.dirname(prop["path"]).split("/Game")[1].split("/")[1]
#folder_list.append("/Game/" + second_folder)
folder_list.append(prop["path"])
fh.write(json.dumps({"ImportGroups": import_groups}))
fh.close()
#result = re.search('/Game(.*)', os.path.dirname(prop["path"]))
#print(result)
if __name__ == '__main__':