Utilisation de XNA dans les applications WPF

Page mise à jour :
Date de création de la page :

résumé

Décrit l’utilisation de XNA Framework dans les applications WPF.

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

Environnement d’exploitation

Conditions préalables

Versions XNA prises en charge
  • 2.0
  • 3.0
Plates-formes prises en charge
  • Windows (XP SP2 ou version ultérieure, Vista)
Version du Vertex Shader requise par Windows 1.1
Version du Pixel Shader requise par Windows 1.1

Environnement d’exploitation

plateforme

substance

Pour effectuer le rendu d’un contrôle particulier à l’aide de DirectX, vous devez obtenir le descripteur de fenêtre pour ce contrôle. Cependant, contrairement aux contrôles Windows Form, les contrôles WPF n’ont pas de poignées de fenêtre (dans WPF, ils « dessinent » simplement le contrôle).

Toutefois, WPF fournit un contrôle appelé « WindowsFormsHost » qui vous permet d’utiliser des contrôles Windows Forms.

Dans cet article, nous allons créer un exemple de dessin d’un polygone lorsqu’il est tourné comme indiqué ci-dessus, mais j’omettrai les détails de XNA lui-même car il serait trop long de l’expliquer. Je vais juste parler de la relation entre WPF et XNA.

Tout d’abord, ouvrez une fenêtre WPF (dans ce cas, Window1.xaml) et placez un contrôle WindowsFormHost à partir de la barre d’outils. Le curseur à droite est un bonus.

WPF ウインドウデザイン

J’ai vraiment besoin de travailler un peu plus sur le XAML, mais je le laisserai pour plus tard car je dois d’abord créer les contrôles pour utiliser XNA.

Ajoutez un « Windows Forms » « Custom Control » à votre projet. Laissez le nom GraphicsDeviceControl.

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

N’oubliez pas d’ajouter au préalable la référence « Microsoft.Xna.Framework ». Il existe également « Microsoft.Xna.Framework.Game », mais il est utilisé dans un projet de jeu uniquement, il n’est donc pas nécessaire de l’inclure.

Managed DirectX の参照

Pour que l’exemple de code soit court, tous les programmes liés à XNA sont résumés dans GraphicsDeviceControl.cs. Ce n’est pas un style d’écriture très polyvalent, alors s’il vous plaît, appliquez-le et réécrivez-le.

Le code complet du GraphicsDeviceControl est illustré ci-dessous (à l’exception de la partie concepteur). Si vous avez déjà utilisé XNA, vous savez qu’il ne fait rien d’extraordinaire. J’utilise un composant Timer pour donner l’impression que le polygone tourne tout le 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();
        }
    }
}

Maintenant que vous avez créé le contrôle, examinons le code XAML. Puisque nous allons placer le contrôle que nous avons créé, nous allons ajouter un espace de noms à la balise racine. Ici, il est défini comme « 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>

Ensuite, développez la balise du contrôle WindowsFormsHost que vous venez de placer et ajoutez un GraphicsDeviceControl, comme indiqué ci-dessous.

<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>

Il n’est pas nécessaire d’avoir un « x :Name », mais l’exemple l’utilise pour accéder aux données de sommet à l’aide d’un curseur.

Si vous effectuez cette opération, vous pouvez exécuter une scène sur WPF où les polygones sont dessinés avec un polygone rotatif, comme illustré dans l’exemple. L’accès par curseur est un bonus, veuillez donc télécharger les données d’exemple et les vérifier.

Le programme nécessite le .NET Framework 3.0, le dernier runtime DirectX et le Microsoft XNA Framework Redistributable 2.0. De plus, en tant qu’exigence matérielle, « une carte graphique prenant en charge Pixel Shader 1.1 ou supérieur » est requise.

De plus, le projet a été créé dans « Visual Studio 2008 Professional Edition ». Préparez un environnement pour Visual Studio 2008.