如何使背景具有来自一组给定颜色的混乱颜色?
How to make a background have scrambled colours from a given set of colours?
我正在尝试使用与此颜色相似的背景 image。此处使用的颜色是#2E2E2E、#2C2C2C 和#2D2D2D,它们被拼凑在一起形成上面弹出窗口的颜色。
如果我没记错的话你需要渐变
您可以使用以下代码
<Grid>
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0" />
<GradientStop Color="White" Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
平铺图像是最简单的方法,但您也可以使用像素着色器。
有很多关于如何编写 WPF 像素着色器的教程,Anu Viswan's series 是一个很好的起点。首先,您需要确保 fxc.exe 编译器已安装在您的 PC 上,如果尚未安装(在我的机器上,它位于 C:\Program Files (x86)\Windows Kits\bin.0.19041.0\x64).
接下来您需要编写着色器本身。 Whosebug 用户 appas has a neat trick showing how to do it using the UV coordinates passed in for each pixel 首先,您需要为每个像素生成一个随机数。有了它,将它转换成一个整数并用它来索引你的颜色的查找table。
// NoiseEffect.hlsl
#define NUM_COLORS 3
static float4 lut[NUM_COLORS] = {
float4(1, 0, 0, 1), // red
float4(0, 1, 0, 1), // green
float4(0, 0, 1, 1) // blue
};
float rand(float2 co) {
return frac(sin(dot(co, float2(12.9898, 78.233))) * 43758.5453);
}
float4 main(float2 uv : TEXCOORD) : COLOR{
return lut[(int)floor(rand(uv) * NUM_COLORS)];
}
我在这里使用原色来使效果更明显,要使用您的原始值,您需要将每个组件转换为 0-1 范围:
static float4 lut[NUM_COLORS] = {
float4(0x2e / 255.0f, 0x2e / 255.0f, 0x2e / 255.0f, 1),
float4(0x2c / 255.0f, 0x2c / 255.0f, 0x2c / 255.0f, 1),
float4(0x2d / 255.0f, 0x2d / 255.0f, 0x2d / 255.0f, 1)
};
接下来,运行 fxc 将您的着色器编译成 ps 文件:
fxc.exe /T ps_2_0 /E main /Fo NoiseEffect.ps NoiseEffect.hlsl
将其添加到您的项目中,将其构建操作设置为 Resource,并创建着色器效果 class 以加载它(确保更改 URI 以匹配您的项目名称):
public class NoiseEffect : ShaderEffect
{
public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(NoiseEffect), 0);
public Brush Input
{
get => ((Brush)(GetValue(InputProperty)));
set => SetValue(InputProperty, value);
}
public NoiseEffect()
{
PixelShader pixelShader = new PixelShader();
pixelShader.UriSource = new Uri("pack://application:,,,/YourProjectName;component/NoiseEffect.ps", UriKind.Absolute);
PixelShader = pixelShader;
UpdateShaderValue(InputProperty);
}
}
然后您可以将它用作 XAML 中任何地方的效果,例如:
<Rectangle Width="200" Height="200" Fill="Transparent">
<Rectangle.Effect>
<local:NoiseEffect />
</Rectangle.Effect>
</Rectangle>
请注意我是如何将这个矩形的填充设置为“透明”的。不管它的设置是什么,你只需要将它设置为某些东西,这样像素就会真正被渲染并且你的像素着色器在它们上面 运行 。如果您将 属性 留空,那么您将看不到任何内容。
结果:
我注意到您链接到的图像上的“点”大于 1 个像素;要实现该效果,只需缩放专门用于呈现背景的 GUI 对象,并使用 LayoutTransform 或 RenderTransform 将其放大。或者,在使用它们计算索引之前调整传递到着色器的 uv 值。
我正在尝试使用与此颜色相似的背景 image。此处使用的颜色是#2E2E2E、#2C2C2C 和#2D2D2D,它们被拼凑在一起形成上面弹出窗口的颜色。
如果我没记错的话你需要渐变
您可以使用以下代码
<Grid>
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0" />
<GradientStop Color="White" Offset="1" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
平铺图像是最简单的方法,但您也可以使用像素着色器。
有很多关于如何编写 WPF 像素着色器的教程,Anu Viswan's series 是一个很好的起点。首先,您需要确保 fxc.exe 编译器已安装在您的 PC 上,如果尚未安装(在我的机器上,它位于 C:\Program Files (x86)\Windows Kits\bin.0.19041.0\x64).
接下来您需要编写着色器本身。 Whosebug 用户 appas has a neat trick showing how to do it using the UV coordinates passed in for each pixel 首先,您需要为每个像素生成一个随机数。有了它,将它转换成一个整数并用它来索引你的颜色的查找table。
// NoiseEffect.hlsl
#define NUM_COLORS 3
static float4 lut[NUM_COLORS] = {
float4(1, 0, 0, 1), // red
float4(0, 1, 0, 1), // green
float4(0, 0, 1, 1) // blue
};
float rand(float2 co) {
return frac(sin(dot(co, float2(12.9898, 78.233))) * 43758.5453);
}
float4 main(float2 uv : TEXCOORD) : COLOR{
return lut[(int)floor(rand(uv) * NUM_COLORS)];
}
我在这里使用原色来使效果更明显,要使用您的原始值,您需要将每个组件转换为 0-1 范围:
static float4 lut[NUM_COLORS] = {
float4(0x2e / 255.0f, 0x2e / 255.0f, 0x2e / 255.0f, 1),
float4(0x2c / 255.0f, 0x2c / 255.0f, 0x2c / 255.0f, 1),
float4(0x2d / 255.0f, 0x2d / 255.0f, 0x2d / 255.0f, 1)
};
接下来,运行 fxc 将您的着色器编译成 ps 文件:
fxc.exe /T ps_2_0 /E main /Fo NoiseEffect.ps NoiseEffect.hlsl
将其添加到您的项目中,将其构建操作设置为 Resource,并创建着色器效果 class 以加载它(确保更改 URI 以匹配您的项目名称):
public class NoiseEffect : ShaderEffect
{
public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(NoiseEffect), 0);
public Brush Input
{
get => ((Brush)(GetValue(InputProperty)));
set => SetValue(InputProperty, value);
}
public NoiseEffect()
{
PixelShader pixelShader = new PixelShader();
pixelShader.UriSource = new Uri("pack://application:,,,/YourProjectName;component/NoiseEffect.ps", UriKind.Absolute);
PixelShader = pixelShader;
UpdateShaderValue(InputProperty);
}
}
然后您可以将它用作 XAML 中任何地方的效果,例如:
<Rectangle Width="200" Height="200" Fill="Transparent">
<Rectangle.Effect>
<local:NoiseEffect />
</Rectangle.Effect>
</Rectangle>
请注意我是如何将这个矩形的填充设置为“透明”的。不管它的设置是什么,你只需要将它设置为某些东西,这样像素就会真正被渲染并且你的像素着色器在它们上面 运行 。如果您将 属性 留空,那么您将看不到任何内容。
结果:
我注意到您链接到的图像上的“点”大于 1 个像素;要实现该效果,只需缩放专门用于呈现背景的 GUI 对象,并使用 LayoutTransform 或 RenderTransform 将其放大。或者,在使用它们计算索引之前调整传递到着色器的 uv 值。