שימוש ב-XNA ביישומי WPF

עודכן דף :
תאריך יצירת דף :

תקציר

מתאר כיצד להשתמש ב-XNA Framework ביישומי WPF.

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

סביבת הפעלה

דרישות מוקדמות

גרסאות XNA נתמכות
  • 2.0
  • 3.0
פלטפורמות נתמכות
  • Windows (XP SP2 ואילך, Vista)
Windows נדרש Vertex Shader גירסה 1.1
גירסת Pixel Shader נדרשת של Windows 1.1

סביבת הפעלה

פלטפורמה

חומר

כדי לעבד פקד מסוים באמצעות DirectX, עליך לקבל את נקודת האחיזה של החלון עבור פקד זה. עם זאת, בניגוד לפקדי טופס של Windows, לפקדי WPF אין נקודות אחיזה לחלונות (ב- WPF הם פשוט "מציירים "את הפקד").

עם זאת, WPF מספק פקד בשם "WindowsFormsHost" המאפשר לך להשתמש בפקדי Windows Forms.

במאמר זה, ניצור דוגמה של ציור מצולע כפי שהוא מסובב כפי שמוצג לעיל, אבל אני אשמיט את הפרטים של XNA עצמו כי זה יהיה ארוך מדי להסביר את זה. אני רק אדבר על הקשר בין WPF ו-XNA.

תחילה, פתח חלון WPF (במקרה זה, Window1.xaml) ומקם פקד WindowsFormHost מסרגל הכלים. המחוון מימין הוא בונוס.

WPF ウインドウデザイン

אני באמת צריך לעשות קצת יותר עבודה על XAML, אבל אני אשאיר את זה מאוחר יותר כי אני צריך ליצור את הפקדים כדי להשתמש XNA הראשון.

הוסף "Windows Forms" "פקד מותאם אישית" לפרוייקט שלך. השאר את השם GraphicsDeviceControl.

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

אל תשכח להוסיף את ההפניה "Microsoft.Xna.Framework" מראש. יש גם "Microsoft.Xna.Framework.Game", אבל זה משמש בפרויקט משחק בלבד, ולכן אין צורך לכלול אותו.

Managed DirectX の参照

כדי לשמור על קוד לדוגמה קצר, כל התוכניות הקשורות ל- XNA מסוכמות ב- GraphicsDeviceControl.cs. זה לא סגנון כתיבה מאוד תכליתי, אז בבקשה ליישם אותו ולשכתב אותו.

הקוד המלא עבור GraphicsDeviceControl מוצג להלן (למעט החלק המעצב). אם אי פעם השתמשתם ב-XNA, תדעו שהוא לא עושה שום דבר יוצא דופן. אני משתמש ברכיב טיימר כדי לגרום למצולע להיראות כאילו הוא מסתובב כל הזמן.

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. בנוסף, כדרישת חומרה, נדרש "כרטיס גרפי התומך ב- Pixel Shader 1.1 ואילך".

בנוסף, הפרויקט נוצר ב- "Visual Studio 2008 Professional Edition". הכן סביבה עבור Visual Studio 2008.