Używanie XNA w aplikacjach WPF
streszczenie
Opisuje sposób używania struktury XNA w aplikacjach WPF.
Środowisko pracy
Warunki wstępne
Obsługiwane wersje XNA |
|
Obsługiwane platformy |
|
Wymagana wersja cieniowania wierzchołków systemu Windows | 1.1 |
Wymagana wersja Pixel Shader w systemie Windows | 1.1 |
Środowisko pracy
podest |
substancja
Aby renderować określoną kontrolkę przy użyciu programu DirectX, musisz uzyskać uchwyt okna dla tej kontrolki. Jednak w przeciwieństwie do kontrolek Windows Form, kontrolki WPF nie mają uchwytów okien (w WPF po prostu "rysują" kontrolkę).
Jednak WPF udostępnia kontrolkę o nazwie "WindowsFormsHost", która umożliwia korzystanie z kontrolek Windows Forms.
W tym artykule stworzymy próbkę rysowania wielokąta podczas jego obracania, jak pokazano powyżej, ale pominę szczegóły samego XNA, ponieważ byłoby to zbyt długie, aby je wyjaśnić. Opowiem tylko o związku między WPF i XNA.
Najpierw otwórz okno WPF (w tym przypadku Window1.xaml) i umieść kontrolkę WindowsFormHost na pasku narzędzi. Suwak po prawej stronie to bonus.
Naprawdę muszę trochę popracować nad kodem XAML, ale zostawię to na później, ponieważ najpierw muszę utworzyć kontrolki do korzystania z XNA.
Dodaj "Formularze systemu Windows" "Kontrolka niestandardowa" do swojego projektu. Pozostaw nazwę GraphicsDeviceControl.
Nie zapomnij wcześniej dodać odwołania "Microsoft.Xna.Framework". Istnieje również "Microsoft.Xna.Framework.Game", ale jest on używany w projekcie tylko do gry, więc nie ma potrzeby dołączania go.
Aby przykładowy kod był krótki, wszystkie programy związane z XNA są podsumowane w GraphicsDeviceControl.cs. Nie jest to zbyt uniwersalny styl pisania, więc zastosuj go i przepisz.
Pełny kod elementu GraphicsDeviceControl jest pokazany poniżej (z wyjątkiem części projektanta). Jeśli kiedykolwiek korzystałeś z XNA, wiesz, że nie robi on nic niezwykłego. Używam komponentu Timer, aby wielokąt wydawał się obracać przez cały czas.
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();
}
}
}
Teraz, po utworzeniu kontrolki, przyjrzyjmy się kodowi XAML. Ponieważ zamierzamy umieścić utworzoną przez nas kontrolkę, dodamy przestrzeń nazw do tagu głównego. Tutaj jest zdefiniowany jako "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>
Następnie rozwiń tag kontrolki WindowsFormsHost, która została właśnie umieszczona, i dodaj kontrolkę GraphicsDeviceControl, jak pokazano poniżej.
<my:WindowsFormsHost Name="windowsFormsHostManagedDirectX" Width="300" Height="300"
HorizontalAlignment="Left" VerticalAlignment="Top">
<xw:GraphicsDeviceControl x:Name="GraphicsDeviceControl" />
</my:WindowsFormsHost>
Nie musisz mieć wartości "x:Name", ale przykład używa jej do uzyskiwania dostępu do danych wierzchołków za pomocą suwaka.
Jeśli to zrobisz, możesz uruchomić scenę w WPF, w której wielokąty są rysowane z obracającym się wielokątem, jak pokazano w przykładzie. Dostęp za pomocą suwaka jest dodatkowym atutem, dlatego prosimy o pobranie przykładowych danych i sprawdzenie ich.
Program wymaga .NET Framework 3.0, najnowszego środowiska uruchomieniowego DirectX oraz pakietu redystrybucyjnego Microsoft XNA Framework 2.0. Ponadto jako wymóg sprzętowy wymagana jest "karta graficzna obsługująca Pixel Shader 1.1 lub nowszy".
Dodatkowo projekt powstał w programie "Visual Studio 2008 Professional Edition". Przygotowanie środowiska dla programu Visual Studio 2008.