Repository: FlaxEngine/FlaxEngine
File: Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp (C++)

Code before:
        auto scaleBox = node->GetBox(1);
        
        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<Node>(), textureBox->FirstConnection());
        const auto scale = tryGetValue(scaleBox, node->Values[0]);

        auto result = writeLocal(Value::InitForZero(ValueType::Float4), node);

        const String triplanarTexture = String::Format(TEXT(
            "   float3 worldPos = input.WorldPosition.xyz * {1} / 1000;\n"
            "   float3 normal = input.TBN[2];\n"

            "   {2} += {0}.Sample(SamplerLinearWrap, worldPos.yz) * abs(dot(normal, float3(1,0,0)));\n"
            "   {2} += {0}.Sample(SamplerLinearWrap, worldPos.xz) * abs(dot(normal, float3(0,1,0)));\n"
            "   {2} += {0}.Sample(SamplerLinearWrap, worldPos.xy) * abs(dot(normal, float3(0,0,1)));\n"
        ),
                texture.Value,  //  {0}
                scale.Value,    //  {1}
                result.Value    //  {2}
        );

        _writer.Write(*triplanarTexture);
        value = result;
    }
    default:
        break;
    }
}

#endif


Review comment (suggestion):
Optionally: provide `float Blend = 1.0f` input to the node and apply it here to control the blending threshold:
```hlsl
{2} += {0}.Sample(SamplerLinearWrap, worldPos.yz) * pow(abs(dot(normal, float3(1,0,0)), {3}));
// {3} = Blend
```
(would be nice to have so the transition on the object edges could be bigger or smaller)

Code after:
        auto scaleBox = node->GetBox(1);
        auto blendBox = node->GetBox(2);
        
        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<Node>(), textureBox->FirstConnection());
        const auto scale = tryGetValue(scaleBox, node->Values[0]);
        const auto blend = tryGetValue(blendBox, node->Values[1]);

        auto result = writeLocal(Value::InitForZero(ValueType::Float4), node);

        const String triplanarTexture = String::Format(TEXT(
            "   float3 worldPos = input.WorldPosition.xyz * ({1} * 0.001f);\n"
            "   float3 normal = input.TBN[2];\n"

            "   {3} += {0}.Sample(SamplerLinearWrap, worldPos.yz) * pow(abs(dot(normal, float3(1,0,0))), {2});\n"
            "   {3} += {0}.Sample(SamplerLinearWrap, worldPos.xz) * pow(abs(dot(normal, float3(0,1,0))), {2});\n"
            "   {3} += {0}.Sample(SamplerLinearWrap, worldPos.xy) * pow(abs(dot(normal, float3(0,0,1))), {2});\n"
        ),
                texture.Value,  //  {0}
                scale.Value,    //  {1}
                blend.Value,    //  {2}
                result.Value    //  {3}
        );

        _writer.Write(*triplanarTexture);
        value = result;
    }
    default:
        break;
    }
}

#endif