Textblock不实现笔画属性,而是一个密封类。这方面最常见的工作是从FrameworkElement创建自己的文本块类。然而,我最近偶然发现了DropShadowEffect,并想知道是否可以使用自定义效果来实现相同的概要文本结果,而无需实现整个概要文本块。(我想要一个DropShadow给我的更清晰的轮廓。)
为此,我尝试创建一个从效果继承的类,但立即遇到了问题:
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?
}
//...
}它确实在文档里说过
从effect类派生来实现自定义位图效果。在大多数情况下,您将从ShaderEffect派生
所以我假设这是可能的。那么,您是如何从效应中派生出来的?
发布于 2019-07-02 14:11:59
您必须从ShaderEffect继承而不是效果。下面是一个概述文本的示例,使用边缘检测过滤器效果:
结合这个着色教程和Prewitt边缘检测滤波器,我成功地在文本周围获得了一个不错的轮廓效果。有其他方法可以获得类似的效果,比如创建自己的大纲文本块,但是使用效果具有使用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命令提示符中编译了它:
/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)));https://stackoverflow.com/questions/56799059
复制相似问题