Mostrar una vista XNA directamente en una ventana de WPF

Actualización de la página :
Fecha de creación de la página :

resumen

Describe cómo representar directamente en una ventana de WPF con XNA.

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

Entorno operativo

Prerrequisitos

Versiones de XNA compatibles
  • 2.0
  • 3.0
Plataformas compatibles
  • Windows (XP SP2 o posterior, Vista)
Versión requerida del sombreador de vértices de Windows 1.1
Versión de Pixel Shader requerida para Windows 1.1

Entorno operativo

plataforma

sustancia

En Uso de XNA en aplicaciones de WPF, usé el control WindowsFormsHost para mostrar la vista, pero ahora solo quiero usar la ventana de WPF para mostrar el polígono. "Uso de XNA en aplicaciones WPF" es un poco una representación, por lo que explicaré las diferencias.

Alias de espacio de nombres

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

Dado que las estructuras Color y Matrix están cubiertas por los espacios de nombres XNA Framework y WPF, debe especificar el nombre de la estructura del espacio de nombres para poder utilizarla. Sin embargo, parece ser largo cada vez, por lo que estoy creando un alias de espacio de nombres. Por ejemplo, "Microsoft.Xna.Framework.Rectangle" ahora se puede especificar como "Xna.Rectangle".

temporizador

Desde .NET Framework 3.0, ha estado disponible una clase de temporizador denominada "System.Windows.Threading.DispatcherTimer", y esta clase de temporizador se usa para representar cada fotograma. WPF usa un DispatcherTimer para permitir el procesamiento en el mismo subproceso que la interfaz de usuario.

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

, declarando un DispatcherTimer.

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

Define un método al que DispatcherTimer llama a intervalos regulares.

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

Este es el proceso de configurar el temporizador. Después de crear una instancia de DispatcherTimer y establecer el método al que se va a llamar y el intervalo de tiempo, el método DispatcherTimer.Start inicia el temporizador.

Obtención de una manija de ventana

Para crear un dispositivo Direct3D, necesita un identificador de ventana. Sin embargo, WPF no tiene el concepto de identificador de ventana, por lo que no hay manera de obtenerlo directamente de la clase Window.

Sin embargo, dado que hay ocasiones en las que se requiere un identificador de ventana, como en este caso, el identificador de ventana se puede obtener a través de la clase "System.Windows.Interop.WindowInteropHelper" como interoperabilidad para el código Win32. (esta es la clase Window)

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

Use este identificador al crear un dispositivo Direct3D. Sin embargo, si intenta obtener el identificador de ventana en el método OnInitialized, devolverá 0, probablemente porque la ventana aún no se ha creado. En este ejemplo, el dispositivo se crea en el método OnSourceInitialized.

Renderizar en el área especificada

Puede especificar el área de destino como el segundo argumento de GraphicsDevice.Present. En la muestra, trato de dibujarlo en la posición (50, 50) como un desplazamiento. El tamaño es el mismo que el tamaño del búfer de reserva (300, 300). El primer argumento es el área de la que se va a extraer y, si se especifica null, se utiliza el búfer original.

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

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

Destrucción de un dispositivo

Estás destruyendo tu dispositivo cuando cierras la ventana. Originalmente, quería controlarlo con el método Dispose, pero dado que la clase Window de WPF no hereda IDisposable de forma predeterminada, lo escribí aquí en su lugar.

/// <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);
}

ejecución

Si ejecuta el programa de ejemplo, puede ejecutarlo con una imagen de pantalla como la que se encuentra al principio del artículo.

A primera vista, se renderiza bien, pero cuando cambio el tamaño de la ventana arrastrándola con el ratón, la vista parpadea o desaparece durante el cambio de tamaño. Parece estar en conflicto con la representación de WPF, y probé muchas cosas pero no pude resolverlo.

Si usa XNA, parece más seguro usar el control WindowsFormsHost.

El programa requiere .NET Framework 3.0, el último tiempo de ejecución de DirectX y Microsoft XNA Framework Redistributable 2.0. Además, como requisito de hardware, se requiere "una tarjeta gráfica que admita Pixel Shader 1.1 o superior".

Además, el proyecto fue creado en "Visual Studio 2008 Professional Edition". Prepare un entorno para Visual Studio 2008.