在我的 Pixel Shader(UWP、Win2D)中支持多种颜色输入

2024-02-10

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

这是我的原始帖子,其中包含带有 GIF 的原始解决方案。 原帖 https://stackoverflow.com/questions/47597409/does-uwp-composition-api-support-color-replacement/48548463?noredirect=1#comment84156100_48548463

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>

CODE:

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);
    }
}

因此,我的下一步是将该解决方案向前推进一步,同时引入多种颜色替换。所以我改变了一切以支持两种颜色:

我的改变

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>

CODE:

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、代码和像素着色器中的所有内容都加倍了。但对于像素着色器,我不确定通过将两个结果相乘我的返回值是否正确。我是否能够同时更换多种颜色?


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

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);
    }
}

Enjoy!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在我的 Pixel Shader(UWP、Win2D)中支持多种颜色输入 的相关文章

随机推荐

  • cfspreadsheet 以 d 结尾的字母数字值

  • Laravel 5 将视图和模型保留在资源视图目录中的单独文件夹中

    我已经搜索了很多我的要求 但没有找到适合我的工作解决方案 我正在使用 laravel 5 创建一个 Web 应用程序 我想将与管理员访问权限相关的所有控制器保留到控制器文件夹中的管理子文件夹中 为此我找到了很好的答案Laravel 控制器子
  • 如何在 YAML 中指定范围?

    我可以表达 第三页是扉页 in YAML title 3 那么下面的呢 第 10 至 15 页包含第 1 章 一种方法是 chapter 1 10 11 12 13 14 15 我更喜欢这里的范围 YAML中有类似的东西吗 chapter
  • 如何在 Play 中的静态方法中使用 play.cache.CacheApi!框架2.4.2

    我有一个 play 框架应用程序 我已将其迁移到 play 框架 2 4 2 上运行 它为 javascript html 前端提供 RESTful API 现在我在引入缓存时遇到了一些问题 LibraryController 将 JSON
  • Power Bi 中具有多轴的重叠条形图

    我想在 PowerBi 中有一个具有多个轴的重叠条形图 我有一个来自 Excel 的示例 如果可能的话 我希望在 PowerBi 中重新创建该示例 这里是例子 这在 PowerBi 中可能吗 也许通过使用我不知道的自定义视觉效果 提前致谢
  • AudioPlayer iOS 和 m4a

    我制作了一个使用 AVAudioPlayer 播放音乐的应用程序 它上传或下载歌曲 将它们写入核心数据 然后在选择时调用它们来播放 我测试过的所有 15 首歌曲都可以在 iPhone 音乐客户端和我自己的电脑上正常运行 但是 其中三个无法在
  • 动态复选框创建

    我想在我的 Android 应用程序运行时动态创建一组复选框 当应用程序运行时 除了按钮之外什么都不显示 我忘记了什么 提前致谢 public class DataNotificationSurvey extends Activity pr
  • 使用 PHP 在 CSV 文件中用双引号将每个字段括起来?

    我需要使用 PHP 将所有带有双引号的字符串和数字放入 CSV 文件中 如何从 PHP 创建 CSV 文件 并将所有数据放在双引号内 我正在使用此代码生成 CSV 我正在使用 codeigniter 框架 array array array
  • jQuery 切换 Cookie 支持

    我正在尝试将 jQuery Cookie 插件实现到我的幻灯片切换脚本中 但到目前为止尚未成功 这是我的代码 没有任何 cookie 实现 jQuery document ready function a toggle click func
  • Eclipse 缩进指南

    我正在尝试从以下网页安装 eclipse 的缩进指南插件 http sschaef github io IndentGuide http sschaef github io IndentGuide 我之前没有在 eclipse 中安装过插件
  • 进行机器间锁定有哪些好方法?

    我们的服务器集群由 20 台机器组成 每台机器有 10 个 5 个线程的 pid 我们想要某种方法来防止任何机器上任何 pid 中的任何两个线程同时修改同一个对象 我们的代码是用 Python 编写的并在 Linux 上运行 如果这有助于缩
  • 当应用程序在 WP 8.1 商店应用程序中恢复时,应用程序恢复事件不会触发

    我的 WP 8 1 商店应用程序的行为非常奇怪 当我快速离开然后返回时 应用程序恢复事件会按预期触发 但是 如果我将应用程序保留在后台一段时间 然后返回时 应用程序将触发 Constructor 和 OnNavigateTo 事件而不是 R
  • 检查 Rust 中的整数溢出[重复]

    这个问题在这里已经有答案了 Rust 有没有一种规范的方法来显式检查整数溢出 我用谷歌搜索但找不到答案 就像是 match add or overflow x y None gt println overflow Some z gt pri
  • 如何子类化 UILabel、UIButton 等 UI 元素

    我正在子类化UILabel in a CustomLabel class 当我尝试使用简单的方法时遇到问题UILabel我希望将来对其他元素进行子类化 我读到我可以创建一个category of UILabel 这东西哪一个比较好呢 类别还
  • Ansible Galaxy 角色安装到特定目录?

    所以我想我应该尽可能开始使用 Ansible Galaxy 而不是编写自己的角色 我刚刚安装了我的第一个角色 它被安装到 etc local ansible roles 我在 OSX 上 现在我想知道你如何在我真正需要的地方安装这个角色 我
  • Visual Studio 2012 附带哪个版本的 Dinkumware STL Lib?

    在早期版本的 Visual Studio 中 有一个预定义的宏 CPPLIB VER 它报告此版本 VS 附带的 Dinkumware STL 库的版本 截至 2012 年 我无法找到或使用这个宏 它未定义 并且我无法在网上找到有关此事的任
  • Sitecore 中的常规链接

    我是 Sitecore 的新手 我创建了一个页面模板 并为 常规链接 类型的 URL 添加了一个字段 我为链接文本创建了另一个字段 这是该项目中的标准做法 我只是想在我的用户控件中显示链接 但我无法让它工作 这应该很简单 但我在兜圈子 这是
  • 非焦点窗体上的 C#/WPF 热键(如 launchy)

    Is it possible to catch a hotkey eg Ctrl Space from a not focused form to make it appear whenever someone uses this spec
  • 我可以在 Fortran 中使用可分配数组作为意图(输出)矩阵吗?

    考虑以下子例程 subroutine myProc m n flag X Integer intent in m n logical intent in flag real 8 intent out allocatable X if fla
  • 在我的 Pixel Shader(UWP、Win2D)中支持多种颜色输入

    我一直在开发一款可以提供颜色替换的应用程序 并且在解决方案上从 Jet Chopper 获得了很多帮助 他为我提供了以下代码 该代码本质上使用 ControlSpectrum 控件来控制源颜色和目标颜色 这个想法是您指定一个源颜色 然后将其