// Copyright 2020-2024 CesiumGS, Inc. and Contributors #pragma once #include "CoreMinimal.h" #if WITH_EDITOR #include "Materials/MaterialFunctionMaterialLayer.h" #endif #include #include #if WITH_EDITOR enum ECustomMaterialOutputType : int; enum class ECesiumEncodedMetadataType : uint8; enum class ECesiumEncodedMetadataComponentType : uint8; class UMaterialExpressionParameter; #endif namespace GenerateMaterialUtility { #if WITH_EDITOR template static FORCEINLINE ObjClass* LoadObjFromPath(const FName& Path) { if (Path == NAME_None) return nullptr; return Cast( StaticLoadObject(ObjClass::StaticClass(), nullptr, *Path.ToString())); } /** * @brief The message used for the description of autogenerated nodes. */ static const FString AutogeneratedMessage = "AUTOGENERATED DO NOT EDIT"; /** * @brief An increment constant that is used to space out the autogenerated * nodes. */ static const int32 Incr = 200; /** * @brief Classification of nodes into categories, such that they can be handled * separately. */ struct MaterialNodeClassification { /** Nodes that were procedurally created with the AutogeneratedMessage. */ TArray AutoGeneratedNodes; /** Nodes without the AutogeneratedMessage (presumably added by the user). */ TArray UserAddedNodes; }; /** * @brief A container that bundles various components used to procedurally * create or modify a material. */ struct MaterialGenerationState { /** * Nodes that are procedurally created and to be marked with * AutogeneratedMessage. */ TArray AutoGeneratedNodes; /** * Nodes that should only exist once in the material layer, e.g., * SetMaterialAttributes. These will not be regenerated if already present. */ TArray OneTimeGeneratedNodes; /** * A map from autogenerated node names to the FExpressionInputs of user-added * nodes. These are the nodes to which they previously sent their outputs. */ TMap> UserConnectionOutputMap; /** * The details of an input connection from an autogenerated node. When nodes * are regenerated, this is used to reconstruct the connection. */ struct AutogeneratedInput { FString nodeName; FString outputName; }; /** * Describes a connection to a node placed by the user or to an * otherwise user-added connection between two autogenerated nodes (e.g., * property values that were linked to the "If" that handles null feature * IDs). */ typedef std::variant UserConnectionInput; /** * A map between the names of parameters on a node and their user-added * connection details. */ typedef TMap ParameterConnections; /** * A map from autogenerated node names to a collection of parameters from * which they previously took inputs. */ TMap UserConnectionInputMap; }; /** * Creates a new material layer asset with the given name. If the specified * package doesn't exist, this function creates it. */ UMaterialFunctionMaterialLayer* CreateMaterialLayer(const FString& PackageName, const FString& MaterialName); /** * Moves the generated nodes from the material state into the given material * layer. */ void MoveNodesToMaterialLayer( MaterialGenerationState& MaterialState, UMaterialFunctionMaterialLayer* pMaterialLayer); /** * Computes a scalar for spacing out material nodes. The actual computation is * rather arbitrary, but this prevents clumping when properties have extremely * long names. */ float GetNameLengthScalar(const FName& Name); float GetNameLengthScalar(const FString& Name); ECustomMaterialOutputType GetOutputTypeForEncodedType(ECesiumEncodedMetadataType Type); FString GetHlslTypeForEncodedType( ECesiumEncodedMetadataType Type, ECesiumEncodedMetadataComponentType ComponentType); FString GetSwizzleForEncodedType(ECesiumEncodedMetadataType Type); /** * @brief Generates a parameter node corresponding to the given encoded * metadata type. */ UMaterialExpressionParameter* GenerateParameterNode( UMaterialFunctionMaterialLayer* TargetMaterialLayer, const ECesiumEncodedMetadataType Type, const FString& Name, int32 NodeX, int32 NodeY); #endif } // namespace GenerateMaterialUtility