Uso de XNA en aplicaciones de WPF

Actualización de la página :
Fecha de creación de la página :

resumen

Describe cómo usar XNA Framework en aplicaciones WPF.

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

Entorno operativo

Prerrequisitos

Versiones de XNA compatibles
  • 2.0
  • 3.0
Plataformas compatibles
  • Windows (XP SP2 o posterior, Vista)
Versión requerida del sombreador de vértices de Windows 1.1
Versión de Pixel Shader requerida para Windows 1.1

Entorno operativo

plataforma

sustancia

Para representar en un control determinado mediante DirectX, debe obtener el identificador de ventana para ese control. Sin embargo, a diferencia de los controles de Windows Forms, los controles de WPF no tienen identificadores de ventana (en WPF simplemente "dibujan" el control).

Sin embargo, WPF proporciona un control denominado "WindowsFormsHost" que permite usar controles de Windows Forms.

En este artículo, crearemos una muestra de cómo dibujar un polígono a medida que se gira como se muestra arriba, pero omitiré los detalles de XNA en sí porque sería demasiado largo explicarlo. Solo hablaré sobre la relación entre WPF y XNA.

En primer lugar, abra una ventana de WPF (en este caso, Window1.xaml) y coloque un control WindowsFormHost en la barra de herramientas. El control deslizante de la derecha es una ventaja.

WPF ウインドウデザイン

Realmente necesito trabajar un poco más en el XAML, pero lo dejaré para más adelante porque primero tengo que crear los controles para usar XNA.

Agregue un "Control personalizado" de "Windows Forms" a su proyecto. Deje el nombre GraphicsDeviceControl.

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

No olvide agregar la referencia "Microsoft.Xna.Framework" de antemano. También existe "Microsoft.Xna.Framework.Game", pero se usa en un proyecto de solo juego, por lo que no es necesario incluirlo.

Managed DirectX の参照

Para que el código de ejemplo sea breve, todos los programas relacionados con XNA se resumen en GraphicsDeviceControl.cs. No es un estilo de escritura muy versátil, así que aplícalo y reescríbelo.

A continuación se muestra el código completo de GraphicsDeviceControl (excepto la parte del diseñador). Si alguna vez has usado XNA, sabrás que no hace nada fuera de lo común. Estoy usando un componente Temporizador para hacer que parezca que el polígono gira todo el tiempo.

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

Ahora que ha creado el control, echemos un vistazo al XAML. Como vamos a colocar el control que creamos, agregaremos un espacio de nombres a la etiqueta raíz. Aquí, se define como "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>

A continuación, expanda la etiqueta del control WindowsFormsHost que acaba de colocar y agregue un GraphicsDeviceControl, como se muestra a continuación.

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

No es necesario que tenga un "x:Name", pero el ejemplo lo usa para acceder a los datos de vértice con un control deslizante.

Si lo hace, puede ejecutar una escena en WPF en la que los polígonos se dibujen con un polígono giratorio, como se muestra en el ejemplo. El acceso por control deslizante es una ventaja, así que descargue los datos de muestra y compruébelos.

El programa requiere .NET Framework 3.0, el último tiempo de ejecución de DirectX y Microsoft XNA Framework Redistributable 2.0. Además, como requisito de hardware, se requiere "una tarjeta gráfica que admita Pixel Shader 1.1 o superior".

Además, el proyecto fue creado en "Visual Studio 2008 Professional Edition". Prepare un entorno para Visual Studio 2008.