// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #if COMPILE_WITH_MODEL_TOOL #include "Engine/Core/Config.h" #include "Engine/Serialization/ISerializable.h" #include "Engine/Graphics/Models/ModelData.h" #include "Engine/Graphics/Models/SkeletonData.h" #include "Engine/Animations/AnimationData.h" class JsonWriter; /// /// The model file import data types (used as flags). /// enum class ImportDataTypes : int32 { /// /// Imports materials and meshes. /// Geometry = 1 << 0, /// /// Imports the skeleton bones hierarchy. /// Skeleton = 1 << 1, /// /// Imports the animations. /// Animations = 1 << 2, /// /// Imports the scene nodes hierarchy. /// Nodes = 1 << 3, /// /// Imports the materials. /// Materials = 1 << 4, /// /// Imports the textures. /// Textures = 1 << 5, }; DECLARE_ENUM_OPERATORS(ImportDataTypes); /// /// Imported model data container. Represents unified model source file data (meshes, animations, skeleton, materials). /// class ImportedModelData { public: struct LOD { Array Meshes; BoundingBox GetBox() const; }; struct Node { /// /// The parent node index. The root node uses value -1. /// int32 ParentIndex; /// /// The local transformation of the node, relative to the parent node. /// Transform LocalTransform; /// /// The name of this node. /// String Name; }; public: /// /// The import data types types. /// ImportDataTypes Types; /// /// The textures slots. /// Array Textures; /// /// The material slots. /// Array Materials; /// /// The level of details data. /// Array LODs; /// /// The skeleton data. /// SkeletonData Skeleton; /// /// The scene nodes. /// Array Nodes; /// /// The node animations. /// AnimationData Animation; public: /// /// Initializes a new instance of the class. /// /// The types. ImportedModelData(ImportDataTypes types) { Types = types; } /// /// Finalizes an instance of the class. /// ~ImportedModelData() { // Ensure to cleanup data for (int32 i = 0; i < LODs.Count(); i++) LODs[i].Meshes.ClearDelete(); } }; /// /// Import models and animations helper. /// class FLAXENGINE_API ModelTool { public: /// /// Declares the imported data type. /// DECLARE_ENUM_EX_3(ModelType, int32, 0, Model, SkinnedModel, Animation); /// /// Declares the imported animation clip duration. /// DECLARE_ENUM_EX_2(AnimationDuration, int32, 0, Imported, Custom); /// /// Importing model options /// struct Options : public ISerializable { ModelType Type = ModelType::Model; // Geometry bool CalculateNormals = false; float SmoothingNormalsAngle = 175.0f; bool FlipNormals = false; float SmoothingTangentsAngle = 45.0f; bool CalculateTangents = true; bool OptimizeMeshes = true; bool MergeMeshes = true; bool ImportLODs = true; bool ImportVertexColors = true; bool ImportBlendShapes = false; ModelLightmapUVsSource LightmapUVsSource = ModelLightmapUVsSource::Disable; // Transform float Scale = 1.0f; Quaternion Rotation = Quaternion::Identity; Vector3 Translation = Vector3::Zero; bool CenterGeometry = false; // Animation AnimationDuration Duration = AnimationDuration::Imported; Vector2 FramesRange = Vector2::Zero; float DefaultFrameRate = 0.0f; float SamplingRate = 0.0f; bool SkipEmptyCurves = true; bool OptimizeKeyframes = true; bool EnableRootMotion = false; String RootNodeName; int32 AnimationIndex = -1; // Level Of Detail bool GenerateLODs = false; int32 BaseLOD = 0; int32 LODCount = 4; float TriangleReduction = 0.5f; // Materials bool ImportMaterials = true; bool ImportTextures = true; bool RestoreMaterialsOnReimport = true; public: // [ISerializable] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; }; public: /// /// Imports the model source file data. /// /// The file path. /// The output data. /// The import options. /// The error message container. /// True if fails, otherwise false. static bool ImportData(const String& path, ImportedModelData& data, Options options, String& errorMsg); /// /// Imports the model. /// /// The file path. /// The output data. /// The import options. /// The error message container. /// The output folder for the additional imported data - optional. Used to auto-import textures and material assets. /// True if fails, otherwise false. static bool ImportModel(const String& path, ModelData& meshData, Options options, String& errorMsg, const String& autoImportOutput = String::Empty); public: static int32 DetectLodIndex(const String& nodeName); static bool FindTexture(const String& sourcePath, const String& file, String& path); /// /// Gets the local transformations to go from rootIndex to index. /// /// The nodes containing the local transformations. /// The root index. /// The current index. /// The transformation at this index. template static Transform CombineTransformsFromNodeIndices(Array& nodes, int32 rootIndex, int32 index) { if (index == -1 || index == rootIndex) return Transform::Identity; auto result = nodes[index].LocalTransform; if (index != rootIndex) { const auto parentTransform = CombineTransformsFromNodeIndices(nodes, rootIndex, nodes[index].ParentIndex); result = parentTransform.LocalToWorld(result); } return result; } private: #if USE_ASSIMP static bool ImportDataAssimp(const char* path, ImportedModelData& data, const Options& options, String& errorMsg); #endif #if USE_AUTODESK_FBX_SDK static bool ImportDataAutodeskFbxSdk(const char* path, ImportedModelData& data, const Options& options, String& errorMsg); #endif #if USE_OPEN_FBX static bool ImportDataOpenFBX(const char* path, ImportedModelData& data, const Options& options, String& errorMsg); #endif }; #endif