Search code examples
c#wpfshaderpixel-shader

Setting pixel shader uniform variable


Dummy question, I guess. I have a custom shader that looks like this:

sampler2D InputTexture;

float parameter1, parameter2 etc

float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 result = blah-blah-blah some calculations using parameter1, parameter2 etc.

    return result;
}

I'm trying to use it via wrapper that looks like this:

class MyShaderEffect : ShaderEffect
{
    private PixelShader _pixelShader = new PixelShader();
    public readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(MyShaderEffect), 0);

    public MyShaderEffect()
    {
        _pixelShader.UriSource = new Uri("MyShader.ps", UriKind.Relative);
        this.PixelShader = _pixelShader;
        this.UpdateShaderValue(InputProperty);
    }

    public Brush Input
    {
        get { return (Brush)this.GetValue(InputProperty); }
        set { this.SetValue(InputProperty, value); }
    }
}

So, my question is: how do I set those shader parameters from C# program?


Solution

  • It's right there in the documentation of the ShaderEffect class. You need to create dependency properties for every parameter. For example:

    class MyShaderEffect
    {
        public MyShaderEffect()
        {
            PixelShader = _pixelShader;
    
            UpdateShaderValue(InputProperty);
            UpdateShaderValue(ThresholdProperty);
        }
    
        public double Threshold
        {
            get { return (double)GetValue(ThresholdProperty); }
            set { SetValue(ThresholdProperty, value); }
        }
    
        public static readonly DependencyProperty ThresholdProperty =
            DependencyProperty.Register("Threshold", typeof(double), typeof(MyShaderEffect),
                    new UIPropertyMetadata(0.5, PixelShaderConstantCallback(0)));
    }
    

    The 0 in PixelShaderConstantCallback refers to the register you use in HLSL:

    float threshold : register(c0);
    

    This way WPF knows to update the shader when the property changes. It's also important to call UpdateShaderValue in the constructor to initially pass the value.