イメージフィルタのぼかしフィルタの応用で、摺りガラス(曇りガラス)効果を実現する方法を紹介します。
摺りガラス Version 1
摺りガラス効果は、背景をぼかしつつ、半透明の白色を重ねることで実現できます。以下のコードは、その基本的な実装例です。
// 摺りガラス風エフェクトの描画領域
SKRect rect = new SKRect( 100, 50, 500, 250 );
// ぼかし用ペイント
using var paintFrostedGlassBlur = new SKPaint {
Style = SKPaintStyle.Fill,
ImageFilter = SKImageFilter.CreateBlur( 4, 4 ) // ぼかし半径=4
};
// 透明白色ペイント
using var paintFrostedGlassColor = new SKPaint {
Style = SKPaintStyle.Fill,
Color = new SKColor( 255, 255, 255, 32 ) // R=255, G=255, B=255, A=32
};
// 状態を保存
canvas.Save();
// クリッピング設定
canvas.ClipRect( rect );
// ぼかし描画(キャンバスに結びついているサーフェスをぼかして描画)
canvas.DrawSurface( canvas.Surface, 0, 0, paintFrostedGlassBlur );
// 透明白色描画
canvas.DrawRect( rect, paintFrostedGlassColor );
// 状態を復元
canvas.Restore();
実行すると、以下のように、摺りガラス効果が適用された矩形が描画されます。
摺りガラス Version 2
更に、ドロップシャドウを追加して、よりリアルな摺りガラス効果を実現します。
ドロップシャドウを描画するには、クリッピング領域を反転させて、矩形の外側にだけドロップシャドウを描画するようにします。
以下のコードを、Version 1のコードの後に追加してください。
// ドロップシャドウペイント
using var paintDropShadow = new SKPaint {
Style = SKPaintStyle.Fill,
ImageFilter = SKImageFilter.CreateDropShadow(
2, 2, // 影のオフセット
4, 4, // 影のぼかし半径
new SKColor( 0, 0, 0, 100 ) // 影の色(R=0, G=0, B=0, A=100)
)
};
// 状態を保存
canvas.Save();
// クリッピング設定(反転)
canvas.ClipRect( rect, SKClipOperation.Difference );
// ドロップシャドウ描画
canvas.DrawRect( rect, paintDropShadow );
// 状態を復元
canvas.Restore();
実行すると、以下のように、ドロップシャドウが追加された摺りガラス効果が適用された矩形が描画されます。
摺りガラス Version 3
更に、表面のザラザラした粒子感を追加して、よりリアルな摺りガラス効果を実現します。
粒子感を追加するには、フラクタルノイズを元にしたシェーダーを記述し、透明度を調整して重ね描きします。
// 摺りガラス風エフェクトの描画領域
SKRect rect = new SKRect( 100, 50, 500, 250 );
// ぼかし用ペイント
using var paintFrostedGlassBlur = new SKPaint {
Style = SKPaintStyle.Fill,
ImageFilter = SKImageFilter.CreateBlur( 4, 4 )
};
// ノイズ付き透明白色シェーダーのSKSLコード
string skslFrostedGlassNoise = @"
uniform shader noiseShader; // 元ノイズシェーダー
const half kAmp = 0.7; // 振幅
const half kOffset = 0.1; // オフセット
const half kAlpha = 0.25; // アルファ
half4 main(float2 coord) {
// ノイズシェーダーから値を取得して強さを調整
float intensity = noiseShader.eval( coord ).r;
intensity = clamp( intensity * kAmp + ( 1 + kOffset - kAmp ), 0.0, 1.0 );
// ノイズ付き透明白色を返す(事前乗算形式)
return half4( intensity, intensity, intensity, 1 ) * kAlpha;
}
";
// ノイズ付き透明白色シェーダーのためのランタイムエフェクト
var effectFrostedGlassNoise = SKRuntimeEffect.CreateShader( skslFrostedGlassNoise, out var _ );
// ユニフォーム設定
using var uniforms = new SKRuntimeEffectUniforms( effectFrostedGlassNoise );
// 子シェーダー設定
using var children = new SKRuntimeEffectChildren( effectFrostedGlassNoise );
using var perlinNoise = SKShader.CreatePerlinNoiseFractalNoise( 0.7f, 0.7f, 4, 0 );
children[ "noiseShader" ] = perlinNoise; // ノイズシェーダー"noiseShader"
// シェーダー生成
using var shaderFrostedGlassNoise = effectFrostedGlassNoise.ToShader( uniforms, children );
// ノイズ付き透明白色ペイント
using var paintFrostedGlassColor = new SKPaint {
Style = SKPaintStyle.Fill,
Shader = shaderFrostedGlassNoise,
Color = SKColors.White
};
// 状態を保存
canvas.Save();
// クリッピング設定
canvas.ClipRect( rect );
// ぼかし描画
canvas.DrawSurface( canvas.Surface, 0, 0, paintFrostedGlassBlur );
// 状態を復元
canvas.Restore();
// 透明白色描画
canvas.DrawRect( rect, paintFrostedGlassColor );
// ドロップシャドウペイント
using var paintDropShadow = new SKPaint {
Style = SKPaintStyle.Fill,
ImageFilter = SKImageFilter.CreateDropShadow(
2, 2, // 影のオフセット
4, 4, // 影のぼかし半径
new SKColor( 0, 0, 0, 100 ) // 影の色(R=0, G=0, B=0, A=100)
)
};
// 状態を保存
canvas.Save();
// クリッピング設定(反転)
canvas.ClipRect( rect, SKClipOperation.Difference );
// ドロップシャドウ描画
canvas.DrawRect( rect, paintDropShadow );
// 状態を復元
canvas.Restore();
実行すると、以下のように、粒子感が追加された摺りガラス効果が適用された矩形が描画されます。
ところで・・・
ところで、何故どの実装例も、ぼかしフィルタを適用するときにDrawRectではなくて、クリッピングしてDrawSurfaceを使っているのか?と思われるかもしれません。
これは、Skiaのぼかしフィルタは、描画図形の外側を参照できないためです。要するに、DrawRectを使うと、縁のぼかしが不完全になってしまうのです。
まとめ
摺りガラス効果は、ぼかしフィルタと透明色の重ね描き、ドロップシャドウ、ノイズシェーダーを組み合わせることで実現できます。凝れば凝るほどリアルな摺りガラス表現を描画できますが、パフォーマンスに注意しながら応用しましょう。
総合目次


