// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #pragma once #if COMPILE_WITH_MATERIAL_GRAPH #include "Engine/Graphics/Materials/MaterialInfo.h" #include "Engine/Graphics/Materials/MaterialParams.h" #include "MaterialLayer.h" #include "Types.h" /// /// Material node input boxes (each enum item value maps to box ID). /// enum class MaterialGraphBoxes { /// /// The layer input. /// Layer = 0, /// /// The color input. /// Color = 1, /// /// The mask input. /// Mask = 2, /// /// The emissive input. /// Emissive = 3, /// /// The metalness input. /// Metalness = 4, /// /// The specular input. /// Specular = 5, /// /// The roughness input. /// Roughness = 6, /// /// The ambient occlusion input. /// AmbientOcclusion = 7, /// /// The normal input. /// Normal = 8, /// /// The opacity input. /// Opacity = 9, /// /// The refraction input. /// Refraction = 10, /// /// The position offset input. /// PositionOffset = 11, /// /// The tessellation multiplier input. /// TessellationMultiplier = 12, /// /// The world displacement input. /// WorldDisplacement = 13, /// /// The subsurface color input. /// SubsurfaceColor = 14, /// /// The amount of input boxes. /// MAX }; /// /// Material shaders generator from graphs. /// class MaterialGenerator : public ShaderGenerator { public: struct MaterialGraphBoxesMapping { byte ID; const Char* SubName; MaterialTreeType TreeType; MaterialValue DefaultValue; }; private: Array _layers; Array> _vsToPsInterpolants; MaterialTreeType _treeType; MaterialLayer* _treeLayer = nullptr; String _treeLayerVarName; MaterialValue _ddx, _ddy, _cameraVector; public: MaterialGenerator(); ~MaterialGenerator(); public: /// /// Gets material root layer /// /// Base layer MaterialLayer* GetRootLayer() const; /// /// Add new layer to the generator data (will be deleted after usage) /// /// Layer to add void AddLayer(MaterialLayer* layer); /// /// Gets layer that has given ID, if not loaded tries to load it /// /// Layer ID /// Calling node /// Material layer or null if cannot do that MaterialLayer* GetLayer(const Guid& id, Node* caller); /// /// Generate material source code (first layer should be the base one) /// /// Output source code /// Material info structure (will contain output data) /// Output material parameters data /// True if cannot generate code, otherwise false bool Generate(WriteStream& source, MaterialInfo& materialInfo, BytesContainer& parametersData); private: void clearCache(); void createGradients(Node* caller); Value getCameraVector(Node* caller); void eatMaterialGraphBox(String& layerVarName, MaterialGraphBox* nodeBox, MaterialGraphBoxes box); void eatMaterialGraphBox(MaterialLayer* layer, MaterialGraphBoxes box); void eatMaterialGraphBoxWithDefault(MaterialLayer* layer, MaterialGraphBoxes box); void ProcessGroupLayers(Box* box, Node* node, Value& value); void ProcessGroupMaterial(Box* box, Node* node, Value& value); void ProcessGroupMath(Box* box, Node* node, Value& value); void ProcessGroupParameters(Box* box, Node* node, Value& value); void ProcessGroupTextures(Box* box, Node* node, Value& value); void ProcessGroupTools(Box* box, Node* node, Value& value); void ProcessGroupParticles(Box* box, Node* node, Value& value); void ProcessGroupFunction(Box* box, Node* node, Value& value); void writeBlending(MaterialGraphBoxes box, Value& result, const Value& bottom, const Value& top, const Value& alpha); using ShaderGenerator::findParam; SerializedMaterialParam* findParam(const Guid& id, MaterialLayer* layer); MaterialGraphParameter* findGraphParam(const Guid& id); MaterialValue* sampleTextureRaw(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture); void sampleTexture(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture); void sampleSceneDepth(Node* caller, Value& value, Box* box); void linearizeSceneDepth(Node* caller, const Value& depth, Value& value); // This must match ParticleAttribute::ValueTypes enum in Particles Module enum class ParticleAttributeValueTypes { Float, Float2, Float3, Float4, Int, Uint, }; enum class ParticleAttributeSpace { AsIs, LocalPosition, LocalDirection, }; MaterialValue AccessParticleAttribute(Node* caller, const StringView& name, ParticleAttributeValueTypes valueType, const Char* index = nullptr, ParticleAttributeSpace space = ParticleAttributeSpace::AsIs); void prepareLayer(MaterialLayer* layer, bool allowVisibleParams); void WriteCustomGlobalCode(const Array>& nodes, int32 templateInputsMapping); Value VsToPs(Node* node, Box* input); public: static MaterialValue getUVs; static MaterialValue getTime; static MaterialValue getNormal; static MaterialValue getNormalZero; static MaterialValue getVertexColor; static MaterialGraphBoxesMapping MaterialGraphBoxesMappings[]; static const MaterialGraphBoxesMapping& GetMaterialRootNodeBox(MaterialGraphBoxes box); }; #endif