【问题标题】:AngleGradient in WPFWPF中的角度渐变
【发布时间】:2013-12-28 10:08:11
【问题描述】:

如您所知,PhotoShop 中有一个名为 AngleGradient 的渐变选项。但是,WPF 只有LinearGradientBrushRadialGradientBrush 渐变。您知道如何使用XAML 创建AngleGradient 吗?

更新: 样品 - 来自 photoshop:

【问题讨论】:

    标签: wpf xaml gradient wpf-4.0 wpf-brushes


    【解决方案1】:

    我为此编写了一个着色器,对其进行编译并将 .ps 文件作为资源添加到您的项目中:

    // no input texture, the output is completely generated in code
    sampler2D  inputSampler : register(S0);
    /// <summary>The center of the gradient. </summary>
    /// <minValue>0,0</minValue>
    /// <maxValue>1,1</maxValue>
    /// <defaultValue>.5,.5</defaultValue>
    float2 centerPoint : register(C0);
    
    /// <summary>The primary color of the gradient. </summary>
    /// <defaultValue>Blue</defaultValue>
    float4 primaryColor : register(C1);
    
    /// <summary>The secondary color of the gradient. </summary>
    /// <defaultValue>Red</defaultValue>
    float4 secondaryColor : register(C2);
    
    float4 main(float2 uv : TEXCOORD) : COLOR
    {
        float4 src= tex2D(inputSampler, uv);
        float2 p = float2(centerPoint)-uv;
        float angle = (atan2(p.x, p.y) + 3.141596) / (2 * 3.141596);
        float3 f = lerp(primaryColor.rgb, secondaryColor.rgb, angle);
        float4 color = float4(src.a < 0.01 
                                    ? float3(0, 0, 0) // WPF uses pre-multiplied alpha everywhere internally for a number of performance reasons.
                                    : f, src.a < 0.01 ? 0 : 1);
        return color;
    }
    

    这样包装:

    public class AngularGradientEffect : ShaderEffect {
        public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty(
            "Input", 
            typeof(AngularGradientEffect),
            0);
    
        public static readonly DependencyProperty CenterPointProperty = DependencyProperty.Register(
            "CenterPoint",
            typeof(Point),
            typeof(AngularGradientEffect), 
            new UIPropertyMetadata(new Point(0.5D, 0.5D), PixelShaderConstantCallback(0)));
    
        public static readonly DependencyProperty PrimaryColorProperty = DependencyProperty.Register(
            "PrimaryColor", 
            typeof(Color), 
            typeof(AngularGradientEffect), 
            new UIPropertyMetadata(Color.FromArgb(255, 0, 0, 255), PixelShaderConstantCallback(1)));
    
        public static readonly DependencyProperty SecondaryColorProperty = DependencyProperty.Register(
            "SecondaryColor", 
            typeof(Color),
            typeof(AngularGradientEffect), 
            new UIPropertyMetadata(Color.FromArgb(255, 255, 0, 0), PixelShaderConstantCallback(2)));
    
        public AngularGradientEffect() {
            PixelShader pixelShader = new PixelShader();
            pixelShader.UriSource = new Uri("/So.Wpf;component/Effects/AngularGradientEffect.ps", UriKind.Relative);
            this.PixelShader = pixelShader;
    
            this.UpdateShaderValue(InputProperty);
            this.UpdateShaderValue(CenterPointProperty);
            this.UpdateShaderValue(PrimaryColorProperty);
            this.UpdateShaderValue(SecondaryColorProperty);
        }
        public Brush Input {
            get {
                return ((Brush)(this.GetValue(InputProperty)));
            }
            set {
                this.SetValue(InputProperty, value);
            }
        }
        /// <summary>The center of the gradient. </summary>
        public Point CenterPoint {
            get {
                return ((Point)(this.GetValue(CenterPointProperty)));
            }
            set {
                this.SetValue(CenterPointProperty, value);
            }
        }
        /// <summary>The primary color of the gradient. </summary>
        public Color PrimaryColor {
            get {
                return ((Color)(this.GetValue(PrimaryColorProperty)));
            }
            set {
                this.SetValue(PrimaryColorProperty, value);
            }
        }
        /// <summary>The secondary color of the gradient. </summary>
        public Color SecondaryColor {
            get {
                return ((Color)(this.GetValue(SecondaryColorProperty)));
            }
            set {
                this.SetValue(SecondaryColorProperty, value);
            }
        }
    }
    

    这样在Xaml中使用,效果用渐变替换所有不透明的像素,因此形状必须有颜色,任意颜色:

    <Ellipse x:Name="ShaderEllipse" Fill="Transparent" Stroke="Blue" StrokeThickness="15">
        <Ellipse.Effect>
            <effects:AngularGradientEffect PrimaryColor="Red" 
                                           SecondaryColor="Transparent"/>
        </Ellipse.Effect>
    </Ellipse>
    

    输出是:

    添加到this lib

    【讨论】:

    • +1 太棒了 :) 非常感谢。我现在有点忙;我会尽快测试它
    • 将.ps文件标记为资源,如果有问题请告诉我。它有效,但我有可能在这里写错了:D
    • @JohanLarsson:出于某种原因,这会将 Trasparent 视为 White。在您的示例图像中不容易看到,但如果您将背景设置为其他内容,您会看到此渐变是从白色到红色,而不是从透明到红色。
    【解决方案2】:

    Charles Petzold,Windows 编程的原始大师有一个简单的方法描述here。他使用了 Graphical PathsLinearGradientBrushes 的优雅组合。博客条目是为 Silverlight 编写的,但这个概念很容易转化为 WPF。他还有一个链接到他的方法的基础,该方法基于 WPF

    和往常一样,Petzold 先生(我相信他应该是爵士)提供他所有的代码。

    【讨论】:

    • +1 我会阅读文章和代码。这似乎足以实现我的目的。谢谢
    • 我猜着色器必须比许多图形路径更快。
    猜你喜欢
    • 2011-01-28
    • 2018-04-17
    • 2014-04-09
    • 1970-01-01
    • 2023-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多