上次的描边着色器有两个问题,导致效果不太理想。现在我们来设法改进这两点。
问题一:
当TextBlock的呈现宽度和高度没有正确赋值时,将无法正确计算像素宽度。 但是,像素宽度其实根本不需要传进去, ShaderEffect 类有一个DdxUvDdyUvRegisterIndex 属性。此属性的msdn是这么解释的:
使用 DdxUvDdyUvRegisterIndex 属性指定包含纹理坐标对屏幕空间的偏导数的着色器寄存器。 例如,如果将 DdxUvDdyUvRegisterIndex 设置为 4,则使用着色器寄存器 c4。 寄存器 c4 包含四个浮点字段。下面的高级着色语言 (HLSL) 代码演示如何使用此寄存器。nextPixelUV 值表示右边的下一个像素。
float4 ddxUvDdyUv : register(c4);
SamplerState sampler : register(S0);
...float2 nextPixelUV;
nextPixelUV.u = ddxUvDdyUv.x + u;
nextPixelUV.v = ddxUvDdyUv.y + v;
tex2D(sampler, nextPixelUV);
因此,我们压根就不需要传入什么宽度高度!
问题二:
字体的半透明像素问题。由于字体的反锯齿,这些半透明像素是肯定会出现的。但是我们可以设想,我们的描边字体其实可以想象成是叠加在边框上的普通字体,那么这些半透明像素应该怎么办?当然是应该和边框颜色进行半透明混合啦!故此,改动着色器代码,现在无论TextBolck里的内容如何变化,都可以正确的描边了。
最后特别推荐:汉字使用宋体字,在12,13号等大小下,出现透明像素最少。英文和数字的宋体效果非常一般,建议换其他字体如Arial等。可以自己在下面输入任意文字,查看描边效果。
着色器代码:
1 sampler2D input : register(s0);
2
4
5
6
7 float4 fontcolor:register(C0);
8
9 float4 bordercolor:register(C1);
10
11 float4 ddxUvDdyUv : register(c2);
12
13
14 float4 main(float2 uv : TEXCOORD) : COLOR
15 {
16
17
18 float4 Color;
19 Color= tex2D( input , uv.xy);
20
21
22 float ix = length(ddxUvDdyUv.rg);
23 float iy = length(ddxUvDdyUv.ba);
24
25 int i;
26
27
28
29 {
30 if( Color.a==0 )
31 {
32 float4 c2;
33 c2= tex2D( input, uv.xy +float2 (0,iy) );
34
35 if( c2.a>0 )
36 {
37 Color= bordercolor;
38 return Color;
39 }
40 else
41 {
42 c2= tex2D( input, uv.xy +float2 (0,-iy) );
43 if( c2.a>0 )
44 {
45 Color=bordercolor;;
46 return Color;
47 }
48 else
49 {
50 c2= tex2D( input, uv.xy +float2 (ix,0) );
51 if( c2.a>0 )
52 {
53 Color=bordercolor;
54 return Color;
55 }
56 else
57 {
58 c2= tex2D( input, uv.xy +float2 (-ix,0) );
59 if( c2.a>0 )
60 {
61 Color=bordercolor;
62 return Color;
63 }
64 }
65 }
66 }
67 }
68 else
69 {
70
71 float aa=1-Color.a;
72
73 float4 tempcolor= float4( ( fontcolor * Color.a + float4( bordercolor.rgb,Color.a)* aa )) ;
74
75
76 Color=tempcolor;
77 }
78 }
79
80
81
82 return Color;
83 }