Facepunch / sbox-issues

165 stars 11 forks source link

Need combine float2/float3 for shadergraph editor #3819

Open nicholas477 opened 11 months ago

nicholas477 commented 11 months ago

For?

S&Box

What can't you do?

Right now there's only support for making float4s with the combine node in the shadergraph. I wanted to make a shader that makes a grid in xy world space but I can't. The issue is that I can't run fwidth() on just the XY axes of the world space since there's no combine node for float2.

How would you like it to work?

Add a combine2/combine3 node that makes float2s, float3s.

What have you tried?

I made my own combine vector 2 node:

/// <summary>
/// Combine values into a single vector2
/// </summary>
[Title( "Combine2" ), Category( "Channel" )]
public class CombineVector2 : ShaderNode
{
    [Input( typeof( float ) )]
    [HideInEditor]
    public NodeInput X { get; set; }

    [Input( typeof( float ) )]
    [HideInEditor]
    public NodeInput Y { get; set; }

    public float DefaultX { get; set; } = 0.0f;
    public float DefaultY { get; set; } = 0.0f;

    [Output( typeof( Vector2 ) )]
    [HideInEditor]
    public NodeResult.Func Vector => ( Compiler compiler ) =>
    {
        var x = compiler.ResultOrDefault( X, DefaultX ).Cast( 1 );
        var y = compiler.ResultOrDefault( Y, DefaultY ).Cast( 1 );

        return new NodeResult( 2, $"float2( {x}, {y} )" );
    };
}

it works great but I don't want to edit the engine.

Additional context

No response

QuackCola commented 11 months ago

The existing Combine could probably be modified to support just combing into a float 2 and float3.

Or better yet maybe if a node is not connected to z , w inputs of a combine node assume the user wants just a combined float2 from two floats? Same sort of situation if a user only has connected to x,y.z of a combine node resulting in a float3.

QuackCola commented 9 months ago

Another simpler solution that could be done if Facepunch still wants to keep it to one node, which is what is done in unity shadergraph.

/// <summary>
/// Combine input values into 3 separate vectors
/// </summary>
[Title( "Combine" ), Category( "Channel" )]
public class CombineVector : ShaderNode
{
    [Input( typeof( float ) )]
    [HideInEditor]
    public NodeInput X { get; set; }

    [Input( typeof( float ) )]
    [HideInEditor]
    public NodeInput Y { get; set; }

    [Input( typeof( float ) )]
    [HideInEditor]
    public NodeInput Z { get; set; }

    [Input( typeof( float ) )]
    [HideInEditor]
    public NodeInput W { get; set; }

    public float DefaultX { get; set; } = 0.0f;
    public float DefaultY { get; set; } = 0.0f;
    public float DefaultZ { get; set; } = 0.0f;
    public float DefaultW { get; set; } = 0.0f;

    [Output( typeof( Vector4 ) )]
    [HideInEditor]
    public NodeResult.Func XYZW => ( Compiler compiler ) =>
    {
        var x = compiler.ResultOrDefault( X, DefaultX ).Cast( 1 );
        var y = compiler.ResultOrDefault( Y, DefaultY ).Cast( 1 );
        var z = compiler.ResultOrDefault( Z, DefaultZ ).Cast( 1 );
        var w = compiler.ResultOrDefault( W, DefaultW ).Cast( 1 );

        return new NodeResult( 4, $"float4( {x}, {y}, {z}, {w} )" );
    };

    [Output( typeof( Vector3 ) )]
    [HideInEditor]
    public NodeResult.Func XYZ => ( Compiler compiler ) =>
    {
        var x = compiler.ResultOrDefault( X, DefaultX ).Cast( 1 );
        var y = compiler.ResultOrDefault( Y, DefaultY ).Cast( 1 );
        var z = compiler.ResultOrDefault( Z, DefaultZ ).Cast( 1 );

        return new NodeResult( 3, $"float3( {x}, {y}, {z} )" );
    };

    [Output( typeof( Vector2 ) )]
    [HideInEditor]
    public NodeResult.Func XY => ( Compiler compiler ) =>
    {
        var x = compiler.ResultOrDefault( X, DefaultX ).Cast( 1 );
        var y = compiler.ResultOrDefault( Y, DefaultY ).Cast( 1 );

        return new NodeResult( 2, $"float2( {x}, {y})" );
    };
}

Otherwise something like Compose Vector 2, Compose Vector 3, and changing the current combine name to compose vector 4 would work just as well.

Also renaming it from combine to compose when taking the individual node route would make more sense for the name of the nodes in my opinion.