diff --git a/Source/Engine/ContentImporters/CreateMaterial.cpp b/Source/Engine/ContentImporters/CreateMaterial.cpp index fb16b89ee..9d9af4b38 100644 --- a/Source/Engine/ContentImporters/CreateMaterial.cpp +++ b/Source/Engine/ContentImporters/CreateMaterial.cpp @@ -12,9 +12,13 @@ #include "Engine/Tools/MaterialGenerator/MaterialGenerator.h" #include "Engine/Serialization/MemoryWriteStream.h" +#define SET_POS(node, pos) meta.Position = pos; node->Meta.AddEntry(11, (byte*)&meta, sizeof(meta)); +#define CONNECT(boxA, boxB) boxA.Connections.Add(&boxB); boxB.Connections.Add(&boxA) + namespace { - ShaderGraphNode<>* AddFloatValue(MaterialLayer* layer, const float& value, const float& defaultValue) + template + ShaderGraphNode<>* AddValueNode(MaterialLayer* layer, const float& value, const float& defaultValue) { if (Math::NearEqual(value, defaultValue)) return nullptr; @@ -28,7 +32,8 @@ namespace return &node; } - ShaderGraphNode<>* AddColorNode(MaterialLayer* layer, const Color& value, const Color& defaultValue) + template + ShaderGraphNode<>* AddValueNode(MaterialLayer* layer, const Color& value, const Color& defaultValue) { if (value == defaultValue) return nullptr; @@ -86,6 +91,35 @@ namespace Float2 Position; bool Selected; }; + + template + void AddInput(MaterialLayer* layer, Meta11 meta, MaterialGraphBoxes box, const Guid& texture, const T& value, const T& defaultValue, const Float2& pos, ShaderGraphNode<>** outTextureNode = nullptr) + { + auto textureNode = AddTextureNode(layer, texture); + auto valueNode = AddValueNode(layer, value, defaultValue); + if (textureNode && valueNode) + { + auto diffuseMultiply = AddMultiplyNode(layer); + CONNECT(diffuseMultiply->Boxes[0], textureNode->Boxes[1]); + CONNECT(diffuseMultiply->Boxes[1], valueNode->Boxes[0]); + CONNECT(layer->Root->Boxes[static_cast(box)], diffuseMultiply->Boxes[2]); + SET_POS(valueNode, pos + Float2(-467.7404, 91.41332)); + SET_POS(textureNode, pos + Float2(-538.096, -103.9724)); + SET_POS(diffuseMultiply, pos + Float2(-293.5272f, -2.926111f)); + } + else if (textureNode) + { + CONNECT(layer->Root->Boxes[static_cast(box)], textureNode->Boxes[1]); + SET_POS(textureNode, pos + Float2(-293.5272f, -2.926111f)); + } + else if (valueNode) + { + CONNECT(layer->Root->Boxes[static_cast(box)], valueNode->Boxes[0]); + SET_POS(valueNode, pos + Float2(-293.5272f, -2.926111f)); + } + if (outTextureNode) + *outTextureNode = textureNode; + } } CreateMaterial::Options::Options() @@ -129,85 +163,32 @@ CreateAssetResult CreateMaterial::Create(CreateAssetContext& context) box.Parent = layer->Root; Meta11 meta; meta.Selected = false; -#define SET_POS(node, pos) meta.Position = pos; node->Meta.AddEntry(11, (byte*)&meta, sizeof(meta)); -#define CONNECT(boxA, boxB) boxA.Connections.Add(&boxB); boxB.Connections.Add(&boxA) - auto diffuseTexture = AddTextureNode(layer, options.Diffuse.Texture); - auto diffuseColor = AddColorNode(layer, options.Diffuse.Color, Color::White); - if (diffuseTexture && diffuseColor) + + // Diffuse + Mask + ShaderGraphNode<>* diffuseTextureNode; + AddInput(layer, meta, MaterialGraphBoxes::Color, options.Diffuse.Texture, options.Diffuse.Color, Color::White, Float2::Zero, &diffuseTextureNode); + if (diffuseTextureNode && options.Diffuse.HasAlphaMask) { - auto diffuseMultiply = AddMultiplyNode(layer); - CONNECT(diffuseMultiply->Boxes[0], diffuseTexture->Boxes[1]); - CONNECT(diffuseMultiply->Boxes[1], diffuseColor->Boxes[0]); - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Color)], diffuseMultiply->Boxes[2]); - SET_POS(diffuseColor, Float2(-467.7404, 91.41332)); - SET_POS(diffuseTexture, Float2(-538.096, -103.9724)); - SET_POS(diffuseMultiply, Float2(-293.5272f, -2.926111f)); - } - else if (diffuseTexture) - { - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Color)], diffuseTexture->Boxes[1]); - SET_POS(diffuseTexture, Float2(-293.5272f, -2.926111f)); - } - else if (diffuseColor) - { - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Color)], diffuseColor->Boxes[0]); - SET_POS(diffuseColor, Float2(-293.5272f, -2.926111f)); - } - if (diffuseTexture && options.Diffuse.HasAlphaMask) - { - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Mask)], diffuseTexture->Boxes[5]); - } - auto emissiveTexture = AddTextureNode(layer, options.Emissive.Texture); - auto emissiveColor = AddColorNode(layer, options.Emissive.Color, Color::Transparent); - if (emissiveTexture && emissiveColor) - { - auto emissiveMultiply = AddMultiplyNode(layer); - CONNECT(emissiveMultiply->Boxes[0], emissiveTexture->Boxes[1]); - CONNECT(emissiveMultiply->Boxes[1], emissiveColor->Boxes[0]); - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Emissive)], emissiveMultiply->Boxes[2]); - SET_POS(emissiveTexture, Float2(-667.7404, 91.41332)); - SET_POS(emissiveTexture, Float2(-738.096, -103.9724)); - SET_POS(emissiveMultiply, Float2(-493.5272f, -2.926111f)); - } - else if (emissiveTexture) - { - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Emissive)], emissiveTexture->Boxes[1]); - SET_POS(emissiveTexture, Float2(-493.5272f, -2.926111f)); - } - else if (emissiveColor) - { - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Emissive)], emissiveColor->Boxes[0]); - SET_POS(emissiveColor, Float2(-493.5272f, -2.926111f)); + CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Mask)], diffuseTextureNode->Boxes[5]); } + + // Emissive + AddInput(layer, meta, MaterialGraphBoxes::Emissive, options.Emissive.Texture, options.Emissive.Color, Color::Transparent, Float2(0, 200)); + + // Opacity + AddInput(layer, meta, MaterialGraphBoxes::Opacity, options.Opacity.Texture, options.Opacity.Value, 1.0f, Float2(0, 400)); + + // Opacity + AddInput(layer, meta, MaterialGraphBoxes::Roughness, options.Roughness.Texture, options.Roughness.Value, 0.5f, Float2(200, 400)); + + // Normal auto normalMap = AddTextureNode(layer, options.Normals.Texture, true); if (normalMap) { CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Normal)], normalMap->Boxes[1]); SET_POS(normalMap, Float2(-893.5272f, -200.926111f)); } - auto opacityTexture = AddTextureNode(layer, options.Opacity.Texture); - auto opacityValue = AddFloatValue(layer, options.Opacity.Value, 1.0f); - if (opacityTexture && opacityValue) - { - auto opacityMultiply = AddMultiplyNode(layer); - CONNECT(opacityMultiply->Boxes[0], opacityTexture->Boxes[1]); - CONNECT(opacityMultiply->Boxes[1], opacityValue->Boxes[0]); - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Opacity)], opacityMultiply->Boxes[2]); - SET_POS(opacityTexture, Float2(-867.7404, 91.41332)); - SET_POS(opacityTexture, Float2(-938.096, -103.9724)); - SET_POS(opacityMultiply, Float2(-693.5272f, -2.926111f)); - } - else if (opacityTexture) - { - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Opacity)], opacityTexture->Boxes[1]); - SET_POS(opacityTexture, Float2(-693.5272f, -2.926111f)); - } - else if (opacityValue) - { - CONNECT(layer->Root->Boxes[static_cast(MaterialGraphBoxes::Opacity)], opacityValue->Boxes[0]); - SET_POS(opacityValue, Float2(-693.5272f, -2.926111f)); - } -#undef CONNECT + MemoryWriteStream stream(512); layer->Graph.Save(&stream, true); context.Data.Header.Chunks[SHADER_FILE_CHUNK_VISJECT_SURFACE]->Data.Copy(stream.GetHandle(), stream.GetPosition()); @@ -224,4 +205,7 @@ CreateAssetResult CreateMaterial::Create(CreateAssetContext& context) return CreateAssetResult::Ok; } +#undef CONNECT +#undef SET_POS + #endif diff --git a/Source/Engine/ContentImporters/CreateMaterial.h b/Source/Engine/ContentImporters/CreateMaterial.h index 3f6a2ff7f..27de5721f 100644 --- a/Source/Engine/ContentImporters/CreateMaterial.h +++ b/Source/Engine/ContentImporters/CreateMaterial.h @@ -37,6 +37,12 @@ public: Guid Texture = Guid::Empty; } Opacity; + struct + { + float Value = 0.5f; + Guid Texture = Guid::Empty; + } Roughness; + struct { Guid Texture = Guid::Empty; diff --git a/Source/Engine/Core/Math/Color.h b/Source/Engine/Core/Math/Color.h index 836ead090..5d177ee2c 100644 --- a/Source/Engine/Core/Math/Color.h +++ b/Source/Engine/Core/Math/Color.h @@ -237,9 +237,10 @@ public: Color& operator*=(const float b) { - R = Math::Saturate(R * b); - G = Math::Saturate(G * b); - B = Math::Saturate(B * b); + R = R * b; + G = G * b; + B = B * b; + A = A * b; return *this; } diff --git a/Source/Engine/Graphics/Models/ModelData.cpp b/Source/Engine/Graphics/Models/ModelData.cpp index cc95ed6ba..21905a9ae 100644 --- a/Source/Engine/Graphics/Models/ModelData.cpp +++ b/Source/Engine/Graphics/Models/ModelData.cpp @@ -622,9 +622,21 @@ bool MaterialSlotEntry::UsesProperties() const Emissive.TextureIndex != -1 || !Math::IsOne(Opacity.Value) || Opacity.TextureIndex != -1 || + Math::NotNearEqual(Roughness.Value, 0.5f) || + Roughness.TextureIndex != -1 || Normals.TextureIndex != -1; } +float MaterialSlotEntry::ShininessToRoughness(float shininess) +{ + // https://github.com/assimp/assimp/issues/4573 + const float a = -1.0f; + const float b = 2.0f; + const float c = (shininess / 100) - 1; + const float d = b * b - (4 * a * c); + return (-b + Math::Sqrt(d)) / (2 * a); +} + ModelLodData::~ModelLodData() { Meshes.ClearDelete(); diff --git a/Source/Engine/Graphics/Models/ModelData.h b/Source/Engine/Graphics/Models/ModelData.h index 65bedf876..f0a0eb3dd 100644 --- a/Source/Engine/Graphics/Models/ModelData.h +++ b/Source/Engine/Graphics/Models/ModelData.h @@ -356,6 +356,12 @@ struct FLAXENGINE_API MaterialSlotEntry int32 TextureIndex = -1; } Opacity; + struct + { + float Value = 0.5f; + int32 TextureIndex = -1; + } Roughness; + struct { int32 TextureIndex = -1; @@ -364,6 +370,7 @@ struct FLAXENGINE_API MaterialSlotEntry bool TwoSided = false; bool UsesProperties() const; + static float ShininessToRoughness(float shininess); }; /// diff --git a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp index 5c72d963f..8ec8bcbc7 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp @@ -232,6 +232,8 @@ struct OpenFbxImporterData if (mat && EnumHasAnyFlags(Options.ImportTypes, ImportDataTypes::Materials)) { material.Diffuse.Color = ToColor(mat->getDiffuseColor()); + material.Emissive.Color = ToColor(mat->getEmissiveColor()) * (float)mat->getEmissiveFactor(); + material.Roughness.Value = MaterialSlotEntry::ShininessToRoughness((float)mat->getShininess()); if (EnumHasAnyFlags(Options.ImportTypes, ImportDataTypes::Textures)) { diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp index 74cbfbb52..97789421d 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp @@ -1219,6 +1219,9 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option materialOptions.Opacity.Value = material.Opacity.Value; if (material.Opacity.TextureIndex != -1) materialOptions.Opacity.Texture = data.Textures[material.Opacity.TextureIndex].AssetID; + materialOptions.Roughness.Value = material.Roughness.Value; + if (material.Roughness.TextureIndex != -1) + materialOptions.Roughness.Texture = data.Textures[material.Roughness.TextureIndex].AssetID; if (material.Normals.TextureIndex != -1) materialOptions.Normals.Texture = data.Textures[material.Normals.TextureIndex].AssetID; if (material.TwoSided || material.Diffuse.HasAlphaMask)