エフェクトを実装する
FilterEffect はレンダーターゲットを後処理する EngineObject です。基本的な書き方は描画オブジェクトを実装と同じで、partial class で宣言し、IProperty<T> メンバを公開し、ApplyTo の中で自動生成された Resource からスナップショット値を読み取ります。
EngineObject リファレンス を読んでいない場合は先に目を通してください。プロパティシステムや Resource のライフサイクルがそこで説明されています。
1. 最小のエフェクト
using Beutl.Graphics.Effects;
using Beutl.Graphics.Rendering;
namespace MyExtension;
public sealed partial class MyFilterEffect : FilterEffect
{
public MyFilterEffect()
{
ScanProperties<MyFilterEffect>();
}
public override void ApplyTo(FilterEffectContext context, FilterEffect.Resource resource)
{
// ここで context にフィルタ操作を追加します。
}
}
Drawable との違いは 2 つ:
ApplyToはFilterEffectContextと自動生成されたResourceを受け取ります。プロパティの値を読むにはresourceを派生Resource型にキャストします。MeasureCore/OnDrawはありません。エディタがFilterEffectContextを介してレンダーターゲットを流し込んでくれるので、それをどう変換するかだけを記述します。
2. 既存のエフェクトを組み合わせる
最も簡単なカスタムエフェクトは、FilterEffectContext の拡張メソッドを使って Beutl 組み込みの操作を重ねていく方法です。境界の自動拡張(例:ブラーは表面を広げる)も内部で処理されるため、サイズ調整を自分で書く必要はほぼありません。
using System.ComponentModel.DataAnnotations;
using Beutl.Engine;
using Beutl.Graphics.Effects;
using Beutl.Graphics.Rendering;
using Beutl.Media;
namespace MyExtension;
public sealed partial class HighContrastBlur : FilterEffect
{
public HighContrastBlur()
{
ScanProperties<HighContrastBlur>();
}
[Display(Name = "Blur Sigma")]
[Range(0, float.MaxValue)]
public IProperty<float> BlurSigma { get; } = Property.CreateAnimatable<float>(20);
[Display(Name = "Contrast")]
[Range(-100, 100)]
public IProperty<float> Contrast { get; } = Property.CreateAnimatable<float>(20);
public override void ApplyTo(FilterEffectContext context, FilterEffect.Resource resource)
{
var r = (Resource)resource;
context.Blur(new Size(r.BlurSigma, r.BlurSigma));
context.HighContrast(
grayscale: false,
invertStyle: HighContrastInvertStyle.NoInvert,
contrast: r.Contrast / 100f);
}
}
FilterEffectContext には組み込み操作それぞれに対応するメソッドが用意されています:Blur、DropShadow、InnerShadow、Erode、Dilate、ColorMatrix、Saturate、HueRotate、Brightness、HighContrast、Lighting、MatrixConvolution、Transform、BlendMode など。完全なリストは FilterEffectContext.cs を参照してください。
Crop(Rect, GradientSpreadMethod = Decal) は Bounds と同じ座標系の矩形を切り出します。既定の Decal は範囲外を透明にして境界を縮めます。Pad は端の色を延長し、Repeat は繰り返し、Reflect は反転して繰り返し、元の境界を保ちます。
複数入力や複数パスのGLSL処理については、C#スクリプトも参照してください。
3. レンダーターゲットを直接処理する
メタデータコールバックの診断
コンパイラーが BESG004 を報告した場合は、メタデータコールバックと、その中から呼ぶ処理が参照している値を確認してください。変更される静的な値を直接読み取らず、明示的な状態や束縛された描画リソースを通じて渡します。
4. 拡張機能で登録する
using Beutl.Extensibility;
using Beutl.Services;
namespace MyExtension;
[Export]
public sealed class MyEffectExtension : Extension
{
public override string Name => "My Effects";
public override string DisplayName => "My Effects";
public override void Load()
{
LibraryService.Current.Register<HighContrastBlur>(
KnownLibraryItemFormats.FilterEffect,
"High-Contrast Blur");
}
}
複数のエフェクトをまとめたい場合は、EngineObject リファレンス で説明している RegisterGroup ヘルパーを使うと、ライブラリ上で 1 つのカテゴリにグルーピングできます。
Beutl ソースの参考ファイル
| ファイル | 学べること |
|---|---|
src/Beutl.Engine/Graphics/FilterEffects/HighContrast.cs | FilterEffectContext の単一呼び出しで完結する最小エフェクト。 |
src/Beutl.Engine/Graphics/FilterEffects/FlatShadow.cs | CustomEffect で独自描画を行い、transformBounds で境界を拡張する例。 |
src/Beutl.Engine/Graphics/FilterEffects/FilterEffectContext.cs | チェイン可能な組み込み操作の全リスト。 |