我一直在开发一款可以提供Color Replacement的应用程序,并且@Jet Chopper在解决方案上提供了很多帮助。他为我提供了以下代码,它基本上使用ControlSpectrum控件来获取源颜色和目标颜色。您的想法是指定一个源颜色,然后由目标颜色替换。这是当前的工作代码:
这是我的原始帖子,其中包含带有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>
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);
}
PIXEL SHADER:
#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种颜色:
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);
}
PIXEL SHADER:
#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,我不确定两个结果相乘,我的返回值是否正确。我是否能够一次性更换多种颜色?
答案 0 :(得分:1)
好的,这里的样本有2种输入颜色,2种颜色和2种阈值。
XAML:
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);
}
代码背后:
#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);
}
}
HLSL着色器:
Location
享受!
答案 1 :(得分:0)
在WPF中,没有办法自动&#34;堆叠&#34;效果。但是,您可以使用合成来完成它。你不必对像素着色器所做的任何事情加倍。您基本上会对相关孩子的祖先加倍,并应用多个像素着色器效果。例如,假设您想要将2个颜色替换像素着色器应用于单个图像。以下伪代码可以帮助您:
<Grid Name="Ancestor1">
<Grid Name="Ancestor2">
<Image Source="..." Name="Child" />
</Grid>
</Grid>
在后面的代码中,您可以将像素着色器效果应用于每个祖先,如下所示:
Ancestor1.Effect = New ColorReplacementPixelShader() with { .PropertyA = someValue, ... }
Ancestor2.Effect = New ColorReplacementPixelShader() with { .PropertyA = somevalue, ... }
在这样做时,您已经有效地将相同的像素着色器TWICE应用于子图像元素,但是通过使用两个祖先堆叠效果来实现这一点。
希望有所帮助!