Exibir uma exibição XNA diretamente em uma janela do WPF

Página atualizada :
Data de criação de página :

resumo

Descreve como renderizar diretamente em uma janela do WPF com XNA.

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

Ambiente operacional

Pré-requisitos

Versões do XNA suportadas
  • 2.0
  • 3.0
Plataformas suportadas
  • Windows (XP SP2 ou posterior, Vista)
Versão do sombreador de vértice necessária para Windows 1.1
Versão do sombreador de pixel necessária para Windows 1.1

Ambiente operacional

plataforma

substância

Em Usando XNA em aplicativos WPF, usei o controle WindowsFormsHost para exibir o modo de exibição, mas agora quero usar apenas a janela do WPF para exibir o polígono. "Usando XNA em aplicativos WPF" é um pouco de representação, então explicarei as diferenças.

Aliases de namespace

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

Como as estruturas Color e Matrix são cobertas pelos namespaces XNA Framework e WPF, você deve especificar o nome da estrutura do namespace para usá-la. No entanto, parece ser longo todas as vezes, então estou criando um alias de namespace. Por exemplo, "Microsoft.Xna.Framework.Rectangle" agora pode ser especificado como "Xna.Rectangle".

temporizador

Desde o .NET Framework 3.0, uma classe de temporizador chamada "System.Windows.Threading.DispatcherTimer" está disponível e essa classe de temporizador é usada para renderizar cada quadro. O WPF usa um DispatcherTimer para permitir o processamento no mesmo thread que a interface do usuário.

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

, declarando um DispatcherTimer.

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

Define um método que o DispatcherTimer chama em 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 é o processo de definir o cronômetro. Depois de criar uma instância de DispatcherTimer e definir o método a ser chamado e o intervalo de tempo, o método DispatcherTimer.Start inicia o temporizador.

Obtendo um identificador de janela

Para criar um dispositivo Direct3D, você precisa de um identificador de janela. No entanto, o WPF não tem o conceito de um identificador de janela, portanto, não há como obtê-lo diretamente da classe Window.

No entanto, como há momentos em que um identificador de janela é necessário, como nesse caso, o identificador de janela pode ser obtido por meio da classe "System.Windows.Interop.WindowInteropHelper" como uma interoperabilidade para o código Win32. (esta é a classe Window)

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

Use esse identificador ao criar um dispositivo Direct3D. No entanto, se você tentar obter o identificador de janela no método OnInitialized, ele retornará 0, provavelmente porque a janela ainda não foi criada. Neste exemplo, o dispositivo é criado no método OnSourceInitialized.

Renderizar para área especificada

Você pode especificar a área de destino como o segundo argumento de GraphicsDevice.Present. Na amostra, tento desenhá-lo na posição (50, 50) como um deslocamento. O tamanho é o mesmo que o tamanho do backbuffer (300, 300). O primeiro argumento é a área da qual extrair e, se null for especificado, o buffer original será usado.

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

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

Destruindo um dispositivo

Você está destruindo seu dispositivo quando fecha a janela. Originalmente, eu queria lidar com isso com o método Dispose, mas como a classe Window do WPF não herda IDisposable por padrão, eu a escrevi aqui.

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

execução

Se você executar o programa de exemplo, poderá executá-lo com uma imagem de tela como a do início do artigo.

À primeira vista, ele renderiza bem, mas quando redimensiono a janela arrastando-a com o mouse, a visualização pisca ou desaparece durante o redimensionamento. Parece estar em conflito com a renderização do WPF, e tentei muitas coisas, mas não consegui resolver.

Se você estiver usando o XNA, parece mais seguro usar o controle WindowsFormsHost.

O programa requer o .NET Framework 3.0, o tempo de execução DirectX mais recente e o Microsoft XNA Framework Redistributable 2.0. Além disso, como requisito de hardware, é necessária "uma placa gráfica compatível com Pixel Shader 1.1 ou superior".

Além disso, o projeto foi criado no "Visual Studio 2008 Professional Edition". Prepare um ambiente para o Visual Studio 2008.