融合效果是指對兩個接近的元素進行高斯模糊後再提高對比度,使它們看上去「粘」在一起。在之前的一篇文章中,我使用 Win2D 實現了融合效果,效果如下:
不過 Win2D 不適用於 WPF,在 WPF 中可以使用 BlurEffect 配合自定義 Effect 實現類似的效果。HandyControl 中有一個使用自定義的 ContrastEffect 實現融合效果的 Demo,如下圖:
但是 ContrastEffect 是通過 Contrast 屬性同時控制 RGBA 四個通道的對比值,所以沒辦法控制準確地顏色。另外 HandyControl 也提供了 ColorMatrixEffect,不過 ColorMatrixEffect 很難控制對比度。
既然都用到自定義 Effect 了,這次索性自己寫一個。
在 Win2D 中,實現融合效果的步驟是先使用 GaussianBlurEffect 在兩個元素間產生粘連在一起的半透明畫素,再用 ColorMatrixEffect 加強對比對,使半透明的畫素變得完全不透明。
在 WPF 中我們可以直接使用自帶的 BlurEffect 實現高斯模糊,效果如下:
接下來需要加強對比度。WPF 中沒有 ColorMatrixEffect 的替代品,不過我們可以使用 HLSL(高階著色器語言)編寫 PixelShader 並生成自定義的 WPF Effect。編寫 PixelShader 可以使用 Shazzam Shader Editor, walterlv 有一篇關於如何使用這款編輯器的教學:
WPF 畫素著色器入門:使用 Shazzam Shader Editor 編寫 HLSL 畫素著色器程式碼
在這裡我編寫了一個對 Alpha 進行二值化處理的 PixelShader 實現加強對比度功能,它的作用很簡單:當畫素的 Alpha 大於閾值就將 Alpha 置為 1,否則為 0,程式碼如下:
float Thresh : register(C0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 color;
color = tex2D(input, uv.xy);
if (color.a == 0 || color.a == 1 || Thresh == 0)
{
return color;
}
float4 resultColor = 0;
float opacity = color.a > Thresh ? 1 : 0;
if (opacity > 0)
{
resultColor.rgb = color.rgb / color.a * opacity;
}
resultColor.a = opacity;
return resultColor;
}
雖然確實實現了融合效果,但是圓形的邊緣有嚴重的鋸齒。很明顯,問題出在上面的程式碼中 Alpha 通道最終不是 0 就是 1,為了使邊緣平滑,應該留下一些「中間派」。修改後的程式碼參照了 LowerThresh 和 UpperThresh,處於這兩個閾值之間的畫素用作保持邊緣平滑的「中間派」,具體程式碼如下:
float UpperThresh : register(C0);
float LowerThresh : register(C1);
float4 main(float2 uv : TEXCOORD) : COLOR
{
float4 color;
color = tex2D(input, uv.xy);
if (color.a == 0 || color.a == 1 || LowerThresh == 0)
{
return color;
}
if (UpperThresh < LowerThresh)
{
return color;
}
float4 resultColor = 0;
float opacity = 1;
if (color.a < LowerThresh)
{
opacity = 0;
}
if (color.a > LowerThresh && color.a < UpperThresh)
{
opacity = (color.a - LowerThresh) / (UpperThresh - LowerThresh);
}
if (opacity > 0)
{
resultColor.rgb = color.rgb / color.a * opacity;
}
resultColor.a = opacity;
return resultColor;
}
這篇文章介紹瞭如何使用自定義 Effect 實現融合效果,只要理解了融合效果的原理並動手實現了一次,之後就可以參考部落格園的 ChokCoco 大佬玩出更多花樣,例如這種效果::
更多好玩的效果可以參考 ChokCoco 大佬的部落格:你所不知道的 CSS 濾鏡技巧與細節
原始碼:https://github.com/DinoChan/wpf_design_and_animation_lab