情報
要求されたトピックは次のとおりです。しかし、このトピックはこのライブラリには含まれていません。

Windows Phone 8 の Direct3D with XAML アプリ

2014/06/18

対象: Windows Phone 8 および Windows Phone Silverlight 8.1 のみ

このトピックでは、Direct3D with XAML アプリの構造について説明し、さらに Windows Phone SDK 8.0 に含まれるプロジェクト テンプレートについて解説します。この種類のアプリは DrawingSurfaceBackgroundGrid コントロールを使用します。このコントロールでは、Direct3D を使用してアプリの背景全体にわたって表示されるグラフィックを UI の XAML コントロールの背後にレンダリングできます。DrawingSurfaceBackgroundGrid は XAML ツリーのルート要素とする必要があり、常にフル サイズの画面になります。

別の種類のアプリは XAML & Direct3D アプリです。このアプリは DrawingSurface コントロールを使用します。このコントロールは任意のサイズにして、他の XAML コントロールの上、下およびインラインに配置できます。アプリに適したコントロールの選択の詳細については、「Windows Phone 8 のゲームに適したプロジェクト テンプレートを選択する」を参照してください。

Windows ストア アプリのゲーム開発について説明するために作成されたマーブル メイズのサンプルは、Direct3D with XAML プロジェクト テンプレートを使用するように移植されています。サンプルをダウンロードするには、「Direct3D with XAML のマーブル メイズ」を参照してください。

Direct3D with XAML アプリは、XAML ベースの Windows Phone アプリと Windows Phone ランタイム を基にしたコンポーネントという 2 つのコンポーネントで構成されます。XAML エンジンは、Direct3D グラフィック デバイスを作成して維持します。XAML エンジンは、フレームごとに 1 回、グラフィック デバイスと関連付けられているレンダー ターゲットを Windows Phone ランタイム コンポーネントに渡します。グラフィック デバイスの更新後、Windows Phone ランタイム コンポーネントの Render メソッドが呼び出されます。アプリはここで Direct3D を呼び出して、指定したレンダー ターゲットに描画できます。グラフィック デバイスが XAML エンジンと共有されているため、Render メソッドはアプリが描画用のデバイスを使用できる唯一の場所です。Windows Phone SDK 8.0 では、この種類のアプリが必要とする低レベルのインフラストラクチャを実装するプロジェクト テンプレートが提供されます。このプロジェクト テンプレートを使用して新しいアプリを作成することができます。その後で F5 キーを押すと、デバイスの画面または Windows Phone Emulator に 3D キューブが直ちにレンダリングされます。このトピックの残りの部分では、Direct3D with XAML アプリ用のプロジェクト テンプレートについて説明します。

Direct3D with XAML プロジェクト テンプレートを使用し、複数のページが含まれる場合、プロジェクト テンプレートに含まれるファイルを次のように変更する必要があります。これにより、ユーザーがページ間を移動するときに、メモリが正しく管理されます。これらの変更は、プロジェクト テンプレートの将来のリリースに含まれます。

プロジェクト テンプレートを更新するには

  1. MainPage.xaml.cs で、次の行を

    
    private Direct3DBackground m_d3dBackground = new Direct3DBackground();
    
    
    

    次のように置き換えます

    
    private Direct3DBackground m_d3dBackground = null;
    
    
    
  2. MainPage.xaml.cs で、DrawingSurface コントロールの Loaded イベント ハンドラーを次のように置き換えます。

    
    private void DrawingSurfaceBackground_Loaded(object sender, RoutedEventArgs e)
    {
        if (m_d3dBackground == null)
        {
            m_d3dBackground = new Direct3DBackground();
    
            // Set window bounds in dips
            m_d3dBackground.WindowBounds = new Windows.Foundation.Size(
                (float)Application.Current.Host.Content.ActualWidth,
                (float)Application.Current.Host.Content.ActualHeight
                );
    
            // Set native resolution in pixels
            m_d3dBackground.NativeResolution = new Windows.Foundation.Size(
                (float)Math.Floor(Application.Current.Host.Content.ActualWidth * Application.Current.Host.Content.ScaleFactor / 100.0f + 0.5f),
                (float)Math.Floor(Application.Current.Host.Content.ActualHeight * Application.Current.Host.Content.ScaleFactor / 100.0f + 0.5f)
                );
    
            // Set render resolution to the full native resolution
            m_d3dBackground.RenderResolution = m_d3dBackground.NativeResolution;
    
            // Hook-up native component to DrawingSurfaceBackgroundGrid
            DrawingSurfaceBackground.SetBackgroundContentProvider(m_d3dBackground.CreateContentProvider());
            DrawingSurfaceBackground.SetBackgroundManipulationHandler(m_d3dBackground);
        }
    }
    
    
    
  3. PhoneDirect3DXamlAppComponent.cpp で、CreateContentProvider メソッドの定義を次で置き換えます。

    
    IDrawingSurfaceBackgroundContentProvider^ Direct3DBackground::CreateContentProvider()
    {
    	ComPtr<Direct3DContentProvider> provider = Make<Direct3DContentProvider>(this);
    	return reinterpret_cast<IDrawingSurfaceBackgroundContentProvider^>(provider.Get());
    }
    
    
    

このセクションでは、Direct3D with XAML アプリのプロジェクト テンプレートに含まれているファイルについて説明します。

Direct3D with XAML アプリを作成する場合は、Windows Phone SDK 8.0 に含まれる Direct3D with XAML アプリのプロジェクト テンプレートを使用して作業を開始する必要があります。新しいプロジェクトを作成するには、Visual Studio で、[ファイル] メニューの [新しいプロジェクト] をクリックし、[Visual C++] の下で [Windows Phone の Direct3D with XAML アプリ] をクリックします。

このテンプレートは、マネージ XAML ベース アプリと このテンプレートは、マネージ XAML ベース アプリと Windows Phone ランタイム コンポーネントという 2 つのプロジェクトを含む新しいソリューションを作成します。XAML アプリは、通常の Windows Phone アプリとほとんど同じです。このアプリでは、XAML とマネージ コードを使用して UI を実装しますが、その方法は Direct3D グラフィックを使用しないアプリの場合と同じです。唯一の違いは、数行のコードがプロジェクトに追加されており、それにより、Direct3D グラフィックが表示される DrawingSurfaceBackgroundGrid コントロールが追加され、Windows Phone ランタイム コンポーネントへの接続が設定されることです。

Windows Phone ランタイム コンポーネント プロジェクトには、純粋なネイティブの Windows Phone 用 Direct3D アプリ内のファイルに類似しているファイル、および Windows 8 用 Direct3D プロジェクト テンプレートに類似しているファイルがいくつか含まれています。これらのファイルは、グラフィック デバイスの取得を処理し、画面上にキューブを描画するサンプル コードを含んでいます。Windows Phone ランタイム コンポーネントとメイン アプリケーション、および Direct3D グラフィックを XAML UI に合成する基になる XAML エンジンとの間の通信に使用されるいくつかの追加のファイルがあります。アプリの作成をすぐに始める予定で、アプリを機能させる低レベルの技術的な詳細に興味がない場合は、XAML ベースの UI とマネージ コードをホストする MainPage クラス、共有テクスチャへの実際の描画が実行される場所となる CubeRenderer クラス、およびタッチ入力について説明する PhoneDirect3DXamlAppComponent.cpp ファイルに関するセクションを読むだけでもかまいません。残りの部分は、テンプレートで提供されるコードに関する説明よりも詳しい説明になっています。

マネージ XAML アプリ

前に説明したように、Direct3D with XAML テンプレートを元にして作成された XAML アプリ プロジェクトは、Direct3D を使用しない通常の Windows Phone アプリとほとんど同じです。ただし、2 つのファイルに若干の追加のコードがあります。

MainPage.xaml

このファイルは、XAML ベースの Windows Phone アプリの UI を定義します。このプロジェクト テンプレートと共に、DrawingSurfaceBackgroundGrid コントロールが追加されます。このコントロールは、XAML ページのルート要素です。その他の XAML コントロールは、DrawingSurfaceBackgroundGrid の子として追加できますが、その前後または DrawingSurfaceBackgroundGrid を含む要素は配置できません。


<DrawingSurfaceBackgroundGrid x:Name="DrawingSurfaceBackground" Loaded="DrawingSurfaceBackground_Loaded">
</DrawingSurfaceBackgroundGrid>


MainPage.xaml.cs

メイン ページの分離コード ファイルで、DrawingSurfaceBackgroundGrid コントロールが実際の Direct3D 描画を実行する Windows Phone ランタイム コンポーネントにフックされます。ページの上部にある using ディレクティブは、Windows Phone ランタイム コンポーネント "PhoneDirect3DXamlAppComponent" が含まれる名前空間を参照します。


using PhoneDirect3DXamlAppComponent;


次に、Direct3DBackground 型のメンバー変数が宣言されます。Direct3DBackground は、Windows Phone ランタイム コンポーネントによって公開されるクラスです。このクラスについてはこのチュートリアルで後で詳しく説明します。


private Direct3DBackground m_d3dBackground = null;


MainPage.xaml.cs でテンプレートが作成する唯一のメソッドは、DrawingSurfaceBackgroundGrid コントロールの Loaded イベント ハンドラーです。 このメソッドの最初の部分は、Direct3DBackground クラスの WindowBoundsNativeResolution、および RenderResolution プロパティを設定します。これらのプロパティにより、Windows Phone ランタイム コンポーネントは画面と同じ大きさのビューポートを作成できます。WindowBounds プロパティはデバイス非依存ピクセル (DIP) で表されたサイズを使用します。これは、DrawingSurfaceBackgroundGrid およびすべてのコントロールが ActualWidth および ActualHeight プロパティに使用するのと同じ単位です。 NativeResolution プロパティと RenderResolution プロパティでは、寸法を物理ピクセル単位で表すことが前提となっています。したがって、サイズは ScaleFactor プロパティで乗算し、100 で除算することによって変換されます。これにより、サポート対象のすべての画面解像度で正しいサイズ (ピクセル単位) になることが保証されます。数式に .5 ピクセルを加算し、Floor 関数を呼び出すことにより、寸法が最も近い整数に切り上げられます。

サイズ プロパティの設定後に、DrawingSurfaceBackgroundGrid コントロールの SetContentProvider(Object) メソッドが、Direct3DBackground メソッド CreateContentProvider によって返されたオブジェクトを使用して呼び出されます。この呼び出しで、Windows Phone ランタイム コンポーネントを、Direct3D を使用して DrawingSurfaceBackgroundGrid コントロールのコンテンツを描画するプロバイダーとして設定します。このチュートリアルで後で説明するように、プロジェクト テンプレートは CreateContentProvider ヘルパー メソッドを使用して、コンテンツ プロバイダーを設定するための低レベルの呼び出しをカプセル化できるように構造化されます。

次に SetManipulationHandler(Object) が呼び出され、Direct3DBackground オブジェクトが渡されます。これにより、ユーザーが DrawingSurfaceBackgroundGrid コントロール内をタッチしたときに、PointerPressed()PointerMoved()、および PointerReleased() タッチ イベントを受け取るように Direct3DBackground を登録します。MainPage 分離コードページ内でタッチ イベントを取得してからコンポーネントにデータを手動で渡すよりも、Windows Phone ランタイム コンポーネント内でこれらのイベントを直接使用する方がパフォーマンスが向上します。


private void DrawingSurfaceBackground_Loaded(object sender, RoutedEventArgs e)
{
    if (m_d3dBackground == null)
    {
        m_d3dBackground = new Direct3DBackground();

        // Set window bounds in dips
        m_d3dBackground.WindowBounds = new Windows.Foundation.Size(
            (float)Application.Current.Host.Content.ActualWidth,
            (float)Application.Current.Host.Content.ActualHeight
            );

        // Set native resolution in pixels
        m_d3dBackground.NativeResolution = new Windows.Foundation.Size(
            (float)Math.Floor(Application.Current.Host.Content.ActualWidth * Application.Current.Host.Content.ScaleFactor / 100.0f + 0.5f),
            (float)Math.Floor(Application.Current.Host.Content.ActualHeight * Application.Current.Host.Content.ScaleFactor / 100.0f + 0.5f)
            );

        // Set render resolution to the full native resolution
        m_d3dBackground.RenderResolution = m_d3dBackground.NativeResolution;

        // Hook-up native component to DrawingSurfaceBackgroundGrid
        DrawingSurfaceBackground.SetBackgroundContentProvider(m_d3dBackground.CreateContentProvider());
        DrawingSurfaceBackground.SetBackgroundManipulationHandler(m_d3dBackground);
    }
}


Windows ランタイム コンポーネント

このセクションでは、Direct3D with XAML アプリ プロジェクト テンプレートの一部として作成される Windows ランタイム コンポーネントについて説明します。このプロジェクトのファイルの多くは、DrawingSurfaceBackgroundGrid コントロールとコンポーネントのフックの低レベルの詳細を処理します。ほとんどの場合、これらを変更する必要はありません。

PhoneDirect3DXamlAppComponent.h

このヘッダー ファイルは Direct3DBackground クラスを宣言します。このクラスは、XAML エンジンと作成した Direct3D コードの間のプロキシとして機能します。このクラスは、PointerPressed()PointerMoved() および PointerReleased() イベントを含む IDrawingSurfaceManipulationHandler インターフェイスを実装します。

PhoneDirect3DXamlAppComponent.cpp

PhoneDirect3DXamlAppComponent 実装ファイル内には、MainPage.xaml.cs の DrawingSurfaceBackground_Loaded イベント ハンドラーから呼び出される CreateContentProvider メソッドの定義があります。このメソッドは、Direct3DContentProvider クラスの新規インスタンスを初期化し、IDrawingSurfaceContentProvider としてキャストします。IDrawingSurfaceContentProvider の定義を見ると、メンバーが定義されていないことがわかります。これはコードを使用して実装するインターフェイスではないためです。Direct3DContentProvider クラスは、Windows ランタイム C++ テンプレート ライブラリ (WRL) を使用して実装されます。このメソッドは、クラスを Windows Phone ランタイム インターフェイスとしてキャストし、XAML エンジンによってアクセスできるようにします。アプリを開発するときにこれらの実装の詳細について心配する必要はありません。ここでは情報提供のみを目的として説明しています。


IDrawingSurfaceBackgroundContentProvider^ Direct3DBackground::CreateContentProvider()
{
	ComPtr<Direct3DContentProvider> provider = Make<Direct3DContentProvider>(this);
	return reinterpret_cast<IDrawingSurfaceBackgroundContentProvider^>(provider.Get());
}


次に、PhoneDirect3DXamlAppComponent.cpp は、MainPage.xaml.cs の DrawingSurfaceBackground_Loaded イベント ハンドラーから呼び出される SetManipulationHost(DrawingSurfaceManipulationHost) メソッドの実装を提供します。これにより、Direct3DBackground クラスは、DrawingSurface コントロールからタッチ入力イベントを受け取れるようになります。このテンプレートは、独自のコードを追加できるタッチ入力イベント用スタブアウト ハンドラーも提供します。


void Direct3DBackground::SetManipulationHost(DrawingSurfaceManipulationHost^ manipulationHost)
{
	manipulationHost->PointerPressed +=
		ref new TypedEventHandler<DrawingSurfaceManipulationHost^, PointerEventArgs^>(this, &Direct3DBackground::OnPointerPressed);

	manipulationHost->PointerMoved +=
		ref new TypedEventHandler<DrawingSurfaceManipulationHost^, PointerEventArgs^>(this, &Direct3DBackground::OnPointerMoved);

	manipulationHost->PointerReleased +=
		ref new TypedEventHandler<DrawingSurfaceManipulationHost^, PointerEventArgs^>(this, &Direct3DBackground::OnPointerReleased);
}



void Direct3DBackground::OnPointerPressed(DrawingSurfaceManipulationHost^ sender, PointerEventArgs^ args)
{
	// Insert your code here.
}

void Direct3DBackground::OnPointerMoved(DrawingSurfaceManipulationHost^ sender, PointerEventArgs^ args)
{
	// Insert your code here.
}

void Direct3DBackground::OnPointerReleased(DrawingSurfaceManipulationHost^ sender, PointerEventArgs^ args)
{
	// Insert your code here.
}


次に、PhoneDirect3DXamlAppComponent.cpp が Connect および Disconnect メソッドを定義します。Connect は、SetContentProvider(Object) の呼び出しが完了した後に呼び出されます。このメソッドでは、新しい CubeRenderer が作成され、その Initialize メソッドが呼び出されます。この呼び出し中に、CubeRenderer が頂点バッファーやシェーダーなどのデバイスに依存するリソースを作成します。Disconnect は、関連付けられている DrawingSurfaceBackgroundGrid コントロールがビジュアル ツリーから消去されるときに呼び出されます。


HRESULT Direct3DBackground::Connect(_In_ IDrawingSurfaceRuntimeHostNative* host, _In_ ID3D11Device1* device)
{
	m_renderer = ref new CubeRenderer();
	m_renderer->Initialize(device);
	m_renderer->UpdateForWindowSizeChange(WindowBounds.Width, WindowBounds.Height);

	// Restart timer after renderer has finished initializing.
	m_timer->Reset();

	return S_OK;
}

void Direct3DBackground::Disconnect()
{
	m_renderer = nullptr;
}


フレームごとに PrepareResources メソッドが XAML エンジンによって呼び出されます。 このときに、Windows Phone ランタイム コンポーネントによってレンダー ターゲットで必要なサイズを設定できます。テンプレートによって、レンダー ターゲットの幅と高さが DrawingSurfaceBackground_Loaded で XAML アプリによって設定された画面のサイズに設定されます。このサイズはレンダリング速度を速くするため、実際の画面の解像度の 4 分の 1 などに小さく設定できます。XAML エンジンでは、ハードウェア スケーリングが自動的に使用され、小さなレンダー ターゲットが最大で全画面のサイズまで効率よくスケーリングされます。

注意注意:

XAML エンジンでは、ハードウェア スケーリングを使用して、Direct3D with XAML アプリのレンダー ターゲットをスケーリングします。MediaElement でもハードウェア スケーリングが使用されているため、DrawingSurfaceBackgroundGrid のパフォーマンスには、XAML ビジュアル ツリーに MediaElement が存在するかどうかが重要です。 MediaElement なしで DrawingSurfaceBackgroundGrid を使用すると、ランタイムでさらに最適化できるため、結果としてパフォーマンスが向上します。


HRESULT Direct3DBackground::PrepareResources(_In_ const LARGE_INTEGER* presentTargetTime, _Inout_ DrawingSurfaceSizeF* desiredRenderTargetSize)
{
	m_timer->Update();
	m_renderer->Update(m_timer->Total, m_timer->Delta);

	desiredRenderTargetSize->width = RenderResolution.Width;
	desiredRenderTargetSize->height = RenderResolution.Height;

	return S_OK;
}


PhoneDirect3DXamlAppComponent.cpp で定義される最後のメソッドは Draw です。このメソッドで最初に実行されるのは、Direct3Dbase.cpp で定義される UpdateDevice を呼び出して、グラフィック デバイス、コンテキスト、レンダー ターゲットを更新することです。ユーザーが切り替えてアプリから離れて戻ってきたときに、XAML エンジンが失われ、グラフィック デバイスが再作成される可能性があります。この場合、このメソッドを使用すると、アプリはテクスチャやシェーダーなどのデバイスに依存するリソースを再作成できます。

XAML エンジンは、XAML UI を更新するごとに 1 回 Draw メソッドを呼び出します。RequestAdditionalFrame を呼び出すことで、現在のフレームの終了後にできるだけ早く画面を再描画するように XAML エンジンに指示します。RequestAdditionalFrame は、Connect を呼び出した後、Disconnect を呼び出す前に、Windows Phone ランタイム コンポーネントの任意の場所で呼び出すことができます。アプリの電力消費を抑制するには、テンプレート コードを変更して、Draw メソッドが呼び出されるたびに RequestAdditionalFrame が呼び出されないようにすることができます。XAML エンジンは、UI を更新するたびに Draw を呼び出しますが、できる限り迅速な再描画は行わなくなります。これは、静的なコンテンツ、またはアプリに最大限のフレーム レートで再描画する必要のないコンテンツを表示させる場合は特に役立ちます。


HRESULT Direct3DBackground::Draw(_In_ ID3D11Device1* device, _In_ ID3D11DeviceContext1* context, _In_ ID3D11RenderTargetView* renderTargetView)
{
	m_renderer->UpdateDevice(device, context, renderTargetView);
	m_renderer->Render();

	RequestAdditionalFrame();

	return S_OK;
}


Direct3DBase.cpp

Direct3DBase は、Direct3D アプリ、Windows Phone、Windows 8 などで使用される多くの Direct3D プロジェクト テンプレートで使用されるクラスです。このクラスの実装は、XAML &amp; Direct3D アプリのテンプレートでは少々異なりますが、構造と機能はよく似ています。ほとんどの場合、このクラスを変更する必要はありません。このクラスは、CreateDeviceResources を直ちに呼び出す Initialize メソッドを公開します。このメソッドの基本実装では、何も実行されません。CubeRenderer.cpp でオーバーロードされたメソッドは、このメソッドを使用してテクスチャやシェーダーなどのデバイスに依存するリソースを作成します。このメソッドは、アプリの実行中にグラフィック デバイスが変更されると、複数回呼び出せることに注意してください。

次に、Direct3DBase は、UpdateDevice メソッドを実装します。このメソッドは、フレームごとに 1 回 Direct3DBackground クラスから呼びだされることを見てきました。前のフレームからグラフィック デバイスが変更されると、CreateDeviceResources が再度呼び出されます。レンダー ターゲットのサイズが変更されると、CreateWindowSizeDependentResources が呼び出されます。最後に、レンダー ターゲットのサイズからビューポイント オブジェクトが作成されます。

CubeRenderer.cpp

CubeRenderer クラスは Direct3Dbase から継承します。このクラスは、回転するキューブを描画するいくつかの Direct3D サンプル コードを提供します。このファイルもさまざまなプラットフォーム上の Direct3D テンプレートに共通です。Direct3D を初めて使用するときには、ある程度時間をかけてこのファイル内のコードを変更し、画面に描画される内容を変更したい場合もあります。最終的に自分のゲームに合わせて作成したクラスでこのクラスを置き換えることがよくありますが、基本的な構造は維持する必要があります。たとえば、Direct3DBase から自分のクラスを継承する必要があります。

CubeRenderer.cpp には、CreateDeviceResources のメソッドの定義が含まれています。ここでデバイスに依存するリソースを作成します。テンプレート内のサンプル コードは、キューブのジオメトリを定義する頂点バッファーとインデックス バッファーを作成し、さらにレンダー ターゲットにキューブを描画する方法を定義する頂点シェーダーとピクセル シェーダーを作成します。

次に、CreateWindowSizeDependentResources メソッドが定義されます。このメソッドは、レンダー ターゲットのサイズを使用して、パースペクティブ マトリックスを作成します。

最終的に、CubeRenderer.cpp は、フレームごとに 1 回呼び出される Update メソッドと Render メソッドを実装します。Update では通常、ゲーム内のオブジェクトがフレームごとに新しい場所に更新されます。サンプル コードでは、ビューとモデルの行列が更新され、キューブが画面上で回転します。Render では、レンダー ターゲットに描画するための Direct3D 呼び出しが実行されます。このメソッドに含めるコードはゲームによって大きく異なります。グラフィック デバイスは XAML エンジンによって所有されているため、Render メソッド中はレンダー ターゲットに描画するグラフィック デバイスのみが使用できることに注意する必要があります。

Direct3DContentProvider.cpp

Direct3DContentProvider.cpp は、XAML エンジンと Windows Phone ランタイム コンポーネントのフックの低レベルの詳細を処理します。ほとんどの場合、ゲームを実装するためにこの動作を変更する必要はないので、この動作はこのクラス内にカプセル化されました。

表示: