オノデラの研究日記 in わんくま

思いついたネタを気ままに書いていくブログ

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  209  : 記事  5  : コメント  5971  : トラックバック  40

ニュース

プロフィール

  • ●おのでら
    宮城県在住
    主に業務向けソフトを製作

Twitter

ニュース

主なリンク

XNA 関連リンク

アイテム

ゲーマーカード

その他

記事カテゴリ

書庫

日記カテゴリ

 DirectX を使用して特定のコントロール上にレンダリングを行うには、そのコントロールのウインドウハンドルを取得する必要があります。しかし、WPF のコントロールは Windows Form のコントロールと違い、ウインドウハンドルというものがありません(WPF では単にコントロールを「描画」しているだけに過ぎません)。

 しかし、WPF には「WindowsFormsHost」というコントロールがあり、これを使うことによって Windows Form コントロールを使用することができます。

 今回は下のようにポリゴンが回転されながら描画するサンプルを作成しますが、Managed DirectX 自体に関しては説明を入れると長くなってしまうので詳細は省きます。WPF と Managed DirectX の関連性だけ説明していきます。

WPFウインドウ上でManaged DirectXを使ってポリゴンを表示させる

 まず、WPF のウインドウ(ここでは Window1.xaml)を開き、ツールバーから「WindowsFormHost」コントロールを配置します。右にあるスライダーはおまけです。

WPF ウインドウデザイン

 本当は XAML の方にもう少し手を加えなければいけないのですが、Managed DirectX を使うためのコントロールを先に作成しなければいけないので後に回します。

 プロジェクトに「Windows Forms」の「カスタムコントロール」を追加してください。名前は「GraphicsDeviceControl」としておきます。

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

 事前に「Microsoft.DirectX」「Microsoft.DirectX.Direct3D」「Microsoft.DirectX.Direct3DX」の参照を忘れずに追加しておいてください。

Managed DirectX の参照

 サンプルコードを手短にするために、Managed DirectX に関係するプログラムはすべて GraphicsDeviceControl.cs にまとめています。あまり汎用性がある書き方ではないので、各自応用して書き換えてください。

 GraphicsDeviceControl の全コードは下のようにしました(デザイナ部分は除く )。Managed DirectX を使ったことがある人なら、特に変わった事はしていないことがわかるかと思います。常にポリゴンが回転するように見せるために Timer コンポーネントを使用しています。
 ほんとは「ApplicationSystem.Windows.Forms.Application.Idle」イベントを使用したかったのですが、WPF ではこのイベントは使えないので Timer を変わりに使っています。WPF ではアイドルイベントってどうやって拾うのかな?

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.DirectX;
using Microsoft.DirectX.Direct3D;
namespace ManagedDirectXOnWPF
{
    /// <summary>
    /// グラフィックデバイスコントロール
    /// </summary>
    public partial class GraphicsDeviceControl : Control
    {
        /// <summary>
        /// Direct3D デバイス
        /// </summary>
        private Device device = null;

        /// <summary>
        /// 頂点データ
        /// </summary>
        private CustomVertex.PositionColored[] vertices = new CustomVertex.PositionColored[3];
        /// <summary>
        /// 頂点データ
        /// </summary>
        public CustomVertex.PositionColored[] Vertices
        {
            get { return this.vertices; }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public GraphicsDeviceControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// コントロールが作成されるとき
        /// </summary>
        protected override void OnCreateControl()
        {
            if (this.DesignMode == false)
            {
                try
                {
                    // デバイス作成
                    PresentParameters pp = new PresentParameters();
                    pp.Windowed = true;
                    pp.SwapEffect = SwapEffect.Discard;
                    pp.BackBufferWidth = 300;
                    pp.BackBufferHeight = 300;
                    pp.EnableAutoDepthStencil = true;
                    pp.AutoDepthStencilFormat = DepthFormat.D16;
                    this.device = new Device(0, DeviceType.Hardware, this.Handle,
                        CreateFlags.SoftwareVertexProcessing, pp);

                    // 頂点データの設定
                    this.vertices[0] = new CustomVertex.PositionColored(
                        0.0f, -2.0f + (float)Math.Sqrt(3) * 3.0f, 0.0f,
                        Color.FromArgb(255, 0, 0).ToArgb());
                    this.vertices[1] = new CustomVertex.PositionColored(
                        3.0f, -2.0f, 0.0f,
                        Color.FromArgb(0, 255, 0).ToArgb());
                    this.vertices[2] = new CustomVertex.PositionColored(
                        -3.0f, -2.0f, 0.0f,
                        Color.FromArgb(0, 0, 255).ToArgb());

                    // ビュー変換行列を設定
                    this.device.Transform.View = Matrix.LookAtRH(
                        new Vector3(0.0f, 0.0f, -10.0f),
                        new Vector3(0.0f, 0.0f, 0.0f),
                        new Vector3(0.0f, 1.0f, 0.0f));

                    // 射影変換を設定
                    this.device.Transform.Projection = Matrix.PerspectiveFovRH(
                        Geometry.DegreeToRadian(45.0f), 1.0f, 1.0f, 100.0f);

                    // レンダリングステート設定
                    this.device.RenderState.Lighting = false;
                    this.device.RenderState.CullMode = Cull.None;
                    this.device.RenderState.AlphaBlendEnable = true;
                    this.device.RenderState.SourceBlend = Blend.SourceAlpha;
                    this.device.RenderState.DestinationBlend = Blend.InvSourceAlpha;
                }
                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.BeginScene();
            this.device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, Color.DarkBlue, 1.0f, 0);

            // 三角形描画
            this.device.Transform.World = Matrix.RotationY((float)Environment.TickCount / 1000.0f);
            this.device.VertexFormat = CustomVertex.PositionColored.Format;
            this.device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, this.vertices);

            this.device.EndScene();
            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 x:Class="ManagedDirectXOnWPF.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPFウインドウ上でManaged DirectXを使用してポリゴン描画"
    Height="338" Width="422"
    xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
    xmlns:xw="clr-namespace:ManagedDirectXOnWPF">
    <!-- 省略 -->
</Window>

 続いて配置した WindowsFormsHost コントロールのタグを展開し、下のように GraphicsDeviceControl を追加します。

<my:WindowsFormsHost Name="windowsFormsHostManagedDirectX" Width="300" Height="300"
                        HorizontalAlignment="Left" VerticalAlignment="Top">
    <xw:GraphicsDeviceControl x:Name="GraphicsDeviceControl" />
</my:WindowsFormsHost>

 「x:Name」はなくてもかまいませんが、サンプルではスライダーで頂点データにアクセスするために使用しています。

 これを実行すれば、サンプルみたいにポリゴンが回転して描画されるシーンを WPF 上で実行することができます。スライダーによるアクセスはおまけなのでサンプルデータをダウンロードして確認してみてください。

 以下、実行ファイルです。「.NET Framework 3.0」と「最新の DirectX ランタイム」が必要です。Windows Vista の場合はそのまま実行できます。

 サンプルプロジェクト一式です。「Visual Studio 2008 Professional Edition」で作成しています。

投稿日時 : 2008年1月25日 12:48

コメント

# WPF上でXNAを使用する 2008/01/29 8:50 オノデラの研究日記 in わんくま
WPF上でXNAを使用する

# xqOPfyRuVPrgdnTgpy 2014/08/28 12:22 http://crorkz.com/
uowyhi Thanks for another magnificent article. Where else could anyone get that type of info in such an ideal way of writing? I have a presentation next week, and I am on the look for such info.

# Illikebuisse fvrlb 2021/07/04 14:42 www.pharmaceptica.com
hydrochloraquin https://www.pharmaceptica.com/

# re: WPF??Managed DirectX????? 2021/08/07 7:03 hydroxychlor 200mg
cloroquine https://chloroquineorigin.com/# hydroxychloroquine 400 mg

# ロレックス オイスター 相場 2022/09/04 10:19 nnesmdxagbq@yahoo.co.jp
欲しい時にサクッと手に入る明日楽対応がありがたい。また、きちんとブランドの箱に収まっていて好感度高めです。
【送料無料】ルイヴィトン アイフォンケースをセール価格で販売中♪ルイヴィトン アイフォンケース ダミエ グラフィット iPhone6 iPhone6S ハードケース N61205 新品 LOUISVUITTON
ローズゴールドに映える
此のタイプのケースを愛用しています。
落ち着いたダミエグラフィットに、
新作のローズゴールド(やや甘めのカラー)がよく映えます。
ロレックス オイスター 相場 https://www.gmt78.com/product/detail/6634.htm

Post Feedback

タイトル
名前
Url:
コメント