「VCS/WpfMandelbrot」の編集履歴(バックアップ)一覧に戻る

VCS/WpfMandelbrot - (2014/06/01 (日) 20:49:14) のソース

|開発環境|Microsoft Visual Studio Express 2013 for Windows Desktop|
|実行環境|Microsoft Windows 8.1 (64bit)|
|プロジェクトの種類|Visual C#/WPF アプリケーション|
|プロジェクト名|WpfMandelbrot|
#table_zebra(project, #fff, #eee)

参考
-[[Mandelbrot Set with PixelShader in WPF - CodeProject>http://www.codeproject.com/Articles/226547/Mandelbrot-Set-with-PixelShader-in-WPF]]

以下のファイルをプロジェクトに追加する。
|Mandelbrot.cs|クラス||
|Mandelbrot.fx|既存の項目|ビルド アクション:なし|
|Mandelbrot.ps|既存の項目|ビルド アクション:Resource|

MainWindow.xaml
#highlight(xml){{
<Window x:Class="WpfMandelbrot.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfMandelbrot"
        Title="MainWindow" Height="500" Width="500">
    <Grid Background="LightBlue">
        <Grid.Effect>
            <local:Mandelbrot x:Name="Mandelbrot" />
        </Grid.Effect>
    </Grid>
</Window>
}}

MainWindow.xaml.cs
#highlight(c#){{
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Media3D;
using System.Windows.Threading;

namespace WpfMandelbrot
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private DispatcherTimer intervalTimer = new DispatcherTimer();
        private Point3D pos = new Point3D(0, 0, 1);

        public MainWindow()
        {
            InitializeComponent();

            intervalTimer.Interval = TimeSpan.FromMilliseconds(30);
            intervalTimer.Tick += intervalTimer_Tick;
            intervalTimer.Start();
        }

        private void intervalTimer_Tick(object sender, EventArgs e)
        {
            if (Keyboard.IsKeyDown(Key.Escape)) Application.Current.Shutdown();
            if (Keyboard.IsKeyDown(Key.Up)) pos.Y -= pos.Z * 0.01;
            if (Keyboard.IsKeyDown(Key.Down)) pos.Y += pos.Z * 0.01;
            if (Keyboard.IsKeyDown(Key.Left)) pos.X -= pos.Z * 0.01;
            if (Keyboard.IsKeyDown(Key.Right)) pos.X += pos.Z * 0.01;
            if (Keyboard.IsKeyDown(Key.PageUp)) pos.Z *= 0.99;
            if (Keyboard.IsKeyDown(Key.PageDown)) pos.Z *= 1.01;
            Mandelbrot.Center = pos;
            Mandelbrot.Aspect = ActualHeight / ActualWidth;
            Title = string.Format("WpfMandelbrot ({0:f6},{1:f6}) {2:f6}", pos.X, pos.Y, pos.Z);
        }
    }
}
}}

Mandelbrot.cs
#highlight(c#){{
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Media.Effects;
using System.Windows.Media.Media3D;

namespace WpfMandelbrot
{
    public class Mandelbrot : ShaderEffect
    {
        private static PixelShader _pixelShader =
            new PixelShader() { UriSource = new Uri(@"Mandelbrot.ps", UriKind.RelativeOrAbsolute) };

        public Mandelbrot()
        {
            PixelShader = _pixelShader;

            UpdateShaderValue(CenterProperty);
            UpdateShaderValue(AspectProperty);
        }

        //----------------------------------------------------------------------
        public Point3D Center
        {
            get { return (Point3D)GetValue(CenterProperty); }
            set { SetValue(CenterProperty, value); }
        }

        public static readonly DependencyProperty CenterProperty =
            DependencyProperty.Register("Center", typeof(Point3D), typeof(Mandelbrot),
            new UIPropertyMetadata(new Point3D(0, 0, 1), PixelShaderConstantCallback(0)));

        //----------------------------------------------------------------------
        public double Aspect
        {
            get { return (double)GetValue(AspectProperty); }
            set { SetValue(AspectProperty, value); }
        }

        public static readonly DependencyProperty AspectProperty =
            DependencyProperty.Register("Aspect", typeof(double), typeof(Mandelbrot),
            new UIPropertyMetadata(1.0, PixelShaderConstantCallback(1)));
    }
}
}}

Mandelbrot.fx
#highlight(fx){{
float4 center : register(c0);
float aspect : register(c1);

float4 main(float2 uv : TEXCOORD) : COLOR
{
	const int MaxIterate = 254;

	const float2 c = (uv - 0.5) * float2(1.0, aspect) * center.z + center.xy;

	float2 p = 0;
	int n;
	for (n = 0; n < MaxIterate && dot(p, p) < 4.0; n++) {
		p = float2(p.x * p.x - p.y * p.y, 2.0 * p.x * p.y) + c;
	}

	float4 color;
	if (n < MaxIterate) {
		float u = (float)n / (float)MaxIterate;
		color.rgb = float3(u, u, 1.0 - u);
	}
	else {
		color.rgb = 0.0;
	}
	color.a = 1.0;
	return color;
}
}}

プロジェクトのプロパティ
ビルド イベント/ビルド前に実行するコマンド ライン
#highlight(bat){{
"C:\Program Files (x86)\Windows Kits\8.1\bin\x86\fxc.exe"^
 /T ps_3_0 /Fo $(ProjectDir)Mandelbrot.ps $(ProjectDir)Mandelbrot.fx
}}