HLSLでEffect
1.HLSLファイル
効果に応じて3つのFXファイルを作りました。main()は、1ピクセルごとエントリーされるようです。uvに位置がセットされます。tex2D()で指定した任意の位置の1ピクセル(色)が取得できます。この関数の戻り値がuvの位置の新たな色になります。
- Grayscale.fx
- sampler2D input : register(s0);
- float4 main(float2 uv : TEXCOORD) : COLOR
- {
- float4 pix;
- pix = tex2D(input , uv.xy);
- pix.rgb = (pix.r+pix.g+pix.b)/3.0f;
- return pix;
- }
- Laplace.fx
- float2 texSize : register(c0);
- sampler2D input : register(s0);
- float2 nextXY(float2 uv, float dx, float dy)
- {
- uv.x += dx/texSize.x;
- uv.y += dy/texSize.y;
- return uv;
- }
- float4 main(float2 uv : TEXCOORD) : COLOR
- {
- float4 sum;
- sum = tex2D(input, nextXY(uv,-1,-1))
- + tex2D(input, nextXY(uv,0,-1))
- + tex2D(input, nextXY(uv,1,-1))
- + tex2D(input, nextXY(uv,-1,0))
- + tex2D(input, nextXY(uv,1,0))
- + tex2D(input, nextXY(uv,-1,1))
- + tex2D(input, nextXY(uv,0,1))
- + tex2D(input, nextXY(uv,1,1))
- + (tex2D(input, uv.xy) * (-8.0f));
- sum.a=1;
- return sum;
- }
- WaveEffect.fx
- float2 texSize : register(c0);
- sampler2D input : register(s0);
- float4 main(float2 uv : TEXCOORD) : COLOR
- {
- float4 pix;
- uv.x += sin( //sinでゆれを作る。
- (6.283/(texSize.y/5))*(1-uv.y) //縦の1/5で1周するような角度を元にyに応じて小さくしていく。
- * ((1-uv.y)*texSize.y) ) //これにyの位置に応じた倍率を掛ける。
- * (1+uv.y)*0.03;//横の幅の3->6%を移動。
- pix = tex2D(input, uv.xy);
- return pix;
- }
2.HLSLのコンパイル
Visual Studio Expressでコンパイルする方法がわからなかったのでDOS窓で行いました。
- fxc /T ps_2_0 /E main /Fo"Grayscale.ps" "Grayscale.fx"
- fxc /T ps_2_0 /E main /Fo"Laplace.ps" "Laplace.fx"
- fxc /T ps_2_0 /E main /Fo"WaveEffect.ps" "WaveEffect.fx"
DirextX SDK のインストールディレクトリの Utilities\bin\ に fxc.exe があります。
同じ場所に dx_setenv.cmd があるので、DOS窓を開いたら最初にこれを実行しておきます。
コンパイルの結果、Grayscale.ps、Laplace.ps、WaveEffect.ps の3つの .ps ファイルができます。
3.ShaderEffectクラス
ShaderEffectクラスの派生クラスを作ります。
コンストラクタで PixelShader プロパティを設定します。
PixelShader の UriSource に .ps ファイルのパスを設定します。
- using System;
- using System.Windows;
- using System.Windows.Media.Effects;
- namespace wpf_effect1
- {
- class Grayscale : ShaderEffect
- {
- public Grayscale()
- {
- PixelShader = new PixelShader();
- string path = System.IO.Path.GetFullPath(©"..\..\Grayscale.ps");
- PixelShader.UriSource = new Uri(path);
- }
- }
- }
この例ように、単に UriSource を設定するだけなら派生クラスを作る必要はないようです。
HLSLの記述した処理に、画像のサイズなどの値を渡すためには、派生が必要です。
Laplace.fx にある texSize は、次のようにして設定してあります。
- public Size TexSize
- {
- get { return (Size)GetValue(TexSizeProperty); }
- set { SetValue(TexSizeProperty, value); }
- }
- public static readonly DependencyProperty TexSizeProperty
- = DependencyProperty.Register("TexSize", typeof(Size), typeof(Laplace),
- new UIPropertyMetadata(new Size(8, 8), PixelShaderConstantCallback(0)));
4.Effectの適用
次のようなXAMLで表示のレイアウトをしてあります。4箇所に同じ画像を割付け、原図以外には、grayscale1、laplace1、waveEffect1と名前を付けてあります。
- <Window x:Class="wpf_effect1.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="HLSL Effect">
- <Window.Resources>
- <BitmapImage x:Key="original" UriSource="BegoniaEvansiana.png"/>
- </Window.Resources>
- <Grid Loaded="Grid_Loaded">
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="324"></ColumnDefinition>
- <ColumnDefinition Width="324"></ColumnDefinition>
- </Grid.ColumnDefinitions>
- <StackPanel Grid.Column="0" Width="320">
- <TextBlock>原図</TextBlock>
- <Image Source="{StaticResource original}"/>
- <TextBlock>グレースケール</TextBlock>
- <Image x:Name="grayscale1" Source="{StaticResource original}"/>
- </StackPanel>
- <StackPanel Grid.Column="1" Width="320">
- <TextBlock>ラプラス(8方向)</TextBlock>
- <Image x:Name="laplace1" Source="{StaticResource original}"/>
- <TextBlock>波</TextBlock>
- <Image x:Name="waveEffect1" Source="{StaticResource original}"/>
- </StackPanel>
- </Grid>
- </Window>
Grid の Loaded イベントで、image の Effect プロパティをセットしました。
- private void Grid_Loaded(object sender, RoutedEventArgs e)
- {
- grayscale1.Effect = new Grayscale();
- laplace1.Effect = new Laplace(laplace1.ActualWidth, laplace1.ActualHeight);
- waveEffect1.Effect = new WaveEffect(waveEffect1.ActualWidth, waveEffect1.ActualHeight);
- }
XAML の記述でEffectを設定する場合は、ShaderEffectクラスの派生クラスを異なるアセンブリ(DLL)にすることになります。
5.その他
5.1.気が付いたこと
- 古いノートパソコンではEffectが無視された。
理由はわからない。
ハードウエアがサポートしないときはエラーでなく、単に無視されるのでは。
- Visual Studio Express内でHLSLをコンパイルする方法がわからない。
- Debug方法がわからない。
5,2.main()について
- 図形のピクセルごとにエントリされる。
- 引数で渡される座標は出力位置と考えられる。
main()の返した色がその位置に出力される。
- 座標は、図形の左上が(0,0)、右下が(1,1)になる。
5.3.HLSLについて
- 三角関数は弧度
- float2,float4 は、それぞれ2つ、4つのfloatの組
|