Affichage d’une vue XNA directement sur une fenêtre WPF

Page mise à jour :
Date de création de la page :

résumé

Décrit comment effectuer un rendu directement dans une fenêtre WPF avec XNA.

WPF ウインドウ上に直接 XNA のビューを表示する

Environnement d’exploitation

Conditions préalables

Versions XNA prises en charge
  • 2.0
  • 3.0
Plates-formes prises en charge
  • Windows (XP SP2 ou version ultérieure, Vista)
Version du Vertex Shader requise par Windows 1.1
Version du Pixel Shader requise par Windows 1.1

Environnement d’exploitation

plateforme

substance

Dans Utilisation de XNA dans les applications WPF, j’ai utilisé le contrôle WindowsFormsHost pour afficher la vue, mais je souhaite maintenant utiliser uniquement la fenêtre WPF pour afficher le polygone. « Utilisation de XNA dans les applications WPF » est un peu une représentation, je vais donc expliquer les différences.

Alias d’espace de noms

// 名前空間エイリアス
using Xna = Microsoft.Xna.Framework;
using XnaGraphics = Microsoft.Xna.Framework.Graphics;

Étant donné que les structures Color et Matrix sont couvertes par les espaces de noms XNA Framework et WPF, vous devez spécifier le nom de la structure à partir de l’espace de noms pour pouvoir l’utiliser. Cependant, il semble être long à chaque fois, donc je crée un alias d’espace de noms. Par exemple, « Microsoft.Xna.Framework.Rectangle » peut désormais être spécifié comme « Xna.Rectangle ».

minuteur

Depuis le .NET Framework 3.0, une classe de minuterie appelée « System.Windows.Threading.DispatcherTimer » est disponible, et cette classe de minuterie est utilisée pour afficher chaque image. WPF utilise un DispatcherTimer pour autoriser le traitement sur le même thread que l’interface utilisateur.

/// <summary>
/// タイマー
/// </summary>
private DispatcherTimer timer = null;

, en déclarant un DispatcherTimer.

/// <summary>
/// タイマーイベント
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
    this.Draw();
}

Définit une méthode que DispatcherTimer appelle à intervalles réguliers.

// タイマー
this.timer = new DispatcherTimer();
this.timer.Tick += new EventHandler(dispatcherTimer_Tick);
this.timer.Interval = new TimeSpan(0, 0, 0, 0, 16);
this.timer.Start();

Il s’agit du processus de réglage de la minuterie. Après avoir créé une instance de DispatcherTimer et défini la méthode à appeler et l’intervalle de temps, la méthode DispatcherTimer.Start démarre le minuteur.

Obtention d’une poignée de fenêtre

Pour créer un appareil Direct3D, vous avez besoin d’une poignée de fenêtre. Cependant, WPF n’a pas le concept de descripteur de fenêtre, il n’y a donc aucun moyen de l’obtenir directement à partir de la classe Window.

Toutefois, étant donné qu’il y a des moments où un descripteur de fenêtre est requis, comme dans ce cas, le descripteur de fenêtre peut être obtenu via la classe « System.Windows.Interop.WindowInteropHelper » en tant qu’interopérabilité pour le code Win32. (il s’agit de la classe Window)

// ウィンドウハンドルを取得する
IntPtr handle = new WindowInteropHelper(this).Handle;

Utilisez ce handle lors de la création d’un appareil Direct3D. Toutefois, si vous essayez d’obtenir le descripteur de fenêtre dans la méthode OnInitialized, il renverra 0, probablement parce que la fenêtre n’a pas encore été créée. Dans cet exemple, l’appareil est créé à l’aide de la méthode OnSourceInitialized.

Rendu dans la zone spécifiée

Vous pouvez spécifier la zone de destination comme deuxième argument de GraphicsDevice.Present. Dans l’échantillon, j’essaie de le dessiner à la position (50, 50) en tant que décalage. La taille est la même que celle de la mémoire tampon d’arrière-plan (300, 300). Le premier argument est la zone à partir de laquelle dessiner, et si null est spécifié, le tampon d’origine est utilisé.

// 描画先を指定する
Xna.Rectangle rect = new Xna.Rectangle(
    50, 50,
    (int)this.viewSize.Width, (int)this.viewSize.Height);

this.device.Present(null, rect, this.windowHandle);

Destruction d’un appareil

Vous détruisez votre appareil lorsque vous fermez la fenêtre. À l’origine, je voulais le gérer avec la méthode Dispose, mais comme la classe WPF Window n’hérite pas de IDisposable par défaut, je l’ai écrit ici à la place.

/// <summary>
/// ウインドウが閉じたとき
/// </summary>
/// <param name="e"></param>
protected override void OnClosed(EventArgs e)
{
    if (this.device != null)
    {
        this.device.Dispose();
        this.device = null;
    }

    base.OnClosed(e);
}

exécution

Si vous exécutez l’exemple de programme, vous pouvez l’exécuter avec une image d’écran comme celle du début de l’article.

À première vue, le rendu est bon, mais lorsque je redimensionne la fenêtre en la faisant glisser avec la souris, la vue scintille ou disparaît lors du redimensionnement. Il semble être en conflit avec le rendu WPF, et j’ai essayé beaucoup de choses mais je n’ai pas pu le résoudre.

Si vous utilisez XNA, il semble plus sûr d’utiliser le contrôle WindowsFormsHost.

Le programme nécessite le .NET Framework 3.0, le dernier runtime DirectX et le Microsoft XNA Framework Redistributable 2.0. De plus, en tant qu’exigence matérielle, « une carte graphique prenant en charge Pixel Shader 1.1 ou supérieur » est requise.

De plus, le projet a été créé dans « Visual Studio 2008 Professional Edition ». Préparez un environnement pour Visual Studio 2008.