在我的Pixel Shader(UWP,Win2D)中支持多种颜色输入 [英] Support more than one color input in my Pixel Shader (UWP, Win2D)

查看:149
本文介绍了在我的Pixel Shader(UWP,Win2D)中支持多种颜色输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在开发一个可以提供颜色替换功能的应用程序,并且@Jet Chopper在解决方案上提供了很多帮助.他向我提供了以下代码,该代码基本上使用ControlSpectrum控件来控制源颜色和目标颜色.想法是您指定一个源颜色",然后将其替换为目标颜色".这是当前的工作代码:

I've been working on an app that can provide Color Replacement, and had a lot of help from @Jet Chopper on a solution. He's provided me the following code which essentially uses a ControlSpectrum control for Source and Target colors. The idea is you specify a Source Color which then gets replaced by a Target color. Here's the current working code:

这是我的原始帖子,其中包含带有GIF的原始解决方案. 原始帖子

This is my original post that contains the original solution with a GIF. Original Post

XAML:

<Grid>
    <xaml:CanvasAnimatedControl x:Name="AnimatedControl"
                            CreateResources="AnimatedControl_OnCreateResources"
                            Draw="AnimatedControl_OnDraw"/>

    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Bottom">
        <TextBlock Text="Source Color" FontSize="32" Foreground="White" TextAlignment="Center"/>

        <ColorSpectrum Width="256" Height="256" ColorChanged="SourceColorSpectrum_OnColorChanged"/>
    </StackPanel>

    <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom">
        <TextBlock Text="Replace Color" FontSize="32" Foreground="White" TextAlignment="Center"/>

        <ColorSpectrum Width="256" Height="256" ColorChanged="TargetColorSpectrum_OnColorChanged"/>
    </StackPanel>

    <Slider Width="512" ValueChanged="RangeBase_OnValueChanged" VerticalAlignment="Center"/>
</Grid>

代码:

private PixelShaderEffect _textureShader;
private GaussianBlurEffect _blur;
private BlendEffect _blend;

private void AnimatedControl_OnCreateResources(CanvasAnimatedControl sender, CanvasCreateResourcesEventArgs args)
{
    args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
}

private async Task CreateResourcesAsync(CanvasAnimatedControl sender)
{
    var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Shaders/TextureTest.bin"));
    var buffer = await FileIO.ReadBufferAsync(file);

    var sourceImage = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///Assets/image.jpg"));

    _textureShader = new PixelShaderEffect(buffer.ToArray())
    {
        Source1 = sourceImage
    };

    _blur = new GaussianBlurEffect
    {
        BlurAmount = 4,
        Source = _textureShader
    };

    _blend = new BlendEffect
    {
        Foreground = _blur,
        Background = sourceImage,
        Mode = BlendEffectMode.Color
    };
}

private void AnimatedControl_OnDraw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
{
    args.DrawingSession.DrawImage(_blend);
}

private void RangeBase_OnValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    _textureShader.Properties["threshold"] = (float)e.NewValue / 100;
}

private void SourceColorSpectrum_OnColorChanged(ColorSpectrum sender, ColorChangedEventArgs args)
{
    _textureShader.Properties["sourceColor"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
}

private void TargetColorSpectrum_OnColorChanged(ColorSpectrum sender, ColorChangedEventArgs args)
{
    _textureShader.Properties["replaceColor"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
}

像素着色器:

#define D2D_INPUT_COUNT 1
#define D2D_INPUT0_SIMPLE

#include "d2d1effecthelpers.hlsli"

float3 sourceColor;
float3 replaceColor;
float threshold;

D2D_PS_ENTRY(main)
{
    float3 color = D2DGetInput(0).rgb;

    if (abs(color.r - sourceColor.r) < threshold && abs(color.g - sourceColor.g) < threshold && abs(color.b - sourceColor.b) < threshold) 
    {
        float3 newColor = color - sourceColor + replaceColor;
        return float4(newColor.r, newColor.g, newColor.b, 1);
    }
    else 
    {
        return float4(0, 0, 0, 0);
    }
}

因此,我的下一步是将这一解决方案向前推进,并同时引入更多的一种颜色替换.因此,我更改了所有内容以支持2种颜色:

So my next step was to take this solution one step forward and introduce more that one color replacement simulataneously. So I changed everything to support 2 colors as such:

XAML:

<Grid>
    <xaml:CanvasAnimatedControl x:Name="AnimatedControl"
                            CreateResources="AnimatedControl_OnCreateResources"
                            Draw="AnimatedControl_OnDraw"/>

    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Bottom">
        <TextBlock Text="Source Color" FontSize="32" Foreground="White" TextAlignment="Center"/>

        <ColorSpectrum Width="256" Height="256" ColorChanged="SourceColorSpectrum_OnColorChanged"/>
        <ColorSpectrum Width="256" Height="256" ColorChanged="SourceColorSpectrum_OnColorChanged2"/>
    </StackPanel>

    <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom">
        <TextBlock Text="Replace Color" FontSize="32" Foreground="White" TextAlignment="Center"/>

        <ColorSpectrum Width="256" Height="256" ColorChanged="TargetColorSpectrum_OnColorChanged"/>
        <ColorSpectrum Width="256" Height="256" ColorChanged="TargetColorSpectrum_OnColorChanged2"/>
    </StackPanel>

    <Slider Width="512" ValueChanged="RangeBase_OnValueChanged" VerticalAlignment="Center"/>
</Grid>

代码:

private PixelShaderEffect _textureShader;
private GaussianBlurEffect _blur;
private BlendEffect _blend;

private void AnimatedControl_OnCreateResources(CanvasAnimatedControl sender, CanvasCreateResourcesEventArgs args)
{
    args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
}

private async Task CreateResourcesAsync(CanvasAnimatedControl sender)
{
    var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Shaders/TextureTest.bin"));
    var buffer = await FileIO.ReadBufferAsync(file);

    var sourceImage = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///Assets/image.jpg"));

    _textureShader = new PixelShaderEffect(buffer.ToArray())
    {
        Source1 = sourceImage,
        Source2 = sourceImage
    };

    _blur = new GaussianBlurEffect
    {
        BlurAmount = 4,
        Source = _textureShader
    };

    _blend = new BlendEffect
    {
        Foreground = _blur,
        Background = sourceImage,
        Mode = BlendEffectMode.Color
    };
}

private void AnimatedControl_OnDraw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
{
    args.DrawingSession.DrawImage(_blend);
}

private void RangeBase_OnValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
    _textureShader.Properties["threshold"] = (float)e.NewValue / 100;
}

private void SourceColorSpectrum_OnColorChanged(ColorSpectrum sender, ColorChangedEventArgs args)
{
    _textureShader.Properties["sourceColor"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
}

private void TargetColorSpectrum_OnColorChanged(ColorSpectrum sender, ColorChangedEventArgs args)
{
    _textureShader.Properties["replaceColor"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
}

private void SourceColorSpectrum_OnColorChanged2(ColorSpectrum sender, ColorChangedEventArgs args)
{
    _textureShader.Properties["sourceColor2"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
}

private void TargetColorSpectrum_OnColorChanged2(ColorSpectrum sender, ColorChangedEventArgs args)
{
    _textureShader.Properties["replaceColor2"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
}

像素着色器:

#define D2D_INPUT_COUNT 2
#define D2D_INPUT0_SIMPLE
#define D2D_INPUT1_SIMPLE

#include "d2d1effecthelpers.hlsli"

float3 sourceColor;
float3 replaceColor;
float3 sourceColor2;
float3 replaceColor2;
float threshold;

D2D_PS_ENTRY(main)
{
    float3 color1 = D2DGetInput(0).rgb;
    float3 color2 = D2DGetInput(1).rgb;

    float4 result1;
    float4 result2;

    if (abs(color1.r - sourceColor.r) < threshold &&
        abs(color1.g - sourceColor.g) < threshold &&
        abs(color1.b - sourceColor.b) < threshold) 
    {
        float3 newColor = color1 - sourceColor + replaceColor;
        result1 = float4(newColor.r, newColor.g, newColor.b, 1);
    }
    else 
    {
        result1 = float4(0, 0, 0, 0);
    }

    if (abs(color2.r - sourceColor2.r) < threshold &&
        abs(color2.g - sourceColor2.g) < threshold &&
        abs(color2.b - sourceColor2.b) < threshold)
    {
        float3 newColor = color2 - sourceColor2 + replaceColor2;
        result2 = float4(newColor.r, newColor.g, newColor.b, 1);
    }
    else
    {
        result2 = float4(0, 0, 0, 0);
    }

    return result1 * result2;
}

因此,基本上,我只是将XAML,代码和Pixel Shader中的所有内容都加倍了.但是对于像素着色器,通过将两个结果相乘,我不确定我的返回值是否正确.我是否有能力一次替换多种颜色的正确选择?

So essentially I just doubled everything, in the XAML, the code, and the Pixel Shader. But for the Pixel Shader, I'm not sure if my return value is correct by multiplying both results. Am I on the right track for the ability to replace more than one color at once ?

推荐答案

好,这是您的示例,其中包含2种输入颜色,2种替换颜色和2种阈值.

Ok here's your sample with 2 input colors, 2 replace colors and 2 thresholds.

XAML:

<Grid>
    <xaml:CanvasAnimatedControl x:Name="AnimatedControl"
                            CreateResources="AnimatedControl_OnCreateResources"
                            Draw="AnimatedControl_OnDraw"/>

    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Bottom">
        <TextBlock Text="Source Color 2" FontSize="16" Foreground="White" TextAlignment="Center"/>

        <ColorSpectrum Width="128" Height="128" ColorChanged="ColorSpectrum_OnColorChanged2"/>
    </StackPanel>

    <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom">
        <TextBlock Text="Replace Color 2" FontSize="16" Foreground="White" TextAlignment="Center"/>

        <ColorSpectrum Width="128" Height="128" ColorChanged="ColorSpectrum_OnColorChanged3"/>
    </StackPanel>

    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top">
        <TextBlock Text="Source Color 1" FontSize="16" Foreground="White" TextAlignment="Center"/>

        <ColorSpectrum Width="128" Height="128" ColorChanged="ColorSpectrum_OnColorChanged"/>
    </StackPanel>

    <StackPanel HorizontalAlignment="Right" VerticalAlignment="Top">
        <TextBlock Text="Replace Color 1" FontSize="16" Foreground="White" TextAlignment="Center"/>

        <ColorSpectrum Width="128" Height="128" ColorChanged="ColorSpectrum_OnColorChanged1"/>
    </StackPanel>

    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
    <Slider Width="512" ValueChanged="RangeBase_OnValueChanged" VerticalAlignment="Center"/>
    <Slider Width="512" ValueChanged="RangeBase1_OnValueChanged" VerticalAlignment="Center"/>
    </StackPanel>
</Grid>

后面的代码:

    private PixelShaderEffect _textureShader;
    private GaussianBlurEffect _blur;
    private BlendEffect _blend;

    public Ripple()
    {
        InitializeComponent();
    }

    private void AnimatedControl_OnCreateResources(CanvasAnimatedControl sender, CanvasCreateResourcesEventArgs args)
    {
        args.TrackAsyncAction(CreateResourcesAsync(sender).AsAsyncAction());
    }

    private async Task CreateResourcesAsync(CanvasAnimatedControl sender)
    {
        var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Shaders/TextureTest.bin"));
        var buffer = await FileIO.ReadBufferAsync(file);

        var sourceImage = await CanvasBitmap.LoadAsync(sender, new Uri("ms-appx:///Assets/image.jpg"));

        _textureShader = new PixelShaderEffect(buffer.ToArray())
        {
            Source1 = sourceImage
        };

        _blur = new GaussianBlurEffect
        {
            BlurAmount = 4,
            Source = _textureShader
        };

        _blend = new BlendEffect
        {
            Foreground = _blur,
            Background = sourceImage,
            Mode = BlendEffectMode.Color
        };
    }

    private void AnimatedControl_OnDraw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
    {
        args.DrawingSession.DrawImage(_blend);
    }

    private void RangeBase_OnValueChanged(object sender, RangeBaseValueChangedEventArgs e)
    {
        _textureShader.Properties["threshold"] = (float)e.NewValue / 100;
    }

    private void ColorSpectrum_OnColorChanged(ColorSpectrum sender, ColorChangedEventArgs args)
    {
        _textureShader.Properties["sourceColor"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
    }

    private void ColorSpectrum_OnColorChanged1(ColorSpectrum sender, ColorChangedEventArgs args)
    {
        _textureShader.Properties["replaceColor"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
    }

    private void RangeBase1_OnValueChanged(object sender, RangeBaseValueChangedEventArgs e)
    {
        _textureShader.Properties["threshold2"] = (float)e.NewValue / 100;
    }

    private void ColorSpectrum_OnColorChanged2(ColorSpectrum sender, ColorChangedEventArgs args)
    {
        _textureShader.Properties["sourceColor2"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
    }

    private void ColorSpectrum_OnColorChanged3(ColorSpectrum sender, ColorChangedEventArgs args)
    {
        _textureShader.Properties["replaceColor2"] = new Vector3((float)args.NewColor.R / 255, (float)args.NewColor.G / 255, (float)args.NewColor.B / 255);
    }

HLSL着色器:

#define D2D_INPUT_COUNT 1
#define D2D_INPUT0_SIMPLE

#include "d2d1effecthelpers.hlsli"

float3 sourceColor;
float3 replaceColor;
float threshold;

float3 sourceColor2;
float3 replaceColor2;
float threshold2;

D2D_PS_ENTRY(main)
{
    float3 color = D2DGetInput(0).rgb;

    if (abs(color.r - sourceColor.r) < threshold && abs(color.g - sourceColor.g) < threshold && abs(color.b - sourceColor.b) < threshold) 
    {
        float3 newColor = color - sourceColor + replaceColor;
        return float4(newColor.r, newColor.g, newColor.b, 1);
    }
    else if (abs(color.r - sourceColor2.r) < threshold2 && abs(color.g - sourceColor2.g) < threshold2 && abs(color.b - sourceColor2.b) < threshold2)
    {
        float3 newColor = color - sourceColor2 + replaceColor2;
        return float4(newColor.r, newColor.g, newColor.b, 1);
    }
    else 
    {
        return float4(0, 0, 0, 0);
    }
}

享受!

这篇关于在我的Pixel Shader(UWP,Win2D)中支持多种颜色输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆