Utilizzo di XNA nelle applicazioni WPF

Pagina aggiornata :
Data di creazione della pagina :

sommario

Viene descritto come utilizzare XNA Framework nelle applicazioni WPF.

WPF アプリケーションで XNA を使用する

Ambiente operativo

Prerequisiti

Versioni XNA supportate
  • 2.0
  • 3.0
Piattaforme supportate
  • Windows (XP SP2 o successivo, Vista)
Versione Vertex Shader richiesta da Windows 1.1
Versione Pixel Shader richiesta da Windows 1.1

Ambiente operativo

piattaforma

sostanza

Per eseguire il rendering su un determinato controllo utilizzando DirectX, è necessario ottenere l'handle della finestra per tale controllo. Tuttavia, a differenza dei controlli Windows Form, i controlli WPF non dispongono di handle di finestra (in WPF semplicemente "disegnano" il controllo).

Tuttavia, WPF fornisce un controllo denominato "WindowsFormsHost" che consente di utilizzare i controlli Windows Form.

In questo articolo, creeremo un esempio di disegno di un poligono mentre viene ruotato come mostrato sopra, ma ometterò i dettagli di XNA stesso perché sarebbe troppo lungo spiegarlo. Parlerò solo della relazione tra WPF e XNA.

Innanzitutto, apri una finestra WPF (in questo caso, Window1.xaml) e posiziona un controllo WindowsFormHost dalla barra degli strumenti. Il cursore a destra è un bonus.

WPF ウインドウデザイン

Ho davvero bisogno di fare un po' più di lavoro su XAML, ma lo lascerò per dopo perché devo creare prima i controlli per utilizzare XNA.

Aggiungi un "Controllo personalizzato" "Windows Forms" al tuo progetto. Lasciare il nome GraphicsDeviceControl.

Windows Forms のカスタムコントロールを追加

Non dimenticare di aggiungere in anticipo il riferimento a "Microsoft.Xna.Framework". C'è anche "Microsoft.Xna.Framework.Game", ma questo viene utilizzato in un progetto di solo gioco, quindi non è necessario includerlo.

Managed DirectX の参照

Per ridurre la brevità del codice di esempio, tutti i programmi correlati a XNA sono riepilogati in GraphicsDeviceControl.cs. Non è uno stile di scrittura molto versatile, quindi per favore applicalo e riscrivilo.

Di seguito è riportato il codice completo per GraphicsDeviceControl (ad eccezione della parte della finestra di progettazione). Se hai mai usato XNA, saprai che non fa nulla di straordinario. Sto usando un componente Timer per far sembrare che il poligono ruoti continuamente.

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();
        }
    }
}

Ora che hai creato il controllo, esaminiamo il codice XAML. Poiché stiamo per posizionare il controllo che abbiamo creato, aggiungeremo uno spazio dei nomi al tag radice. Qui è definito come "xw".

<Window&nbsp;x:Class="ManagedDirectXOnWPF.Window1"
&nbsp;&nbsp;&nbsp;&nbsp;xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
&nbsp;&nbsp;&nbsp;&nbsp;xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
&nbsp;&nbsp;&nbsp;&nbsp;Title="WPFウインドウ上でManaged DirectXを使用してポリゴン描画"
&nbsp;&nbsp;&nbsp;&nbsp;Height="338"&nbsp;Width="422"
&nbsp;&nbsp;&nbsp;&nbsp;xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
&nbsp;&nbsp;&nbsp;&nbsp;xmlns:xw="clr-namespace:ManagedDirectXOnWPF">
    <!-- 省略 -->
</Window>

Quindi, espandere il tag per il controllo WindowsFormsHost appena inserito e aggiungere un oggetto GraphicsDeviceControl, come illustrato di seguito.

<my:WindowsFormsHost&nbsp;Name="windowsFormsHostManagedDirectX"&nbsp;Width="300"&nbsp;Height="300"
                    HorizontalAlignment="Left"&nbsp;VerticalAlignment="Top">
  <xw:GraphicsDeviceControl&nbsp;x:Name="GraphicsDeviceControl"&nbsp;/>
</my:WindowsFormsHost>

Non è necessario disporre di un "x:Name", ma l'esempio lo utilizza per accedere ai dati dei vertici con un dispositivo di scorrimento.

In questo caso, è possibile eseguire una scena in WPF in cui i poligoni vengono disegnati con un poligono rotante, come illustrato nell'esempio. L'accesso tramite dispositivo di scorrimento è un vantaggio, quindi scarica i dati di esempio e controllali.

Il programma richiede .NET Framework 3.0, l'ultimo runtime DirectX e Microsoft XNA Framework Redistributable 2.0. Inoltre, come requisito hardware, è necessaria "una scheda grafica che supporti Pixel Shader 1.1 o superiore".

Inoltre, il progetto è stato creato in "Visual Studio 2008 Professional Edition". Preparare un ambiente per Visual Studio 2008.