Использование XNA в приложениях WPF

Страница обновлена :
Дата создания страницы :

сводка

Описывает, как использовать платформу XNA в приложениях WPF.

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

Операционная среда

Необходимые условия

Поддерживаемые версии XNA
  • 2.0
  • 3.0
Поддерживаемые платформы
  • Windows (XP SP2 или более поздняя версия, Vista)
Windows Требуемая версия вершинного шейдера 1.1
Требуемая версия пиксельного шейдера Windows 1.1

Операционная среда

платформа

вещество

Чтобы отобразить определенный элемент управления с помощью DirectX, необходимо получить дескриптор окна для этого элемента управления. Однако, в отличие от элементов управления Windows Form, элементы управления WPF не имеют оконных дескрипторов (в WPF они просто «рисуют» элемент управления).

Тем не менее, WPF предоставляет элемент управления под названием "WindowsFormsHost", который позволяет использовать элементы управления Windows Forms.

В этой статье мы создадим пример рисования многоугольника при его вращении, как показано выше, но я опущу детали самого XNA, потому что это было бы слишком длинно, чтобы объяснить это. Я просто расскажу о взаимоотношениях между WPF и XNA.

Сначала откройте окно WPF (в данном случае Window1.xaml) и разместите элемент управления WindowsFormHost с панели инструментов. Ползунок справа — это бонус.

WPF ウインドウデザイン

Мне действительно нужно немного поработать над XAML, но я оставлю это на потом, потому что сначала мне нужно создать элементы управления для использования XNA.

Добавьте в проект "Windows Forms" "Custom Control". Оставьте имя GraphicsDeviceControl.

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

Не забудьте заранее добавить ссылку на "Microsoft.Xna.Framework". Существует также "Microsoft.Xna.Framework.Game", но он используется в проекте, предназначенном только для игр, поэтому нет необходимости включать его.

Managed DirectX の参照

Чтобы сделать пример кода кратким, все программы, связанные с XNA, обобщены в GraphicsDeviceControl.cs. Это не очень универсальный стиль письма, поэтому, пожалуйста, примените его и перепишите.

Полный код для GraphicsDeviceControl показан ниже (за исключением дизайнерской части). Если вы когда-либо использовали XNA, вы знаете, что он не делает ничего необычного. Я использую компонент Timer, чтобы создать впечатление, что полигон постоянно вращается.

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

Теперь, когда вы создали элемент управления, давайте рассмотрим XAML. Поскольку мы собираемся разместить созданный нами элемент управления, мы добавим пространство имен к корневому тегу. Здесь он определяется как «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>

Затем разверните тег для только что размещенного элемента управления WindowsFormsHost и добавьте элемент управления GraphicsDeviceControl, как показано ниже.

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

Вам не обязательно иметь "x:Name", но в примере он используется для доступа к данным вершин с помощью ползунка.

Если вы это сделаете, вы можете запустить сцену в WPF, где многоугольники рисуются с вращающимся многоугольником, как показано в примере. Доступ по слайдеру является бонусом, поэтому, пожалуйста, скачайте образец данных и проверьте его.

Для работы программы требуется .NET Framework 3.0, новейшая среда выполнения DirectX и распространяемый компонент Microsoft XNA Framework Redistributable 2.0. Кроме того, в качестве требования к оборудованию требуется «видеокарта, поддерживающая пиксельные шейдеры 1.1 или выше».

Кроме того, проект был создан в "Visual Studio 2008 Professional Edition". Подготовка среды для Visual Studio 2008.