استفاده از XNA در اپلیکیشن های WPF
خلاصه
نحوه استفاده از چارچوب XNA در برنامه های WPF را توضیح می دهد.
محیط عملیاتی
پیش نیازها
نسخه های XNA پشتیبانی شده |
|
پلتفرم های پشتیبانی شده |
|
نسخه Vertex Shader مورد نیاز ویندوز | 1.1 |
ویندوز نسخه Pixel Shader مورد نیاز است | 1.1 |
محیط عملیاتی
بستر |
ماده
برای رندر کردن روی یک کنترل خاص با استفاده از DirectX، باید دسته پنجره را برای آن کنترل دریافت کنید. با این حال، برخلاف کنترل های Windows Form، کنترل های WPF دستگیره پنجره ندارند (در WPF آنها به سادگی کنترل را "ترسیم" می کنند).
با این حال، WPF کنترلی به نام "WindowsFormsHost" را ارائه می دهد که به شما امکان می دهد از کنترل های Windows Forms استفاده کنید.
در این مقاله، نمونه ای از ترسیم یک چند ضلعی را همانطور که در بالا نشان داده شده است، ایجاد می کنیم، اما جزئیات خود XNA را حذف می کنم زیرا توضیح آن بسیار طولانی است. من فقط در مورد رابطه بین WPF و XNA صحبت می کنم.
ابتدا یک پنجره WPF را باز کنید (در این مورد، Window1.xaml) و یک کنترل WindowsFormHost را از نوار ابزار قرار دهید. نوار لغزنده سمت راست یک امتیاز است.
من واقعا باید کمی بیشتر روی XAML کار کنم، اما آن را به بعد می گذارم زیرا ابتدا باید کنترل ها را برای استفاده از XNA ایجاد کنم.
یک "Windows Forms" "کنترل سفارشی" را به پروژه خود اضافه کنید. نام GraphicsDeviceControl را ترک کنید.
فراموش نکنید که از قبل مرجع "Microsoft.Xna.Framework" را اضافه کنید. "Microsoft.Xna.Framework.Game" نیز وجود دارد، اما این در یک پروژه فقط بازی استفاده می شود، بنابراین نیازی به گنجاندن آن نیست.
برای کوتاه نگه داشتن کد نمونه، تمام برنامه های مرتبط با XNA در GraphicsDeviceControl.cs خلاصه می شوند. این یک سبک نوشتاری بسیار متنوع نیست، بنابراین لطفا آن را اعمال کنید و آن را بازنویسی کنید.
کد کامل GraphicsDeviceControl در زیر نشان داده شده است (به جز قسمت طراح). اگر تا به حال از XNA استفاده کرده باشید، می دانید که هیچ کار غیرعادی انجام نمی دهد. من از یک مؤلفه تایمر استفاده می کنم تا چند ضلعی همیشه در حال چرخش باشد.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace XNAOnWPF
{
<summary>
グラフィックデバイスコントロール
</summary>
public partial class GraphicsDeviceControl : Control
{
<summary>
グラフィックデバイス
</summary>
private GraphicsDevice device = null;
<summary>
エフェクト
</summary>
private BasicEffect effect = null;
<summary>
頂点データ
</summary>
private VertexPositionColor[] vertices = new VertexPositionColor[3];
<summary>
頂点データ
</summary>
public VertexPositionColor[] Vertices
{
get { return this.vertices; }
}
<summary>
コンストラクタ
</summary>
public GraphicsDeviceControl()
{
InitializeComponent();
}
<summary>
コントロールが作成されるとき
</summary>
protected override void OnCreateControl()
{
if (this.DesignMode == false)
{
try
{
// デバイス作成
PresentationParameters pp = new PresentationParameters();
pp.SwapEffect = SwapEffect.Discard;
pp.BackBufferWidth = 300;
pp.BackBufferHeight = 300;
pp.EnableAutoDepthStencil = true;
pp.AutoDepthStencilFormat = DepthFormat.Depth16;
this.device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
DeviceType.Hardware, this.Handle, pp);
// 頂点データの設定
this.vertices[0] = new VertexPositionColor(
new Vector3(0.0f, -2.0f + (float)Math.Sqrt(3) * 3.0f, 0.0f),
new Microsoft.Xna.Framework.Graphics.Color(255, 0, 0));
this.vertices[1] = new VertexPositionColor(
new Vector3(3.0f, -2.0f, 0.0f),
new Microsoft.Xna.Framework.Graphics.Color(0, 255, 0));
this.vertices[2] = new VertexPositionColor(
new Vector3(-3.0f, -2.0f, 0.0f),
new Microsoft.Xna.Framework.Graphics.Color(0, 0, 255));
// 頂点定義
this.device.VertexDeclaration =
new VertexDeclaration(this.device, VertexPositionColor.VertexElements);
// エフェクト
this.effect = new BasicEffect(this.device, null);
this.effect.VertexColorEnabled = true;
// ビュー変換行列を設定
this.effect.View = Matrix.CreateLookAt(
new Vector3(0.0f, 0.0f, -10.0f),
new Vector3(0.0f, 0.0f, 0.0f),
Vector3.Up);
// 射影変換を設定
this.effect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45.0f), 1.0f, 1.0f, 100.0f);
// レンダリングステート設定
this.device.RenderState.CullMode = CullMode.None;
this.device.RenderState.AlphaBlendEnable = true;
this.device.RenderState.SourceBlend = Blend.SourceAlpha;
this.device.RenderState.DestinationBlend = Blend.InverseSourceAlpha;
}
catch (Exception ex)
{
Trace.WriteLine(ex.ToString());
}
}
base.OnCreateControl();
}
<summary>
使用中のリソースをすべてクリーンアップします。
</summary>
<param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
if (disposing)
{
if (this.device != null)
{
this.device.Dispose();
}
}
base.Dispose(disposing);
}
<summary>
描画イベント
</summary>
<param name="pe"></param>
protected override void OnPaint(PaintEventArgs pe)
{
this.Draw();
base.OnPaint(pe);
}
<summary>
描画
</summary>
private void Draw()
{
if (this.device == null)
{
return;
}
this.device.Clear(Microsoft.Xna.Framework.Graphics.Color.DarkBlue);
// ポリゴンを描画する
this.effect.Begin();
this.effect.Techniques[0].Passes[0].Begin();
this.effect.World = Matrix.CreateRotationY((float)Environment.TickCount / 1000.0f);
this.device.DrawUserPrimitives<VertexPositionColor>(
PrimitiveType.TriangleList, vertices, 0, 1);
this.effect.Techniques[0].Passes[0].End();
this.effect.End();
this.device.Present();
}
<summary>
タイマーイベント
</summary>
<param name="sender"></param>
<param name="e"></param>
private void timer_Tick(object sender, EventArgs e)
{
this.Draw();
}
}
}
اکنون که کنترل را ایجاد کرده اید، بیایید به XAML نگاه کنیم. از آنجایی که می خواهیم کنترلی را که ایجاد کرده ایم قرار دهیم، یک فضای نام به تگ ریشه اضافه می کنیم. در اینجا به عنوان "xw" تعریف می شود.
<Window x:Class="ManagedDirectXOnWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPFウインドウ上でManaged DirectXを使用してポリゴン描画"
Height="338" Width="422"
xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
xmlns:xw="clr-namespace:ManagedDirectXOnWPF">
<!-- 省略 -->
</Window>
در مرحله بعد، تگ کنترل WindowsFormsHost را که به تازگی قرار داده اید گسترش دهید و یک GraphicsDeviceControl اضافه کنید، همانطور که در زیر نشان داده شده است.
<my:WindowsFormsHost Name="windowsFormsHostManagedDirectX" Width="300" Height="300"
HorizontalAlignment="Left" VerticalAlignment="Top">
<xw:GraphicsDeviceControl x:Name="GraphicsDeviceControl" />
</my:WindowsFormsHost>
لازم نیست "x:Name" داشته باشید، اما نمونه از آن برای دسترسی به داده های راس با یک نوار لغزنده استفاده می کند.
اگر این کار را انجام دهید، می توانید صحنه ای را در WPF اجرا کنید که در آن چند ضلعی ها با یک چند ضلعی چرخان ترسیم می شوند، همانطور که در نمونه نشان داده شده است. دسترسی از طریق نوار لغزنده یک امتیاز است، بنابراین لطفا داده های نمونه را دانلود کرده و بررسی کنید.
این برنامه به .NET Framework 3.0، آخرین زمان اجرا DirectX و Microsoft XNA Framework Redistributable 2.0 نیاز دارد. علاوه بر این، به عنوان یک نیاز سخت افزاری، "یک کارت گرافیک که از Pixel Shader 1.1 یا بالاتر پشتیبانی می کند" مورد نیاز است.
علاوه بر این، این پروژه در "Visual Studio 2008 Professional Edition" ایجاد شده است. یک محیط برای ویژوال استودیو 2008 آماده کنید.