// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "SceneImportFactory.h" #include "FbxSceneImportFactory.generated.h" class AActor; class UFbxSceneImportData; class USceneComponent; #define INVALID_UNIQUE_ID 0xFFFFFFFFFFFFFFFF class FFbxAttributeInfo: public TSharedFromThis { public: FString Name; uint64 UniqueId; bool bImportAttribute; // Log the path where it was import so we can retrieve it when doing the re-import FString OriginalImportPath; FString OriginalFullImportName; bool bOriginalTypeChanged; bool bOverridePath; FString OverrideImportPath; FString OverrideFullImportName; // The name of the Options so reimport can show the options FString OptionName; // The node pivot user want to bake by default its the first node that reference the mesh uint64 PivotNodeUid; FString PivotNodeName; // Transient variable use for the ui to not display a uid // If there is more then one Pivots we have to present a list to the user so he can choose which node pivot he want to bake TMap> NodeReferencePivots; FString GetImportPath() { if (bOverridePath) { return OverrideImportPath; } return OriginalImportPath; } FString GetFullImportName() { if (bOverridePath) { return OverrideFullImportName; } return OriginalFullImportName; } void SetOriginalImportPath(FString ImportPath) { OriginalImportPath = ImportPath; IsContentObjectUpToDate = false; } void SetOriginalFullImportName(FString FullImportName) { OriginalFullImportName = FullImportName; IsContentObjectUpToDate = false; } void SetOverridePath(bool OverridePath) { bOverridePath = OverridePath; IsContentObjectUpToDate = false; } FFbxAttributeInfo() : Name(TEXT("")), UniqueId(INVALID_UNIQUE_ID), bImportAttribute(true), OriginalImportPath(TEXT("")), OriginalFullImportName(TEXT("")), bOriginalTypeChanged(false), bOverridePath(false), OverrideImportPath(TEXT("")), OverrideFullImportName(TEXT("")), OptionName(TEXT("")), PivotNodeUid(INVALID_UNIQUE_ID), PivotNodeName(TEXT("-")), IsContentObjectUpToDate(false), ContentPackage(nullptr), ContentObject(nullptr) {} virtual ~FFbxAttributeInfo() {} virtual UClass* GetType() = 0; UPackage* GetContentPackage(); UObject* GetContentObject(); private: // Cache the existing object state bool IsContentObjectUpToDate; UPackage* ContentPackage; UObject* ContentObject; }; class FFbxMeshInfo: public FFbxAttributeInfo , public TSharedFromThis { public: int32 FaceNum; int32 VertexNum; bool bTriangulated; int32 MaterialNum; bool bIsSkelMesh; FString SkeletonRoot; int32 SkeletonElemNum; FString LODGroup; int32 LODLevel; int32 MorphNum; bool IsLod; bool IsCollision; FFbxMeshInfo() : FaceNum(0), VertexNum(0), bTriangulated(false), MaterialNum(0), bIsSkelMesh(false), SkeletonRoot(TEXT("")), SkeletonElemNum(0), LODGroup(TEXT("")), LODLevel(0), MorphNum(0), IsLod(false), IsCollision(false) {} virtual ~FFbxMeshInfo() {} virtual UClass* GetType(); }; class FFbxTextureInfo: public FFbxAttributeInfo , public TSharedFromThis { public: FString TexturePath; FFbxTextureInfo() : TexturePath(TEXT("")) {} virtual UClass* GetType(); }; class FFbxMaterialInfo: public FFbxAttributeInfo , public TSharedFromThis { public: // This string is use to help match the material when doing a reimport FString HierarchyPath; // All the textures use by this material TArray> Textures; FFbxMaterialInfo() : HierarchyPath(TEXT("")) {} virtual UClass* GetType(); }; class FFbxCameraInfo: public TSharedFromThis { public: FString Name; uint64 UniqueId; bool ProjectionPerspective; float AspectWidth; float AspectHeight; float NearPlane; float FarPlane; float OrthoZoom; float FieldOfView; float FocalLength; float ApertureWidth; float ApertureHeight; FFbxCameraInfo() : Name(TEXT("")), UniqueId(INVALID_UNIQUE_ID), ProjectionPerspective(true), AspectWidth(0.0f), AspectHeight(0.0f), NearPlane(0.0f), FarPlane(0.0f), OrthoZoom(0.0f), FieldOfView(0.0f), FocalLength(0.0f), ApertureWidth(0.0f), ApertureHeight(0.0f) {} }; class FFbxLightInfo: public TSharedFromThis { public: FString Name; uint64 UniqueId; int32 Type; // ePoint=0, eDirectional=1, eSpot=2, eArea=3, eVolume=4 FColor Color; // RGB color no alpha float Intensity; // fbx default is 100 int32 Decay; // eNone=0, eLinear=1, eQuadratic=2, eCubic=3 bool CastLight; bool CastShadow; FColor ShadowColor; // RGB color no alpha float InnerAngle; float OuterAngle; float Fog; float DecayStart; bool EnableNearAttenuation; float NearAttenuationStart; float NearAttenuationEnd; bool EnableFarAttenuation; float FarAttenuationStart; float FarAttenuationEnd; // Notes: // Fbx use positive X to point light direction, we have to turn the component 90 degree in z object space FFbxLightInfo() : Name(TEXT("")), UniqueId(INVALID_UNIQUE_ID), Type(0), Color(FColor::White), Intensity(1.0f), Decay(0), CastLight(false), CastShadow(false), ShadowColor(FColor::Black), InnerAngle(0.0f), OuterAngle(0.0f), Fog(0.0f), DecayStart(0.0f), EnableNearAttenuation(false), NearAttenuationStart(0.0f), NearAttenuationEnd(0.0f), EnableFarAttenuation(false), FarAttenuationStart(0.0f), FarAttenuationEnd(0.0f) {} }; // Node use to store the scene hierarchy transform will be relative to the parent class FFbxNodeInfo: public TSharedFromThis { public: FString NodeName; uint64 UniqueId; FString NodeHierarchyPath; TSharedPtr ParentNodeInfo; TSharedPtr AttributeInfo; uint64 AttributeUniqueId; FString AttributeType; FTransform Transform; FVector PivotRotation; FVector PivotScaling; bool bImportNode; TArray> Childrens; TArray> Materials; FFbxNodeInfo() : NodeName(TEXT("")), UniqueId(INVALID_UNIQUE_ID), NodeHierarchyPath(TEXT("")), ParentNodeInfo(NULL), AttributeInfo(NULL), AttributeUniqueId(INVALID_UNIQUE_ID), AttributeType(TEXT("")), Transform(FTransform::Identity), bImportNode(true) {} }; class FFbxSceneInfo: public TSharedFromThis { public: // data for static mesh int32 NonSkinnedMeshNum; // data for skeletal mesh int32 SkinnedMeshNum; // common data int32 TotalGeometryNum; int32 TotalMaterialNum; int32 TotalTextureNum; TArray> MeshInfo; TArray> HierarchyInfo; // Component attributes TMap> LightInfo; TMap> CameraInfo; /* true if it has animation */ bool bHasAnimation; double FrameRate; double TotalTime; FFbxSceneInfo() : NonSkinnedMeshNum(0), SkinnedMeshNum(0), TotalGeometryNum(0), TotalMaterialNum(0), TotalTextureNum(0), bHasAnimation(false), FrameRate(0.0), TotalTime(0.0) {} // Function helper to find the LOD parent of a nodeinfo with a mesh attribute static TSharedPtr RecursiveFindLODParentNode(TSharedPtr NodeInfo) { if (!NodeInfo.IsValid()) return nullptr; if (NodeInfo->ParentNodeInfo.IsValid() && NodeInfo->ParentNodeInfo->AttributeType.Compare(TEXT("eLODGroup")) == 0) return NodeInfo->ParentNodeInfo; return RecursiveFindLODParentNode(NodeInfo->ParentNodeInfo); } }; namespace UnFbx { struct FBXImportOptions; } typedef TMap ImportOptionsNameMap; typedef ImportOptionsNameMap* ImportOptionsNameMapPtr; UCLASS(BlueprintType, hidecategories = Object) class UNREALED_API UFbxSceneImportFactory: public USceneImportFactory { GENERATED_UCLASS_BODY() /** UFactory Interface */ virtual UObject* FactoryCreateFile(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, const FString& Filename, const TCHAR* Parms, FFeedbackContext* Warn, bool& bOutOperationCanceled) override; virtual UObject* FactoryCreateBinary(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn) override; virtual UObject* FactoryCreateBinary(UClass* InClass, UObject* InParent, FName InName, EObjectFlags Flags, UObject* Context, const TCHAR* Type, const uint8*& Buffer, const uint8* BufferEnd, FFeedbackContext* Warn, bool& bOutOperationCanceled) override; virtual bool FactoryCanImport(const FString& Filename) override; /** USceneImportFactory Interface */ virtual bool ImportsAssets() const override { return true; } /** Import options UI detail when importing fbx scene */ UPROPERTY(BlueprintReadWrite, Category = "Editor Scripting | Fbx Scene Import", Transient) class UFbxSceneImportOptions* SceneImportOptions; /** Import options UI detail when importing fbx scene static mesh*/ UPROPERTY(BlueprintReadWrite, Category = "Editor Scripting | Fbx Scene Import", Transient) class UFbxSceneImportOptionsStaticMesh* SceneImportOptionsStaticMesh; /** Import options UI detail when importing fbx scene skeletal mesh*/ UPROPERTY(BlueprintReadWrite, Category = "Editor Scripting | Fbx Scene Import", Transient) class UFbxSceneImportOptionsSkeletalMesh* SceneImportOptionsSkeletalMesh; /** Import data used when importing static meshes */ UPROPERTY(Transient) class UFbxStaticMeshImportData* StaticMeshImportData; /** Import data used when importing skeletal meshes */ UPROPERTY(Transient) class UFbxSkeletalMeshImportData* SkeletalMeshImportData; /** Import data used when importing animations */ UPROPERTY(Transient) class UFbxAnimSequenceImportData* AnimSequenceImportData; /** Import data used when importing textures */ UPROPERTY(Transient) class UFbxTextureImportData* TextureImportData; /* Default Options always have the same name "Default" */ static FString DefaultOptionName; public: static TSharedPtr ConvertSceneInfo(void* VoidFbxImporter, void* VoidFbxSceneInfo); static void ExtractMaterialInfo(void* FbxImporterVoid, TSharedPtr SceneInfoPtr); protected: /** Convert the scene and remake all the transform for the SceneInfo pass in parameter. * We need this because EvaluateGlobal and EvaluateLocal are dependent of the scene conversion. */ void ChangeFrontAxis(void* VoidFbxImporter, void* VoidSceneInfo, TSharedPtr SceneInfoPtr); /** Make sure GlobalImportSettings is pointing to the correct options */ void ApplyMeshInfoFbxOptions(TSharedPtr MeshInfo); /* Compute the path of every node and fill the result in the node. This data will be use by the reimport * as a unique key for for the reimport status of the node hierarchy. */ static void FillSceneHierarchyPath(TSharedPtr SceneInfo); /** Create a hierarchy of actor in the current level */ void CreateLevelActorHierarchy(TSharedPtr SceneInfoPtr); /** Create a hierarchy of actor in the current level */ AActor* CreateActorComponentsHierarchy(TSharedPtr SceneInfoPtr); /** Apply the LocalTransform to the SceneComponent and if PreMultiplyTransform is not null do a pre multiplication * SceneComponent: Must be a valid pointer * LocalTransform: Must be a valid pointer * PreMultiplyTransform: Can be nullptr */ void ApplyTransformToComponent(USceneComponent* SceneComponent, FTransform* LocalTransform, FTransform* PreMultiplyTransform, FVector& PivotLocation, FVector& ParentPivotAccumulation); /** Import all skeletal mesh from the fbx scene */ void ImportAllSkeletalMesh(void* VoidRootNodeToImport, void* VoidFbxImporter, EObjectFlags Flags, int32& NodeIndex, int32& InterestingNodeCount, TSharedPtr SceneInfo); UObject* ImportOneSkeletalMesh(void* VoidRootNodeToImport, void* VoidFbxImporter, TSharedPtr SceneInfo, EObjectFlags Flags, TArray& VoidNodeArray, int32& TotalNumNodes); /** Import all static mesh from the fbx scene */ void ImportAllStaticMesh(void* VoidRootNodeToImport, void* VoidFbxImporter, EObjectFlags Flags, int32& NodeIndex, int32& InterestingNodeCount, TSharedPtr SceneInfo); // @todo document UObject* RecursiveImportNode(void* FFbxImporter, void* VoidNode, EObjectFlags Flags, int32& Index, int32 Total, TSharedPtr SceneInfo, FString PackagePath); // @todo document UObject* ImportANode(void* VoidFbxImporter, TArray& VoidNode, EObjectFlags Flags, int32& NodeIndex, TSharedPtr SceneInfo, TSharedPtr& OutNodeInfo, FString PackagePath, int32 Total = 0, UObject* InMesh = NULL, int LODIndex = 0); /** Find the FFbxNodeInfo in the hierarchy. */ bool FindSceneNodeInfo(TSharedPtr SceneInfo, uint64 NodeInfoUniqueId, TSharedPtr& OutNodeInfo); /** Create a package for the specified node. Package will be the concatenation of UFbxSceneImportFactory::Path and Node->GetName(). */ UPackage* CreatePackageForNode(FString PackageName, FString& StaticMeshName); bool SetStaticMeshComponentOverrideMaterial(class UStaticMeshComponent* StaticMeshComponent, TSharedPtr NodeInfo); /** The path of the asset to import */ FString Path; /** Pointer on the fbx scene import data, we fill this object to be able to do re import of the scene */ UPROPERTY() UFbxSceneImportData* ReimportData; /** Assets created by the factory*/ TMap, UObject*> AllNewAssets; /*Global Setting for non overriden Node*/ UnFbx::FBXImportOptions* GlobalImportSettings; /*The Global Settings Reference*/ UnFbx::FBXImportOptions* GlobalImportSettingsReference; /*The options dictionary*/ ImportOptionsNameMap NameOptionsMap; /* Return the Options from the NameOptionMap Map. return nulptr if the options are not found*/ UnFbx::FBXImportOptions* GetOptionsFromName(FString OptionName); /** Is the import was cancel*/ bool ImportWasCancel; };