How to derived from the Effect class

bwall

Textblock does not implement the stroke property, and is a sealed class. The most common work-around for this is to create your own textblock class from FrameworkElement. However, I've recently stumbled across the DropShadowEffect, and wondered if it was possible to use a custom effect to achieve the same outlined text result without the work of implementing the entire outlined text block. (I want a crisper outline that DropShadow will give me.)

To that end, I tried creating a class inheriting from Effect, but immediately ran into problems:

namespace MyNamespace;

public class OutlineEffect : Effect
{
    internal override Channel GetChannelCore(int index)
    {
        //How am I supposed to override an internal class in a Microsoft namespace?
    }

    //...
}

It does say in the documentation:

Derive from the Effect class to implement a custom bitmap effect. In most cases, you will derive from ShaderEffect

so I would assume this is possible. So, How do you derive from Effect?

bwall

You have to inherit from ShaderEffect instead of Effect. Here's an example for outlining text use an edge-detection filter effect:

Combining this Shader tutorial and the Prewitt Edge Detection Filter I managed to get a decent outline effect around text. There are other ways to get a similar effect, like creating your own outline text block, but using an effect has the advantage of rendering using the GPU, and applying generically to any UIElement. However, I had to play a lot with the EdgeResponse property to get a nice outline.

The end result in 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>

To create the effect, I first created the EdgeDetectionColorEffect.fx (hdld) file - this is the code the GPU uses to filter the image. I compiled it in Visual Studio Command Prompt with the command:

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;
}

Here's the wpf effect class:

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)));

Este artículo se recopila de Internet, indique la fuente cuando se vuelva a imprimir.

En caso de infracción, por favor [email protected] Eliminar

Editado en
0

Déjame decir algunas palabras

0Comentarios
Iniciar sesiónRevisión de participación posterior

Artículos relacionados

How to obtain the derived class type from base when calling a method

How to get the name of a derived class from a vector of base classes

How to prevent a template class from being derived more than once?

How to derive a class that is already derived from Halide::Generator?

class B derived from an abstract base class A, and how can i use singleton in class B?

template class derived from `const` specialized version

Accessing private member from derived class

How does GetType() knows the type of a derived class?

How to seperate definition and implementation of a derived class constructor?

CRTP refer to typedef in derived class from base class

How to properly copy fields from derived classes?

How to retrieve derived classes as is from a Map?

Get Derived DTO From Base Class Request Body DTO

Resolve Services derived from base class using DryIoc

TypeError on pickle.load with class derived from SimpleNamespace

How to Implement Interface with Enum Specific to Derived Class in C#?

How to tell which derived class calling override base method

How can I do constructor overloading in a derived class in TypeScript?

How to use gmock SaveArgPointee with with std::shared_ptr of derived class

TPH - how to satisfy FK constraint when FK is on derived class?

When inheriting SQLAlchemy class from abstract class exception thrown: metaclass conflict: the metaclass of a derived class must be

Dispose Derived Class

How to call the base class constructor when the derived class can not easily pass the parameters to the base class?

Convert base class to derived class

Convert base class to derived class

Class 'Anonymous class derived from AdListener' must either be declared abstract or implement abstract method 'onLoggingImpressionMethod(Ad)'

Unexpectedly able to call derived-class virtual function from base class ctor

Why can't I use alias from a base class in a derived class with templates?

How are objects from derived classes constructed in C++

TOP Lista

CalienteEtiquetas

Archivo