如何从效果类派生

时间:2019-06-27 22:18:44

标签: c# xaml protected derived-class

Textblock不实现stroke属性,而是一个密封的类。最常见的解决方法是create your own textblock class from FrameworkElement。但是,我最近偶然发现了DropShadowEffect,想知道是否可以使用自定义效果来获得相同的轮廓文本结果,而无需执行整个轮廓文本块。 (我想要DropShadow给我的清晰轮廓。)

为此,我尝试创建一个从Effect继承的类,但立即遇到问题:

string password = "\"myNewStrongPassword\"";
var encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes(password));
var attributePassword = new LdapAttribute("unicodePwd", encodedBytes);
ldapConnection.Modify(YOUR_DISTINGUISHED_NAME, new LdapModification(LdapModification.REPLACE, attributePassword));

它确实在documentation中说过:

  

从Effect类派生以实现自定义位图效果。在   大多数情况下,您将从ShaderEffect衍生

所以我认为这是可能的。因此,您如何从效果中得出

1 个答案:

答案 0 :(得分:0)

您必须继承ShaderEffect而不是Effect。这是使用边缘检测滤镜效果概述文本的示例:

结合使用此Shader tutorialPrewitt Edge Detection Filter,我设法在文本周围获得了不错的轮廓效果。还有其他获得类似效果的方法,例如creating your own outline text block,但是使用效果具有使用GPU进行渲染并通常应用于 any UIElement的优势。但是,我必须在EdgeResponse属性中进行很多工作才能获得漂亮的轮廓。

XAML的最终结果:

<Grid>
    <Grid.Resources>
        <local:EdgeDetectionEffect x:Key="OutlineEffect"
            x:Shared="false"
            EdgeResponse="4.0"
            ActualHeight="{Binding RelativeSource={RelativeSource AncestorType=TextBlock}, Path=ActualHeight}"
            ActualWidth="{Binding RelativeSource={RelativeSource AncestorType=TextBlock}, Path=ActualWidth}"/>
    </Grid.Resources>
    <TextBlock Text="The Crazy Brown Fox Jumped Over the Lazy Dog."
        FontWeight="Bold"
        Foreground="Yellow"
        Effect="{StaticResource OutlineEffect}"/>
</Grid>

要创建效果,我首先创建了EdgeDetectionColorEffect.fx(hdld)文件-这是GPU用于过滤图像的代码。我在Visual Studio命令提示符中使用以下命令对其进行了编译:

fxc / T ps_2_0 / E main /Focc.ps EdgeDetectionColorEffect.fx

sampler2D Input : register(s0);
float ActualWidth : register(c0);
float ActualHeight : register(c1);
float4 OutlineColor : register(c2);
float EdgeDetectionResponse : register(c3);

float4 GetNeighborPixel(float2 pixelPoint, float xOffset, float yOffset)
{
    float2 NeighborPoint = {pixelPoint.x + xOffset, pixelPoint.y + yOffset};
    return tex2D(Input, NeighborPoint);
}

// pixel locations:
// 00 01 02
// 10 11 12
// 20 21 22
float main(float2 pixelPoint : TEXCOORD) : COLOR
{

     float wo = 1 / ActualWidth; //WidthOffset
     float ho = 1 / ActualHeight; //HeightOffset

    float4 c00 = GetNeighborPixel(pixelPoint, -wo, -ho); // color of the pixel up and to the left of me.
    float4 c01 = GetNeighborPixel(pixelPoint,  00, -ho);        
    float4 c02 = GetNeighborPixel(pixelPoint,  wo, -ho);
    float4 c10 = GetNeighborPixel(pixelPoint, -wo,   0);
    float4 c11 = tex2D(Input, pixelPoint); // this is the current pixel
    float4 c12 = GetNeighborPixel(pixelPoint,  wo,   0);
    float4 c20 = GetNeighborPixel(pixelPoint, -wo,  ho);
    float4 c21 = GetNeighborPixel(pixelPoint,   0,  ho);
    float4 c22 = GetNeighborPixel(pixelPoint,  wo,  ho);

    float t00 = c00.r + c00.g + c00.b; //total of color channels
    float t01 = c01.r + c01.g + c01.b;
    float t02 = c02.r + c02.g + c02.b;
    float t10 = c10.r + c10.g + c10.b;
    float t11 = c11.r + c11.g + c11.b;
    float t12 = c12.r + c12.g + c12.b;
    float t20 = c20.r + c20.g + c20.b;
    float t21 = c21.r + c21.g + c21.b;
    float t22 = c22.r + c22.g + c22.b;

    //Prewitt - convolve the 9 pixels with:
    //       01 01 01        01 00 -1
    // Gy =  00 00 00   Gx = 01 00 -1
    //       -1 -1 -1        01 00 -1

    float gy = 0.0;  float gx = 0.0;
    gy += t00;       gx += t00;
    gy += t01;       gx += t10;
    gy += t02;       gx += t20;
    gy -= t20;       gx -= t02;
    gy -= t21;       gx -= t12;
    gy -= t22;       gx -= t22;

    if((gy*gy + gx*gx) > EdgeDetectionResponse)
    {
        return OutlineColor;
    }

    return c11;
}

这是wpf效果类:

public class EdgeDetectionEffect : ShaderEffect
{
    private static PixelShader _shader = new PixelShader { UriSource = new Uri("path to your compiled shader probably called cc.ps", UriKind.Absolute) };

public EdgeDetectionEffect()
{
    PixelShader = _shader;
    UpdateShaderValue(InputProperty);
    UpdateShaderValue(ActualHeightProperty);
    UpdateShaderValue(ActualWidthProperty);
    UpdateShaderValue(OutlineColorProperty);
    UpdateShaderValue(EdgeResponseProperty);
}

public Brush Input
{
     get => (Brush)GetValue(InputProperty);
     set => SetValue(InputProperty, value);
}
public static readonly DependencyProperty InputProperty = 
    ShaderEffect.RegisterPixelShaderSamplerProperty(nameof(Input), 
    typeof(EdgeDetectionEffect), 0);

public double ActualWidth
{
     get => (double)GetValue(ActualWidthProperty);
     set => SetValue(ActualWidthProperty, value);
}
public static readonly DependencyProperty ActualWidthProperty =
    DependencyProperty.Register(nameof(ActualWidth), typeof(double), typeof(EdgeDetectionEffect),
    new UIPropertyMetadata(1.0, PixelShaderConstantCallback(0)));

//notice the PixelShaderConstantCallback(#) - this tells it which GPU register to use (compare the number here to the first few lines of the EdgeDetectionColorEffect.fx file above.

public double ActualHeight
{
     get => (double)GetValue(ActualHeightProperty);
     set => SetValue(ActualHeightProperty, value);
}
public static readonly DependencyProperty ActualHeightProperty =
    DependencyProperty.Register(nameof(ActualHeight), typeof(double), typeof(EdgeDetectionEffect),
    new UIPropertyMetadata(1.0, PixelShaderConstantCallback(1)));

public Color OutlineColor
{
     get => (Color)GetValue(OutlineColorProperty);
     set => SetValue(OutlineColorProperty, value);
}
public static readonly DependencyProperty OutlineColorProperty=
    DependencyProperty.Register(nameof(OutlineColor), typeof(Color), typeof(EdgeDetectionEffect),
    new UIPropertyMetadata(Colors.Black, PixelShaderConstantCallback(2)));

public double EdgeResponse
{
     get => (double)GetValue(EdgeResponseProperty);
     set => SetValue(EdgeResponseProperty, value);
}
public static readonly DependencyProperty EdgeResponseProperty =
    DependencyProperty.Register(nameof(EdgeResponse), typeof(double), typeof(EdgeDetectionEffect),
    new UIPropertyMetadata(4.0, PixelShaderConstantCallback(3)));