WPF 응용프로그램에서 XNA 사용

페이지 업데이트 :
페이지 생성 날짜 :

요약

WPF 응용프로그램에서 XNA Framework를 사용하는 방법에 대해 설명합니다.

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

운영 환경

필수 구성 요소

지원되는 XNA 버전
  • 2.0
  • 3.0
지원되는 플랫폼
  • Windows(XP SP2 이상, Vista)
Windows 필수 버텍스 셰이더 버전 1.1
Windows 필수 픽셀 셰이더 버전 1.1

운영 환경

플랫폼

물질

DirectX를 사용하여 특정 컨트롤에서 렌더링하려면 해당 컨트롤에 대한 창 핸들을 가져와야 합니다. 그러나 Windows Form 컨트롤과 달리 WPF 컨트롤에는 창 핸들이 없으며 WPF에서는 단순히 컨트롤을 "그리기"만 합니다.

그러나 WPF는 Windows Forms 컨트롤을 사용할 수 있도록 하는 "WindowsFormsHost"라는 컨트롤을 제공합니다.

이 기사에서는 위와 같이 다각형이 회전할 때 그리는 샘플을 만들지만 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를 사용해 본 적이 있다면 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 재배포 가능 패키지 2.0이 필요합니다. 또, 하드웨어 요구 사항으로서 「Pixel Shader 1.1 이상을 지원하는 그래픽 카드」가 필요합니다.

또한 프로젝트는 "Visual Studio 2008 Professional Edition"에서 생성되었습니다. Visual Studio 2008을 위한 환경을 준비합니다.