33.Dx12版サンプルをDx11版に合わせて追加する(2)

今回は2つのDx12版サンプルをGitHubにアップしましたSimpleSample007,008です。
ドキュメントは申し訳ないですが、まだ記述してません。少しサンプルがたまった段階でアップします。

この記事は、
コミットSimplaSample005,006(Dx12版)追加。ライブラリ修正あり
から、
コミットSimplaSample007,008(Dx12版)追加。ライブラリ修正あり
の間の作業です。
GitHubサイト

https://github.com/WiZFramework/BaseCross

を参照して下さい。

今回はこれまでDx11版のみだったサンプルに、Dx12版を追加したものです。
ですので実行イメージは、Dx11版の同じサンプル番号と同じになります。

SimplaSample007のイメージ

2016082501

SimplaSample008のイメージ

2016082502

今回アップしたサンプルのポイントは頂点とサンプラーの変更です。
中央にある流れるスプライトが頂点の変更によって実装されています。また、背景の壁紙は、ラッピングサンプラーで表示されています。
いずれもDx12版では初めて出てきた表現です。

頂点の変更について

Dx12版における頂点の変更は、Dx11版のようにはいきません。Dx11版は、頂点バッファのポインタをマップしてそこにコピーしますが、Dx12版はそういった便利な機能がついているわけでないので、手作業になります。
とはいえ、シンプルバージョンであっても、ライブラリ側でユーティリティ関数を用意したので、それを使うとよいでしょう。
その関数はMeshResource::UpdateVirtex関数というテンプレート関数です。
内容は以下になります。


template<typename T>
void UpdateVirtex(const vector<T>& vertices) {
	if (!m_AccessWrite) {
		ThrowBaseException(
			L"このメッシュの頂点変更は許可されていません",
			L"if (!m_AccessWrite)",
			L"MeshResource::UpdateVirtex()"
		);
	}
	auto shptr = dynamic_pointer_cast< BackupData<T> >(m_BackupData);
	if (!shptr) {
		return;
	}
	if (shptr->m_Vertices.size() != vertices.size()) {
		return;
	}
	for (size_t i = 0; i < vertices.size();i++) {
		shptr->m_Vertices[i] = vertices[i];
	}
	m_DataRefresh = true;
}

この関数は、例えば変更する頂点がVertexPositionTexture型であればVertexPositionTexture型のvectorを作成して、以下のように記述します。m_SquareMeshはメッシュです。


	//メッシュの頂点の変更
	m_SquareMesh->UpdateVirtex(new_vertices);

のように呼び出せばよいのです。UpdateVirtex関数はテンプレート関数ですので、正式な記述は


	//メッシュの頂点の変更
	m_SquareMesh->UpdateVirtex<VertexPositionTexture>(new_vertices);

となりますが、型名は暗黙でコンパイラに伝わるので、省略できます。
さて、MeshResource::UpdateVirtex関数をよく読みますと、中にm_BackupDataというデータがあって、それにコピーしてるのがわかります。m_BackupDataはメッシュを作成するときに自動的に作成されるバックアップデータです。メッシュのリソースはこの内容をもとに初期化されます。
MeshResource::UpdateVirtex関数によってm_BackupDataが変更されると、m_DataRefresh = true;が呼び出されます。
このフラグはメッシュの内容が変更されたということを示しています。では、このフラグが立っているとどうなるか。
実は、描画時の操作によって、実際にリソースが更新されます。それを行っているのが、MeshResource::UpdateResources関数です。
この関数は引数にコマンドリストを持ちます。つまり、コマンドリストがないと、メッシュリソースの修正はできません。ですので描画時に修正します。
では、描画時はどのような記述になるかというと、VSPSDrawContextクラスDrawIndexed関数を見てみましょう。これもテンプレートになっていて、以下のような記述です。


template<typename Vertex>
void DrawIndexed(const shared_ptr<MeshResource>& Mesh) {
	ResetPipeLine();
	Mesh->UpdateResources<Vertex>(m_CommandList);
	UpdateShaderResource();
	DrawIndexedBase(Mesh);
}

この中でMesh->UpdateResources関数を呼び出しているのがわかります。つまり、ここで呼び出されたMeshResource::UpdateResources関数ではm_DataRefreshがtrueの場合だけ、リソースの更新を行います。
なぜこのような、回りくどい処理をするのか、ですが、MeshResource::UpdateResources関数の中身を追いかけていくと、リソースのコピーを行った時に、バリアというのを張っています。つまり他からアクセスできないように、バリアでアクセスを拒否します。
そのような処理を、例えばこのメッシュリソースを使いまわしする(例えばグループ処理)場合、毎回バリアを張っていたのでは時間がかかってしまいます。そのため、1ターンにおけるリソースの修正は1回きりと制限を設けているわけです。

サンプラーの変更について

サンプラーは、パイプラインステートが作成された直後は、SamplerState::LinearClampという設定になっています。これは、頂点のUV値に合わせて引き延ばす処理になるのでタイリング処理をするにはSamplerState::LinearWrapという内容にします。
WallSprite::OnCreate関数

	m_DrawContext->SetSamplerState(SamplerState::LinearWrap);

という呼び出しを行っています。この関数は、すでに作成されたサンプラーを指定のサンプラーに差し替える処理を行います。

それでは、今回はこの辺で。
次回もよろしくお願いします。

カテゴリー

ピックアップ記事

  1. 2016092201
    今回は前回のサンプルを少し機能を追加しまして、いろんなオブジェクトを追加しています。FullTuto…
  2. 2016092001
    前回更新から時間がたってしまいましたが、今回はフルバージョンチュートリアル003をアップしました。内…
  3. eyecatch
    前回更新から時間がたってしまいましたが、今回はフルバージョンチュートリアル002で懸案となっていまし…
PAGE TOP