Ús de XNA en aplicacions WPF
resum
Descriu com utilitzar el marc XNA a les aplicacions WPF.
Entorn operatiu
Prerequisits
Versions XNA compatibles |
|
Plataformes compatibles |
|
Versió del shader de vèrtex necessària per al Windows | 1.1 |
Versió de Pixel Shader necessària per a Windows | 1.1 |
Entorn operatiu
plataforma |
substància
Per renderitzar en un control concret mitjançant DirectX, heu d'obtenir l'identificador de la finestra per a aquest control. Tanmateix, a diferència dels controls Windows Form, els controls WPF no tenen identificadors de finestra (en WPF simplement "dibuixen" el control).
Tanmateix, WPF proporciona un control anomenat "WindowsFormsHost" que us permet utilitzar controls de Windows Forms.
En aquest article, crearem una mostra de dibuix d'un polígon a mesura que es gira com es mostra anteriorment, però ometindré els detalls de XNA perquè seria massa llarg explicar-ho. Només parlaré de la relació entre WPF i XNA.
Primer, obriu una finestra WPF (en aquest cas, Window1.xaml) i col·loqueu un control WindowsFormHost des de la barra d'eines. El control lliscant de la dreta és un avantatge.
Realment necessito fer una mica més de treball en el XAML, però ho deixaré per més endavant perquè primer he de crear els controls per utilitzar XNA.
Afegiu un "Control personalitzat" de "Windows Forms" al vostre projecte. Deixeu el nom GraphicsDeviceControl.
No oblideu afegir prèviament la referència "Microsoft.Xna.Framework". També hi ha "Microsoft.Xna.Framework.Game", però s'utilitza en un projecte només de jocs, de manera que no cal incloure'l.
Per mantenir el codi d'exemple curt, tots els programes relacionats amb XNA es resumeixen en GraphicsDeviceControl.cs. No és un estil d'escriptura molt versàtil, així que si us plau, apliqueu-lo i reescriviu-lo.
El codi complet per a GraphicsDeviceControl es mostra a continuació (excepte la part del dissenyador). Si alguna vegada heu utilitzat XNA, sabreu que no fa res fora del normal. Estic utilitzant un component Temporitzador per fer que el polígon sembli girar tot el temps.
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();
}
}
}
Ara que heu creat el control, vegem el XAML. Com que col·locarem el control que hem creat, afegirem un espai de noms a l'etiqueta arrel. Aquí, es defineix com a "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>
A continuació, expandiu l'etiqueta del control WindowsFormsHost que acabeu de col·locar i afegiu un GraphicsDeviceControl, tal com es mostra a continuació.
<my:WindowsFormsHost Name="windowsFormsHostManagedDirectX" Width="300" Height="300"
HorizontalAlignment="Left" VerticalAlignment="Top">
<xw:GraphicsDeviceControl x:Name="GraphicsDeviceControl" />
</my:WindowsFormsHost>
No cal que tingueu una "x:Name", però l'exemple l'utilitza per accedir a les dades de vèrtex amb un control lliscant.
Si feu això, podeu executar una escena al WPF on els polígons es dibuixen amb un polígon giratori, tal com es mostra a l'exemple. L'accés per control lliscant és un avantatge, així que descarregueu les dades de mostra i comproveu-les.
El programa requereix el .NET Framework 3.0, l'últim temps d'execució de DirectX i el Microsoft XNA Framework Redistributable 2.0. A més, com a requisit de maquinari, es requereix "una targeta gràfica que admeti Pixel Shader 1.1 o superior".
A més, el projecte es va crear a "Visual Studio 2008 Professional Edition". Prepareu un entorn per al Visual Studio 2008.