ホーム
ゲーム開発
Unity
UnrealEngine
C++
ゲーム数学
ゲームAI
サウンド
アニメーション
GBDK
制作日記
3DCG
Houdini
Blender
USD
グラフィックス
テクノロジ
生成AI関連
動画制作
ツール開発
フロントエンド関連
サーバサイド関連
ソフトウェア設計
ハードウェア関連
おすすめ技術書
音楽
DTM
楽器・機材
ピアノ
その他
ブログについて
都会のエレキベア
ラーメン日記
四コマ漫画
おすすめアイテム
おもしろコラム
お問い合わせ
  • ゲーム開発
    • Unity
    • UnrealEngine
    • C++
    • ゲーム数学
    • ゲームAI
    • サウンド
    • アニメーション
    • GBDK
    • 制作日記
  • 3DCG
    • Houdini
    • Blender
    • USD
    • グラフィックス
  • テクノロジ
    • 生成AI関連
    • 動画制作
    • ツール開発
    • フロントエンド関連
    • サーバサイド関連
    • ソフトウェア設計
    • ハードウェア関連
    • おすすめ技術書
  • 音楽
    • DTM
    • 楽器・機材
    • ピアノ
  • その他
JP|EN
  1. ホーム
  2. 20221126_01

【DirextX12】第三回 DirextX12を使ったゲーム開発 〜座標変換と3Dオブジェクト表示〜

C++グラフィックスDirectX12
2022-11-27

マイケル
マイケル
みなさんこんにちは!
マイケルです!
エレキベア
エレキベア
こんにちクマ〜〜〜
マイケル
マイケル
今回は前回に引き続きDirectX12を触っていきます!
前回はテクスチャ描画まで行ったので、今回は 座標変換と3Dオブジェクトを描画するところまで 進めていこうと思います。

↑前回までの記事

エレキベア
エレキベア
ついに3Dオブジェクトも表示できるようになるクマね
マイケル
マイケル
今回は3Dモデルの読み込みは行わないけど、コードで書いた3Dのキューブを表示して簡単に動かせるところまで進めるから楽しくなってくると思うよ!
エレキベア
エレキベア
これまではマジで地味だったクマからね・・・
エレキベア
エレキベア
毎度お馴染みクマね
マイケル
マイケル
それじゃ早速進めていこう!!
なお今回作ったサンプルについてはGitHubに上げていますので、こちらもよければご参考ください!

GitHub/masarito617 – cpp-dx12-sample-3d
↑今回作ったサンプル

エレキベア
エレキベア
これもまたお馴染みクマね
マイケル
マイケル
また、実装方法については引き続き、下記の公式のサンプルと下記の書籍を参考にさせていただきました!
もっと詳しく知りたい方や理解を深めたい方は一読をおすすめします!

GitHub – microsoft / DirectX-Graphics-Samples
↑公式のサンプル

DirectX 12の魔導書 3Dレンダリングの基礎からMMDモデルを踊らせるまで

エレキベア
エレキベア
日本語の書籍はありがたいクマ〜〜〜

2Dポリゴンの位置をピクセル指定できるようにする

頂点座標の修正

マイケル
マイケル
まずは現在表示している2Dポリゴンの位置をピクセルで指定できるように修正してみます。
現状は下記のようにスクリーン座標を直で入力して指定しています。
		// 頂点定義
		Vertex vertices[] = {
			{{-0.4f,-0.7f, 0.0f}, {0.0f, 1.0f}} , //左下
			{{-0.4f, 0.7f, 0.0f}, {0.0f, 0.0f}} , //左上
			{{ 0.4f,-0.7f, 0.0f}, {1.0f, 1.0f}} , //右下
			{{ 0.4f, 0.7f, 0.0f}, {1.0f, 0.0f}} , //右上
		};
↑スクリーン座標を直接指定している
マイケル
マイケル
これを下記のようにピクセル位置で指定するようにして、正常に描画されるよう修正を進めていきます。
		// 100x100 で (0, 0) の位置
		Vertex vertices[] = {
			{{   0.0f, 100.0f, 0.0f }, { 0.0f, 1.0f }} , //左下
			{{   0.0f,   0.0f, 0.0f }, { 0.0f, 0.0f }} , //左上
			{{ 100.0f, 100.0f, 0.0f }, { 1.0f, 1.0f }} , //右下
			{{ 100.0f,   0.0f, 0.0f }, { 1.0f, 0.0f }} , //右上
		};
↑ピクセル位置で指定できるようする
エレキベア
エレキベア
確かに2Dオブジェクトはピクセル位置で指定できるようにした方が便利クマね
マイケル
マイケル
これができるようになれば、2DゲームやUIも作れるようになるはず!
張り切っていきましょう!!

頂点シェーダーの修正

マイケル
マイケル
このピクセル位置から最終的なスクリーン座標に変換するには、行列を用いた座標変換を行う方法が用いられます。
これについて詳しくは下記記事にまとめてありますので、こちらもご参考ください!
エレキベア
エレキベア
前はOpenGLとGLSLを使って座標変換したクマね
マイケル
マイケル
今回も下記のようにシェーダーに変換するための行列を渡して、オブジェクトの頂点座標と掛け合わせることで座標を変換します。
#include"BasicType.hlsli"
cbuffer cbuff0 : register(b0) {
	matrix mat; // 変換行列
}
BasicType BasicVS(float4 pos : POSITION, float2 uv : TEXCOORD)
{
	BasicType output;
	output.position = mul(mat, pos); // HLSLでは列優先
	output.uv = uv;
	return output;
}
↑行列を渡して座標変換を行う
エレキベア
エレキベア
シェーダーに変換するための行列を渡せばOKクマね

ディスクリプタテーブルの修正

マイケル
マイケル
行列を渡すには、定数バッファービュー(CBV)という形式で渡すことになります。
シェーダーリソースビューと同様、ディスクリプタテーブルに設定して渡す形式になるため、下記のようにインデックスを増やして設定します。
・・・
		// ルートパラメータの生成
		// ディスクリプタテーブルの実体
		CD3DX12_DESCRIPTOR_RANGE1 discriptorRanges[2];
		discriptorRanges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); // CBV
		discriptorRanges[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC); // SRV
		CD3DX12_ROOT_PARAMETER1 rootParameters[1];
		rootParameters[0].InitAsDescriptorTable(2, discriptorRanges, D3D12_SHADER_VISIBILITY_ALL); // 同一パラメータで2つ指定
・・・
↑ディスクリプタテーブルの生成処理を修正
マイケル
マイケル
今回はCBV->SRVの順で設定し、ルートパラメータは同一のものを指定しています。
頂点シェーダーからも見えるように、D3D12_SHADER_VISIBILITY_ALLで指定するようにしましょう!
エレキベア
エレキベア
こんな感じで配列のサイズを変えて設定するクマね

定数バッファービューの生成

マイケル
マイケル
そしてここからは実際に定数バッファーに変換行列を設定して渡すようにしていきます。
まずはディスクリプタヒープについてですが、これはシェーダーリソースビューで使用していたものを共用で使用して問題ありません。
そのため下記のように名前を変更して、サイズも2つ分取るよう修正しておきます。
・・・
	// ディスクリプタヒープの初期化
	{
		// レンダーターゲットビュー
		D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
		rtvHeapDesc.NumDescriptors = kFrameCount;
		rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
		rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
		ThrowIfFailed(device_->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(rtvHeap_.ReleaseAndGetAddressOf())));
		// 基本情報の受け渡し用
		D3D12_DESCRIPTOR_HEAP_DESC basicHeapDesc = {};
		basicHeapDesc.NumDescriptors = 2; // SRV + SBV
		basicHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
		basicHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
		ThrowIfFailed(device_->CreateDescriptorHeap(&basicHeapDesc, IID_PPV_ARGS(basicHeap_.ReleaseAndGetAddressOf())));
	}
・・・
↑ディスクリプタヒープはシェーダーリソースビューと共用するため名前とサイズを変える
エレキベア
エレキベア
ディスクリプタヒープはディスクリプタをまとめる役割だったクマね
マイケル
マイケル
そして次にDirectXに搭載されているDirectX::XMMATRIXを使用して行列を生成していくのですが、列優先、行優先でC++側とHLSL側で行列の扱いが異なってくるため注意が必要です。

参考(とても分かりやすい):
列優先(Column-major),行優先(Row-major)は複数ある – Qiita

マイケル
マイケル
行優先は左から右に乗算していき、列優先は右から左へ乗算します。
DirectX::XMMATRIXは行優先HLSLは列優先です。
エレキベア
エレキベア
OpenGLも確か列優先だったクマね
マイケル
マイケル
数学でも列優先表現を用いることが多いみたいだね。
とにもかくにも、乗算する順番が変わってくることには注意しよう!
実際に変換用の行列を作成している箇所は下記になります。
・・・
	// ディスクリプタヒープもハンドルを事前に取得
	auto basicHeapHandle = basicHeap_->GetCPUDescriptorHandleForHeapStart();
	// 定数バッファービューの生成
	{
		// 2D座標の変換行列を生成
		DirectX::XMMATRIX matrix = DirectX::XMMatrixIdentity();
		matrix.r[0].m128_f32[0] = 2.0f / windowWidth_;
		matrix.r[1].m128_f32[1] = -2.0f / windowHeight_;
		matrix.r[3].m128_f32[0] = -1.0f;
		matrix.r[3].m128_f32[1] = 1.0f;
		// 定数バッファーの生成
		auto constHeapProp = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
		auto constDesc = CD3DX12_RESOURCE_DESC::Buffer((sizeof(matrix) + 0xff) & ~0xff); // 256アライメントでサイズを指定
		ThrowIfFailed(device_->CreateCommittedResource(
			&constHeapProp,
			D3D12_HEAP_FLAG_NONE,
			&constDesc,
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(constBuffer_.ReleaseAndGetAddressOf())));
		// TODO Mapした行列はUnMapせずに保持しておけば後で変更できる
		// 定数情報のコピー
		DirectX::XMMATRIX* mapMatrix;
		constBuffer_->Map(0, nullptr, (void**)&mapMatrix);
		*mapMatrix = matrix;
		constBuffer_->Unmap(0, nullptr);
		// 定数バッファービューの生成
		D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
		cbvDesc.BufferLocation = constBuffer_->GetGPUVirtualAddress();
		cbvDesc.SizeInBytes = static_cast<UINT>(constBuffer_->GetDesc().Width);
		device_->CreateConstantBufferView(&cbvDesc, basicHeapHandle);
	}
	// ハンドルのポインタをオフセットする
	basicHeapHandle.ptr += device_->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
・・・
↑定数バッファーの生成
マイケル
マイケル
下記の2D用のビュー射影行列を作成して設定しています。
また、今回はディスクリプタヒープを共用で使用するため、事前にハンドルを取得しておき、設定したらポインタをオフセットする必要があることにも注意しましょう!


$$M_{srp} = \begin{pmatrix} \frac{2}{width} & 0 & 0 & -1 \\ 0 & \frac{2}{height} & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}$$
↑2D用ビュー射影行列

マイケル
マイケル
シェーダーリソースビューもオフセットした後のハンドルを指定して生成するよう修正しておきます。
・・・
		// シェーダーリソースビューの生成
		D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
		srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
		srvDesc.Format = textureDesc.Format;
		srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
		srvDesc.Texture2D.MipLevels = 1;
		device_->CreateShaderResourceView(textureBuffer_.Get(), &srvDesc, basicHeapHandle); // ★ハンドルをオフセットしたものに変更
・・・
↑シェーダーリソースビューの生成時に渡すハンドルはオフセットしたものにする
エレキベア
エレキベア
これで行列が渡せたクマね

実行!

マイケル
マイケル
それでは正常に変換されているか確認してみましょう!
実行して下記のように表示されれば成功です!
↑100×100、(0, 0)の位置で表示された
エレキベア
エレキベア
綺麗に表示できたクマね
マイケル
マイケル
このままだと小さすぎるのもあるので、大きさや座標位置も変えて確認してみましょう!
		// 600x400 で (50,100) の位置
		Vertex vertices[] = {
			{{  50.0f, 500.0f, 0.0f }, { 0.0f, 1.0f }} , //左下
			{{  50.0f, 100.0f, 0.0f }, { 0.0f, 0.0f }} , //左上
			{{ 650.0f, 500.0f, 0.0f }, { 1.0f, 1.0f }} , //右下
			{{ 650.0f, 100.0f, 0.0f }, { 1.0f, 0.0f }} , //右上
		};
↑位置と大きさを修正
↑問題なく指定できていそう
マイケル
マイケル
いい感じですね!!
エレキベア
エレキベア
これで2Dは完璧クマ〜〜〜

2Dポリゴンを3D空間上で動かす

3D座標の変換を行う

マイケル
マイケル
次はいよいよこの2Dプレーンを3Dオブジェクトとして描画してみます!
とはいえ、基本的に変換する行列を変えてあげるだけなので簡単です。
エレキベア
エレキベア
いよいよ3D空間に突入クマね
マイケル
マイケル
まずは頂点座標をピクセル位置ではなく、オブジェクトのローカル座標を想定して設定します。
		Vertex vertices[] = {
			{{ -1.0f, -1.0f, 0.0f }, { 0.0f, 1.0f }} , //左下
			{{ -1.0f,  1.0f, 0.0f }, { 0.0f, 0.0f }} , //左上
			{{  1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f }} , //右下
			{{  1.0f,  1.0f, 0.0f }, { 1.0f, 0.0f }} , //右上
		};
↑3Dオブジェクトのローカル座標の形式で設定
マイケル
マイケル
ここから変換用の行列を設定していきますが、3Dの場合は「ワールド座標」「ビュー座標」「射影座標」の3つの行列を使用して作成します。
こちらについても詳細は過去に書いた記事をご参照ください!
マイケル
マイケル
行優先の場合は、下記のように
ワールド座標 * ビュー座標 * 射影座標
でローカル座標を変換するための行列を作成することができます。

$$V’ = V * M_w * M_v * M_p$$
↑3Dの座標変換式

エレキベア
エレキベア
C++側ではそのまま掛ければいいわけクマね
マイケル
マイケル
ヘッダーファイルにも必要な行列を定義して、下記のように変換行列を作成して設定します。
出力結果が分かりやすいよう、少しだけ回転も入れています。
・・・
	// 3D座標変換用行列
	DirectX::XMMATRIX worldMatrix_;
	DirectX::XMMATRIX viewMatrix_;
	DirectX::XMMATRIX projMatrix_;
	DirectX::XMMATRIX* mapMatrix_;
	// オブジェクトのパラメータを想定
	float angle_ = 30.0f; // 30度
・・・
↑変換に必要な行列を定義
	// 定数バッファービューの生成
	{
		// 定数バッファーの生成
		auto constHeapProp = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
		auto constDesc = CD3DX12_RESOURCE_DESC::Buffer((sizeof(DirectX::XMMATRIX) + 0xff) & ~0xff); // 256アライメントでサイズを指定
		ThrowIfFailed(device_->CreateCommittedResource(
			&constHeapProp,
			D3D12_HEAP_FLAG_NONE,
			&constDesc,
			D3D12_RESOURCE_STATE_GENERIC_READ,
			nullptr,
			IID_PPV_ARGS(constBuffer_.ReleaseAndGetAddressOf())));
		// 定数バッファービューの生成
		D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
		cbvDesc.BufferLocation = constBuffer_->GetGPUVirtualAddress();
		cbvDesc.SizeInBytes = static_cast<UINT>(constBuffer_->GetDesc().Width);
		device_->CreateConstantBufferView(&cbvDesc, basicHeapHandle);
		// 3D座標用の行列を生成
		worldMatrix_ = DirectX::XMMatrixRotationY(angle_ * (DirectX::XM_PI / 180.0f));
		DirectX::XMFLOAT3 eye(0, 0, -5);
		DirectX::XMFLOAT3 target(0, 0, 0);
		DirectX::XMFLOAT3 up(0, 1, 0);
		viewMatrix_ = DirectX::XMMatrixLookAtLH(DirectX::XMLoadFloat3(&eye), DirectX::XMLoadFloat3(&target), DirectX::XMLoadFloat3(&up));
		projMatrix_ = DirectX::XMMatrixPerspectiveFovLH(
			DirectX::XM_PIDIV2, // 画角: 90度
			static_cast<float>(windowWidth_) / static_cast<float>(windowHeight_), // アスペクト比
			1.0f, // near
			10.0f // far
		);
		// 定数情報のコピー
		constBuffer_->Map(0, nullptr, (void**)&mapMatrix_);
		*mapMatrix_ = worldMatrix_ * viewMatrix_ * projMatrix_;
		constBuffer_->Unmap(0, nullptr);
	}
↑3D用の変換行列を設定する
マイケル
マイケル
以上で実装は完了です!!
エレキベア
エレキベア
行列の計算部分が理解できていれさえいれば簡単クマね

実行!

マイケル
マイケル
これを実行してみると、下記のように少し傾いたオブジェクトが描画されるはずです!
↑無事に描画された
エレキベア
エレキベア
小せえ・・・
マイケル
マイケル
これだと少し見にくいので、Scale値も追加で設定してみましょう!
	// オブジェクトのパラメータを想定
	float angle_ = 30 .0f;
	float scale_ = 3.0f; // ★追加
		// 3D座標用の行列を生成
		worldMatrix_ = DirectX::XMMatrixRotationY(angle_ * (DirectX::XM_PI / 180.0f)) * DirectX::XMMatrixScaling(scale_, scale_, 1.0f);
↑いい感じ!
エレキベア
エレキベア
大きさを変えるのも簡単になったクマね

回転させてみる

マイケル
マイケル
あとはせっかくなので、動作確認がてら動かして遊んでみましょう!
下記のようにUpdate内で回転角度を変更してみます。
// 更新処理
void DXApplication::OnUpdate()
{
	// 回転させてみる
	angle_ += 1.0f;
	worldMatrix_ = worldMatrix_ = DirectX::XMMatrixRotationY(angle_ * (DirectX::XM_PI / 180.0f));
	*mapMatrix_ = worldMatrix_ * viewMatrix_ * projMatrix_;
}
↑ようやくUpdateの使い道が出てきた
マイケル
マイケル
また、デフォルトだとカリングが効いて裏面が描画されないため、
ラスタライズステートにD3D12_CULL_MODE_NONEを指定して裏面も表示するよう変更しておきます。
・・・
		// 裏面描画にしてみる
		auto rasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
		rasterizerState.CullMode = D3D12_CULL_MODE_NONE;
		// パイプラインステートオブジェクト(PSO)を生成
		D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
		psoDesc.pRootSignature = rootsignature_.Get();
		psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; // 入力レイアウトの設定
		psoDesc.VS = CD3DX12_SHADER_BYTECODE(vsBlob.Get());                       // 頂点シェーダ
		psoDesc.PS = CD3DX12_SHADER_BYTECODE(psBlob.Get());                       // ピクセルシェーダ
		psoDesc.RasterizerState = rasterizerState;                                // ラスタライザーステート
		psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);                   // ブレンドステート
		psoDesc.SampleMask = D3D12_DEFAULT_SAMPLE_MASK;                           // サンプルマスクの設定
		psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;   // トポロジタイプ
		psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;    // ストリップ時のカット設定
		psoDesc.NumRenderTargets = 1;                                             // レンダーターゲット数
		psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;                       // レンダーターゲットフォーマット
		psoDesc.SampleDesc.Count = 1;                                             // マルチサンプリングの設定
		ThrowIfFailed(device_->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(pipelinestate_.ReleaseAndGetAddressOf())));
・・・
↑裏面も表示させる
エレキベア
エレキベア
段々ゲームエンジンを使ってる感覚に近づいてきたクマね

実行!

マイケル
マイケル
ここまで実装したところで実行!
下記のように回転すれば成功です!!
↑回転する適当な画像
エレキベア
エレキベア
こんな適当な絵なのに感動クマ・・・

3Dのキューブを描画して動かす

3Dキューブの座標を定義する

マイケル
マイケル
以上で座標変換の実装は完了なのですが、3D感がまだ薄いと思うので、
最後に3Dのキューブを描画して終わろうと思います!
エレキベア
エレキベア
待ってましたクマ〜〜〜
マイケル
マイケル
とはいえ頂点座標、インデックス座標と描画時のサイズ指定を変更するだけですね!
今回はインデックス座標は全振りで下記のように指定してみます。
・・・
		Vertex vertices[] = {
			// 前面
			{{ -1.0, -1.0,  1.0}, { 1.0f, 1.0f }} ,
			{{  1.0, -1.0,  1.0}, { 0.0f, 1.0f }} ,
			{{  1.0,  1.0,  1.0}, { 0.0f, 0.0f }} ,
			{{ -1.0,  1.0,  1.0}, { 1.0f, 0.0f }} ,
			// 背面
			{{ -1.0, -1.0, -1.0,}, { 1.0f, 1.0f }} ,
			{{ -1.0,  1.0, -1.0,}, { 0.0f, 1.0f }} ,
			{{  1.0,  1.0, -1.0,}, { 0.0f, 0.0f }} ,
			{{  1.0, -1.0, -1.0,}, { 1.0f, 0.0f }} ,
			// 上面
			{{ -1.0,  1.0, -1.0}, { 1.0f, 1.0f }} ,
			{{ -1.0,  1.0,  1.0}, { 0.0f, 1.0f }} ,
			{{  1.0,  1.0,  1.0}, { 0.0f, 0.0f }} ,
			{{  1.0,  1.0, -1.0}, { 1.0f, 0.0f }} ,
			// 底面
			{{ -1.0, -1.0, -1.0}, { 1.0f, 1.0f }} ,
			{{  1.0, -1.0, -1.0}, { 0.0f, 1.0f }} ,
			{{  1.0, -1.0,  1.0}, { 0.0f, 0.0f }} ,
			{{ -1.0, -1.0,  1.0}, { 1.0f, 0.0f }} ,
			// 右側面
			{{  1.0, -1.0, -1.0}, { 1.0f, 1.0f }} ,
			{{  1.0,  1.0, -1.0}, { 0.0f, 1.0f }} ,
			{{  1.0,  1.0,  1.0}, { 0.0f, 0.0f }} ,
			{{  1.0, -1.0,  1.0}, { 1.0f, 0.0f }} ,
			// 左側面
			{{ -1.0, -1.0, -1.0}, { 1.0f, 1.0f }} ,
			{{ -1.0, -1.0,  1.0}, { 0.0f, 1.0f }} ,
			{{ -1.0,  1.0,  1.0}, { 0.0f, 0.0f }} ,
			{{ -1.0,  1.0, -1.0}, { 1.0f, 0.0f }} ,
		};
・・・
		// インデックス定義
		unsigned short indices[] = {
			0,  1,  2,  0,  2,  3,  // 前面
			4,  5,  6,  4,  6,  7,  // 背面
			8,  9,  10, 8,  10, 11, // 上面
			12, 13, 14, 12, 14, 15, // 底面
			16, 17, 18, 16, 18, 19, // 右側面
			20, 21, 22, 20, 22, 23  // 左側面
		};
・・・
		// 描画処理の設定
		commandList_->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // プリミティブトポロジの設定 (三角ポリゴン)
		commandList_->IASetVertexBuffers(0, 1, &vertexBufferView_);                // 頂点バッファ
		commandList_->IASetIndexBuffer(&indexBufferView_);                         // インデックスバッファ
		commandList_->DrawIndexedInstanced(36, 1, 0, 0, 0); // ★インデックス座標の数に修正する
・・・
↑コードでキューブになるよう定義してみる
エレキベア
エレキベア
実際の3Dモデルもこんな感じで定義されているクマね

実行!

マイケル
マイケル
これで実行して下記のように描画されれば成功です!!
エレキベア
エレキベア
うおおお〜〜〜〜
やったクマ〜〜〜〜〜〜
マイケル
マイケル
回転方向を変えてみたりしても問題ないことが確認できます!!
エレキベア
エレキベア
適当な画像なのに感動クマ・・・

おわりに

マイケル
マイケル
というわけで今回は座標変換と3Dオブジェクトの描画でした!
どうだったかな??
エレキベア
エレキベア
3D描画できるとやっぱ嬉しいクマね〜〜
DirectXでゲーム開発するイメージも湧いてきたクマ
マイケル
マイケル
今回はコードで3Dキューブの座標を定義したけど、あとは3Dモデルのファイルから頂点座標やUV座標を読み込んで設定さえ出来れば自由にモデルも動かせそうだね!
その辺りは次回やってみようと思うからお楽しみに!!
エレキベア
エレキベア
楽しみクマ〜〜〜〜〜
マイケル
マイケル
それでは今日はこの辺で!!
アデューー!!
エレキベア
エレキベア
クマ〜〜〜〜〜〜

【DirextX12】第三回 DirextX12を使ったゲーム開発 〜座標変換と3Dオブジェクト表示〜 〜完〜

※次回の記事はこちら!

C++グラフィックスDirectX12
2022-11-27
記事をSNSで共有する
X
Facebook
LINE
はてなブックマーク
Pocket
LinkedIn
Reddit

著者の各種アカウント
フォローいただけると大変励みになります!

関連記事
【Three.js】カスタムシェーダーでトゥーン+背面法アウトラインを実装する
2026-02-15
【Three.js】Three.js入門 - シーン構築・モデル読み込み・ポストプロセスまで
2026-02-15
【Houdini21.0】3Dビル群っぽいブログヘッダー画像を作成する
2026-01-10
【Houdini21.0】Solaris徹底入門:USD構成を意識した基本的な作業フローについてまとめる
2025-12-31
【ゲーム数学】第十回 p5.js(+α)で学ぶゲーム数学「複素数とフラクタル」
2025-11-02
【プロシージャル】Pythonで学ぶ波動関数崩壊アルゴリズム(Wave Function Collapse)
2025-06-22
【UE5.5】Nanite、Lumen、VSMの概要についてまとめる
2025-05-12
【書籍紹介】「コンピュータグラフィックス」に出てくる用語をまとめる【CGエンジニア検定】
2024-07-13