先月、MicrosoftからSilverlightの新しいバージョンである「Silverlight 3」と開発ツールがリリースされました。Silverlight 3では、Silverlight 2の機能に加えてビットマップやメディア関連の低水準なAPIが追加され、プログラムから動的に制御できるようになりました。Silverlight 3によって、これまでWebアプリケーション分野での進出が遅れていた映像、音声、画像などのマルチメディアのオーサリングツールが登場するかもしれません。
今回は、Silverlight 3で追加された新機能の1つであるエフェクトについてご紹介します。エフェクトは、任意のUIElementに対してピクセル単位の変換処理を実行時に行うことができる機能です。Silverlight 2でも座標変換や不透明度の変更はできましたが、ビットマップのピクセルを直接制御する手段がなかったため動的な色の変換はできませんでした。例えば、写真編集ソフトウェアにあるような画像の色調整、補正、ぼかしなどの機能をエフェクトで実現できます。
Silverlightでは、エフェクトのために複雑なピクセル変換ロジックを記述する必要はありません。目的のエフェクトをプロパティに設定するだけです。エフェクトを設定するにはUIElementクラスのEffectプロパティを用います。
UIElementクラスEffectプロパティ
public Effect Effect { get; set; }
このプロパティには、描画するUIElementに加えるエフェクトを表すEffectクラスのオブジェクトを設定します。Effectクラス自身は抽象クラスであり、実際にどのような効果を付加するかについては派生クラスによって決定されます。
System.Windows.Media.Effects.Effectクラス
public abstract class Effect : DependencyObject
System.Object
System.Windows.DependencyObject
System.Windows.Media.Effects.Effect
標準で用意されているエフェクトは、ぼかし効果を加えるBlurEffectクラスと、任意の方向に影を落とすDropShadowEffectの2つのエフェクトが用意されています。任意のUIElementのEffectプロパティに対して、これらのエフェクトを設定するだけで、目的の効果がUIに追加されます。
コード01
<Canvas x:Name="LayoutRoot">
<Image Source="test.jpg" Canvas.Left="215" Canvas.Top="10" Width="400" Height="300" />
<Image Source="test.jpg" Canvas.Left="10" Canvas.Top="320" Width="400" Height="300">
<Image.Effect>
<BlurEffect Radius="10" />
</Image.Effect>
</Image>
<Image Source="test.jpg" Canvas.Left="420" Canvas.Top="320" Width="400" Height="300">
<Image.Effect>
<DropShadowEffect Color="Black" ShadowDepth="20" />
</Image.Effect>
</Image>
</Canvas>
コード01の実行結果は、同じ画像に対してぼかし効果を追加するブラー(実行結果1)と、影を落とすドロップシャドウ(実行結果2)を設定したものです。画面上が本来の画像ファイル、実行結果1・2がエフェクトをかけた状態です。これまでのHTMLやSilverlightでは、画像編集ソフトウェアでエフェクトをかけた状態の画像を事前に用意しなければなりませんでした。Silverlight 3であれば、上のコードのようにXAMLでエフェクトを設定するだけで、簡単にピクセル変換による画面効果を追加できます。フォーカスされていない要素をぼかしたり、文字が同じ色の背景に埋もれないようにドロップシャドウを使うなどの演出に応用できるでしょう。
エフェクトは、任意のUIElementに対して設定できるため、画像だけではなくコントロールや動画に対してもかけられます。例えば、再生中の動画に対して動的にぼかし効果を加えることもできます。
コード02
<Canvas x:Name="LayoutRoot">
<Button Content="Kitty on your lap" Canvas.Left="10" Canvas.Top="10" Width="200" Height="100" />
<Button Content="Kitty on your lap" Canvas.Left="220" Canvas.Top="10" Width="200" Height="100">
<Button.Effect>
<BlurEffect Radius="5" />
</Button.Effect>
</Button>
</Canvas>
コード02は、通常のボタンコントロールに対してブラーを設定した実行結果です。右側のボタンは、左のボタンと同じ設定でエフェクトを追加しています。ぼかし効果が追加されていますが、ボタンとしての機能が失われることはありません。エフェクトを持つUIElementの親にエフェクトを設定することで、異なるエフェクトを組み合わせることもできます。
カスタムエフェクトの作成
標準で用意されているエフェクトはブラーとドロップシャドウだけですが、独自のエフェクトを開発することもできます。新しくエフェクトを作成するにはShaderEffect抽象クラスを継承します。
System.Windows.Media.Effects.ShaderEffectクラス
public abstract class ShaderEffect : Effect
System.Object
System.Windows.DependencyObject
System.Windows.Media.Effects.Effect
System.Windows.Media.Effects.ShaderEffect
エフェクトによるピクセルの変換には、C#言語ではなくHLSL (High Level Shader Language) と呼ばれるGPU専用のプログラミング言語を使います。このHLSLを用いて、入力されたデータを変換してピクセルの色を返すピクセルシェーダと呼ばれる一種の関数を作成します。本連載ではGPUやHLSLについては管轄外なので、詳細はMSDNを参照してください。
コード03
sampler2D input : register(s0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
float f;
float4 color;
color = tex2D(input , uv.xy);
f = color.r * 0.299 + color.g * 0.587 * color.b * 0.114;
color.r = color.g = color.b = f;
return color;
}
上のコードがHLSLで書かれたピクセルシェーダです。これは、アプリケーションを記述するための言語ではないため、これ自体が実行可能ファイルになるわけではありません。上のピクセルシェーダをDirectX SDKに付属しているコンパイラ(fxc.exe)を用いることでシェーダのバイナリ表現が生成されます。これをSilverlightで読み込むことで、カスタムエフェクトを実現できます。
コンパイルされたピクセルシェーダを設定するにはShaderEffectクラスのPixelShaderプロパティを使います。
ShaderEffect クラス PixelShaderプロパティ
protected PixelShader PixelShader { get; set; }
このプロパティに、ピクセルシェーダを表すPixelShaderクラスのオブジェクトを設定します。
System.Windows.Media.Effects.PixelShaderクラス
public sealed class PixelShader : DependencyObject
System.Object
System.Windows.DependencyObject
System.Windows.Media.Effects.PixelShader
DirectX SDでコンパイルしたピクセルシェーダのバイナリファイルは、このクラスのUriSourceプロパティに設定します。
PixelShaderクラス UriSourceプロパティ
public Uri UriSource { get; set; }
このプロパティに、ピクセルシェーダのURIを設定します。適切にピクセルシェーダが読み込まれれば、エフェクトに設定されているPixelShaderオブジェクトによってUIElementで描画されるピクセルが変換されます。ピクセルシェーダを記述することで、色合いやコントラストなどの補正、歪みやノイズなどの効果を加えるといった演出を自由にプログラムできます。
コード04
public class TestEffect : ShaderEffect
{
public TestEffect()
{
Uri uri = new Uri(@"/SilverlightApplication1;component/TestShader.ps", UriKind.Relative);
PixelShader pixelShader = new PixelShader();
pixelShader.UriSource = uri;
PixelShader = pixelShader;
}
}
コード04の実行結果は、コード03のピクセルシェーダを設定したTestEffectというShaderEffectクラスから派生する新しいエフェクトを画像に設定したものです。左が本来の画像、右がエフェクトを設定した状態です。このピクセルシェーダでは、ピクセルの色をグレースケールに変換して結果を返しています。TestEffectクラスの内部では、事前にコンパイルしたピクセルシェーダ(TestShader.ps)を読み込み、自分自身のPixelShaderプロパティに設定しています。
このようにSilverlight 3で導入されたエフェクトを用いることで、これまでは事前にビットマップで用意しなければならなかった特殊効果をプログラムから設定できるようになります。デザイナの負担を軽減できると同時に、容易にエフェクトの組み合わせやエフェクトに関連するパラメータを変更しながらデザインを試せます。
著者プロフィール:赤坂玲音
フリーランスのテクニカルライタ兼アプリケーション開発者。主にクライアント技術、プレゼンテーション技術が専門。2005年から現在まで「Microsoft MVP Visual C++」受賞。技術解説書を中心に著書多数。近著に『Silverlight入門』(翔泳社)などがある。