如何使背景具有来自一组给定颜色的混乱颜色?

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 值。