Menggunakan XNA dalam Aplikasi WPF

Halaman Diperbarui :
Tanggal pembuatan halaman :

ringkasan

Menjelaskan cara menggunakan Kerangka Kerja XNA dalam aplikasi WPF.

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

Lingkungan operasi

Prasyarat

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

Lingkungan operasi

balei-balei

zat

Untuk merender kontrol tertentu menggunakan DirectX, Anda perlu mendapatkan pegangan jendela untuk kontrol tersebut. Namun, tidak seperti kontrol Windows Form, kontrol WPF tidak memiliki gagang jendela (di WPF mereka hanya "menggambar" kontrol).

Namun, WPF menyediakan kontrol yang disebut "WindowsFormsHost" yang memungkinkan Anda menggunakan kontrol Windows Formulir.

Pada artikel ini, kita akan membuat contoh menggambar poligon saat diputar seperti yang ditunjukkan di atas, tetapi saya akan menghilangkan detail XNA itu sendiri karena akan terlalu lama untuk menjelaskannya. Saya hanya akan berbicara tentang hubungan antara WPF dan XNA.

Pertama, buka jendela WPF (dalam hal ini, Window1.xaml) dan tempatkan kontrol WindowsFormHost dari toolbar. Penggeser di sebelah kanan adalah bonus.

WPF ウインドウデザイン

Saya benar-benar perlu melakukan sedikit lebih banyak pekerjaan pada XAML, tetapi saya akan membiarkannya untuk nanti karena saya harus membuat kontrol untuk menggunakan XNA terlebih dahulu.

Tambahkan "Windows Forms" "Kontrol Kustom" ke proyek Anda. Biarkan nama GraphicsDeviceControl.

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

Jangan lupa untuk menambahkan referensi "Microsoft.Xna.Framework" sebelumnya. Ada juga "Microsoft.Xna.Framework.Game", tetapi ini digunakan dalam proyek khusus game, jadi tidak perlu memasukkannya.

Managed DirectX の参照

Agar kode sampel tetap singkat, semua program terkait XNA dirangkum dalam GraphicsDeviceControl.cs. Ini bukan gaya penulisan yang sangat serbaguna, jadi silakan terapkan dan tulis ulang.

Kode lengkap untuk GraphicsDeviceControl ditunjukkan di bawah ini (kecuali untuk bagian desainer). Jika Anda pernah menggunakan XNA, Anda akan tahu bahwa itu tidak melakukan sesuatu yang luar biasa. Saya menggunakan komponen Timer untuk membuat poligon tampak berputar sepanjang waktu.

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 setelah Anda membuat kontrol, mari kita lihat XAML. Karena kita akan menempatkan kontrol yang kita buat, kita akan menambahkan namespace ke tag root. Di sini, didefinisikan 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>

Selanjutnya, perluas tag untuk kontrol WindowsFormsHost yang baru saja Anda tempatkan, dan tambahkan GraphicsDeviceControl, seperti yang ditunjukkan di bawah ini.

<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 harus memiliki "x:Name", tetapi sampel menggunakannya untuk mengakses data simpul dengan penggeser.

Jika Anda melakukan ini, Anda dapat menjalankan adegan di WPF di mana poligon digambar dengan poligon yang berputar, seperti yang ditunjukkan dalam sampel. Akses dengan slider adalah bonus, jadi silakan unduh data sampel dan periksa.

Program ini memerlukan .NET Framework 3.0, runtime DirectX terbaru, dan Microsoft XNA Framework Redistributable 2.0. Selain itu, sebagai persyaratan perangkat keras, diperlukan "kartu grafis yang mendukung Pixel Shader 1.1 atau lebih tinggi".

Selain itu, proyek ini dibuat di "Visual Studio 2008 Professional Edition". Siapkan lingkungan untuk Visual Studio 2008.