diff --git a/Source/Editor/Surface/Archetypes/Textures.cs b/Source/Editor/Surface/Archetypes/Textures.cs index 6e4e34f43..4d9f64085 100644 --- a/Source/Editor/Surface/Archetypes/Textures.cs +++ b/Source/Editor/Surface/Archetypes/Textures.cs @@ -405,6 +405,24 @@ namespace FlaxEditor.Surface.Archetypes NodeElementArchetype.Factory.Output(0, "Color", typeof(Float3), 3) } }, + new NodeArchetype + { + TypeID = 17, + Title = "Stochastic Sample Texture", + Description = "Projects a texture using world-space coordinates instead of UVs.", + Flags = NodeFlags.MaterialGraph, + Size = new Float2(240, 60), + DefaultValues = new object[] + { + new Float2(1.0f, 1.0f), + }, + Elements = new[] + { + NodeElementArchetype.Factory.Input(0, "Texture", true, typeof(FlaxEngine.Object), 0), + NodeElementArchetype.Factory.Input(1, "UV", true, typeof(Float2), 1, 0), + NodeElementArchetype.Factory.Output(0, "Color", typeof(Float4), 2), + } + }, }; } } diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp index d6ae2719f..d339bb72e 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp @@ -669,6 +669,115 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value) _writer.Write(*triplanarTexture); value = result; } + case 17: + { + auto textureBox = node->GetBox(0); + auto uvsBox = node->GetBox(1); + + Value uvs; + const bool useCustomUVs = uvsBox->HasConnection(); + if (useCustomUVs) + { + // Get custom UVs + uvs = eatBox(uvsBox->GetParent(), uvsBox->FirstConnection()); + } + else + { + // Use default UVs + uvs = getUVs; + } + + if (!textureBox->HasConnection()) + { + // No texture to sample + value = Value::Zero; + break; + } + + if (!CanUseSample(_treeType)) + { + // Must sample texture in pixel shader + value = Value::Zero; + break; + } + + const auto texture = eatBox(textureBox->GetParent(), textureBox->FirstConnection()); + const auto textureParam = findParam(texture.Value); + const bool isNormalMap = textureParam->Type == MaterialParameterType::NormalMap; + + auto result = writeLocal(Value::InitForZero(ValueType::Float4), node); + createGradients(node); + + auto proceduralSample = String::Format(TEXT( + " {{\n" + " float W1, W2, W3;\n" + " float2 vertex1, vertex2, vertex3;\n" + " float2 uv = {0} * 3.464; // 2 * sqrt (3);\n" + " float2 UV1, UV2, UV3;\n" + " const float2x2 gridToSkewedGrid = float2x2( 1.0, 0.0, -0.57735027, 1.15470054 );\n" + " float2 skewedCoord = mul( gridToSkewedGrid, uv );\n" + " int2 baseId = int2( floor( skewedCoord ) );\n" + " float3 temp = float3( frac( skewedCoord ), 0 );\n" + " temp.z = 1.0 - temp.x - temp.y;\n" + " if ( temp.z > 0.0 )\n" + " {{\n" + " W1 = temp.z;\n" + " W2 = temp.y;\n" + " W3 = temp.x;\n" + " vertex1 = baseId;\n" + " vertex2 = baseId + int2( 0, 1 );\n" + " vertex3 = baseId + int2( 1, 0 );\n" + " }}\n" + " else\n" + " {{\n" + " W1 = -temp.z;\n" + " W2 = 1.0 - temp.y;\n" + " W3 = 1.0 - temp.x;\n" + " vertex1 = baseId + int2( 1, 1 );\n" + " vertex2 = baseId + int2( 1, 0 );\n" + " vertex3 = baseId + int2( 0, 1 );\n" + " }}\n" + " UV1 = {0} + frac( sin( mul( float2x2( 127.1, 311.7, 269.5, 183.3 ), vertex1 ) ) * 43758.5453 );\n" + " UV2 = {0} + frac( sin( mul( float2x2( 127.1, 311.7, 269.5, 183.3 ), vertex2 ) ) * 43758.5453 );\n" + " UV3 = {0} + frac( sin( mul( float2x2( 127.1, 311.7, 269.5, 183.3 ), vertex3 ) ) * 43758.5453 );\n" + " float4 tex1 = {1}.SampleGrad(SamplerLinearWrap, UV1, {2}, {3});\n" + " float4 tex2 = {1}.SampleGrad(SamplerLinearWrap, UV2, {2}, {3});\n" + " float4 tex3 = {1}.SampleGrad(SamplerLinearWrap, UV3, {2}, {3});\n" + ), + uvs.Value, // {0} + texture.Value, // {1} + _ddx.Value, // {2} + _ddy.Value // {3} + ); + + // Decode normal map vector + if (isNormalMap) + { + proceduralSample += String::Format(TEXT( + " tex1.xy = tex1.xy * 2.0 - 1.0;\n" + " tex1.z = sqrt(saturate(1.0 - dot(tex1.xy, tex1.xy))); \n" + " tex2.xy = tex2.xy * 2.0 - 1.0;\n" + " tex2.z = sqrt(saturate(1.0 - dot(tex2.xy, tex2.xy))); \n" + " tex3.xy = tex3.xy * 2.0 - 1.0;\n" + " tex3.z = sqrt(saturate(1.0 - dot(tex3.xy, tex3.xy))); \n" + )); + } + + proceduralSample += String::Format(TEXT( + " tex1 *= W1;\n" + " tex2 *= W2;\n" + " tex3 *= W3;\n" + " {0} = tex1 + tex2 + tex3;\n" + " }}\n" + ), + result.Value // {0} + ); + + _writer.Write(*proceduralSample); + value = result; + + break; + } default: break; }