Verwenden von XNA in WPF-Anwendungen
Zusammenfassung
Beschreibt, wie das XNA-Framework in WPF-Anwendungen verwendet wird.
Betriebsumgebung
Voraussetzungen
Unterstützte XNA-Versionen |
|
Unterstützte Plattformen |
|
Erforderliche Vertex-Shader-Version für Windows | 1.1 |
Erforderliche Pixel-Shader-Version für Windows | 1.1 |
Betriebsumgebung
Bahnsteig |
Substanz
Wenn Sie für ein bestimmtes Steuerelement mit DirectX rendern möchten, müssen Sie das Fensterhandle für dieses Steuerelement abrufen. Im Gegensatz zu Windows Form-Steuerelementen verfügen WPF-Steuerelemente jedoch nicht über Fensterziehpunkte (in WPF wird das Steuerelement einfach "gezeichnet").
WPF stellt jedoch ein Steuerelement mit dem Namen "WindowsFormsHost" bereit, mit dem Sie Windows Forms-Steuerelemente verwenden können.
In diesem Artikel werden wir ein Beispiel für das Zeichnen eines Polygons erstellen, während es wie oben gezeigt gedreht wird, aber ich werde die Details von XNA selbst weglassen, da es zu lang wäre, es zu erklären. Ich werde nur über die Beziehung zwischen WPF und XNA sprechen.
Öffnen Sie zunächst ein WPF-Fenster (in diesem Fall Window1.xaml), und platzieren Sie ein WindowsFormHost-Steuerelement über die Symbolleiste. Der Schieberegler auf der rechten Seite ist ein Bonus.
Ich muss wirklich noch ein wenig an XAML arbeiten, aber ich hebe es mir für später auf, da ich zuerst die Steuerelemente erstellen muss, um XNA zu verwenden.
Fügen Sie Ihrem Projekt ein "Windows Forms" "Benutzerdefiniertes Steuerelement" hinzu. Behalten Sie den Namen GraphicsDeviceControl bei.
Vergessen Sie nicht, vorher die Referenz "Microsoft.Xna.Framework" hinzuzufügen. Es gibt auch "Microsoft.Xna.Framework.Game", aber dies wird in einem reinen Spielprojekt verwendet, sodass es nicht einbezogen werden muss.
Um den Beispielcode kurz zu halten, werden alle XNA-bezogenen Programme in GraphicsDeviceControl.cs zusammengefasst. Es ist kein sehr vielseitiger Schreibstil, also wenden Sie ihn bitte an und schreiben Sie ihn neu.
Der vollständige Code für das GraphicsDeviceControl ist unten dargestellt (mit Ausnahme des Designerteils). Wenn Sie jemals XNA verwendet haben, wissen Sie, dass es nichts Außergewöhnliches tut. Ich verwende eine Timer-Komponente, um das Polygon so aussehen zu lassen, als würde es sich ständig drehen.
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();
}
}
}
Nachdem Sie das Steuerelement erstellt haben, sehen wir uns den XAML an. Da wir das von uns erstellte Steuerelement platzieren werden, fügen wir dem Stammtag einen Namespace hinzu. Hier wird es als "xw" definiert.
<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>
Erweitern Sie als Nächstes das Tag für das WindowsFormsHost-Steuerelement, das Sie gerade platziert haben, und fügen Sie ein GraphicsDeviceControl hinzu, wie unten gezeigt.
<my:WindowsFormsHost Name="windowsFormsHostManagedDirectX" Width="300" Height="300"
HorizontalAlignment="Left" VerticalAlignment="Top">
<xw:GraphicsDeviceControl x:Name="GraphicsDeviceControl" />
</my:WindowsFormsHost>
Sie müssen nicht über einen "x:Name" verfügen, aber im Beispiel wird er verwendet, um mit einem Schieberegler auf Vertexdaten zuzugreifen.
Auf diese Weise können Sie eine Szene in WPF ausführen, in der Polygone mit einem rotierenden Polygon gezeichnet werden, wie im Beispiel gezeigt. Der Zugriff per Schieberegler ist ein Bonus, also laden Sie bitte die Beispieldaten herunter und überprüfen Sie sie.
Das Programm erfordert .NET Framework 3.0, die neueste DirectX-Runtime und Microsoft XNA Framework Redistributable 2.0. Darüber hinaus ist als Hardwarevoraussetzung "eine Grafikkarte erforderlich, die Pixel Shader 1.1 oder höher unterstützt".
Darüber hinaus wurde das Projekt in "Visual Studio 2008 Professional Edition" erstellt. Bereiten Sie eine Umgebung für Visual Studio 2008 vor.