Menggunakan XNA dalam Aplikasi WPF

Laman dikemaskini :
Tarikh penciptaan halaman :

Ringkasan

Menerangkan cara menggunakan Rangka Kerja XNA dalam aplikasi WPF.

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

Persekitaran operasi

Prasyarat

Versi XNA yang Disokong
  • 2.0
  • 3.0
Platform yang Disokong
  • Windows (XP SP2 atau lebih baru, Vista)
Versi Vertex Shader yang Diperlukan Windows 1.1
Windows Versi Pixel Shader Diperlukan 1.1

Persekitaran operasi

Platform

Bahan

Untuk memaparkan pada kawalan tertentu menggunakan DirectX, anda perlu mendapatkan pemegang tetingkap untuk kawalan tersebut. Walau bagaimanapun, tidak seperti kawalan Windows Form, kawalan WPF tidak mempunyai pemegang tetingkap (dalam WPF mereka hanya "melukis" kawalan).

Walau bagaimanapun, WPF menyediakan kawalan yang dipanggil "WindowsFormsHost" yang membolehkan anda menggunakan kawalan Windows Forms.

Dalam artikel ini, kami akan mencipta contoh lukisan poligon semasa ia diputar seperti yang ditunjukkan di atas, tetapi saya akan meninggalkan butiran XNA itu sendiri kerana ia terlalu panjang untuk menerangkannya. Saya hanya akan bercakap tentang hubungan antara WPF dan XNA.

Mula-mula, buka tetingkap WPF (dalam kes ini, Window1.xaml) dan letakkan kawalan WindowsFormHost daripada bar alat. Peluncur di sebelah kanan ialah bonus.

WPF ウインドウデザイン

Saya benar-benar perlu melakukan sedikit lagi kerja pada XAML, tetapi saya akan membiarkannya untuk kemudian kerana saya perlu membuat kawalan untuk menggunakan XNA terlebih dahulu.

Tambahkan "Borang Windows" "Kawalan Tersuai" pada projek anda. Tinggalkan nama GraphicsDeviceControl.

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

Jangan lupa untuk menambah rujukan "Microsoft.Xna.Framework" terlebih dahulu. Terdapat juga "Microsoft.Xna.Framework.Game", tetapi ini digunakan dalam projek permainan sahaja, jadi tidak perlu memasukkannya.

Managed DirectX の参照

Untuk memastikan kod sampel pendek, semua program berkaitan XNA diringkaskan dalam GraphicsDeviceControl.cs. Ia bukan gaya penulisan yang sangat serba boleh, jadi sila gunakan dan tulis semula.

Kod penuh untuk GraphicsDeviceControl ditunjukkan di bawah (kecuali bahagian pereka). Jika anda pernah menggunakan XNA, anda akan tahu bahawa ia tidak melakukan apa-apa yang luar biasa. Saya menggunakan komponen Pemasa untuk menjadikan poligon kelihatan berputar sepanjang masa.

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

Sekarang anda telah mencipta kawalan, mari lihat XAML. Oleh kerana kita akan meletakkan kawalan yang kita buat, kita akan menambah ruang nama pada tag akar. Di sini, ia ditakrifkan sebagai "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>

Seterusnya, kembangkan tag untuk kawalan WindowsFormsHost yang baru anda letakkan, dan tambah GraphicsDeviceControl, seperti yang ditunjukkan di bawah.

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

Anda tidak perlu mempunyai "x:Name", tetapi sampel menggunakannya untuk mengakses data bucu dengan gelangsar.

Jika anda melakukan ini, anda boleh menjalankan adegan pada WPF di mana poligon dilukis dengan poligon berputar, seperti yang ditunjukkan dalam sampel. Akses melalui peluncur adalah bonus, jadi sila muat turun data sampel dan semaknya.

Program ini memerlukan .NET Framework 3.0, masa jalan DirectX terkini dan Microsoft XNA Framework Redistributable 2.0. Di samping itu, sebagai keperluan perkakasan, "kad grafik yang menyokong Pixel Shader 1.1 atau lebih tinggi" diperlukan.

Di samping itu, projek itu dicipta dalam "Visual Studio 2008 Professional Edition". Sediakan persekitaran untuk Visual Studio 2008.