DirectX12の魔導書という参考書での質問

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Sendou_Nanoha
記事: 4
登録日時: 3年前

DirectX12の魔導書という参考書での質問

#1

投稿記事 by Sendou_Nanoha » 3年前

現在、DirectX12の魔導書という参考書をやっているのですが
chapter8のマテリアルを張ることが出来ません
色は付くのですが参考書の通りではなく
ひかりの角度によって色が変わっているようです?

最後にコードを書いておくのですが
1131行目のcmdList->SetDescriptorHeaps(1, &materialDescHeap);
の一文をコメントアウトしないとモデルすら出ない状況です

なので問題はmaterialDescHeapを設定している部分かと思い
参考書記載のコードや、配布されているサンプルコードと見比べたのですが
何処が間違っているのか分かりませんでした。

環境は
Windows10
visualstudio2019
DirectXTexライブラリを使用しています

理解が足りず、具体的な質問にならないのが申し訳ありませんが
なにか、この問題に心当たりがある方はお助け下さい。

コード:

 
#include <Windows.h>
#include<tchar.h>
#include<d3d12.h>
#include<dxgi1_6.h>
#include<DirectXMath.h>
#include<vector>

#include<d3dcompiler.h>
#include <DirectXTex.h>
#ifdef _DEBUG
#include<iostream>
#endif

using namespace std;
using namespace DirectX;

// x84用のデータがないのか、x64でないとDirectXTexが動かない
#pragma comment(lib,"DirectXTex.lib")
#pragma comment(lib,"d3d12.lib")
#pragma comment(lib,"dxgi.lib")
#pragma comment(lib,"d3dcompiler.lib")

///@brief   コンソール画面にフォーマット付き文字列を表示
///@param   format フォーマット(%dとか%fとかの)
///@param   可変長引数
///@remarks この関数はデバッグ用です。デバッグ時にしか動作しません
void DebugOutputFormatString(const char* format, ...) 
{
#ifdef _DEBUG
	va_list valist;
	va_start(valist, format);
	vprintf(format, valist);
	va_end(valist);
#endif
}


// 面倒だけど書かなければいけない関数
LRESULT WindowProcedure(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 
{
	// ウィンドウが破棄されたら呼ばれます
	if (msg == WM_DESTROY) 
	{
		PostQuitMessage(0);	// OSに対して「もうこのアプリは終わるんや」と伝える
		return 0;
	}
	return DefWindowProc(hwnd, msg, wparam, lparam);	// 規定の処理を行う
}

const unsigned int window_width	 = 1280;
const unsigned int window_height = 720;

ID3D12Device* device = nullptr;
IDXGIFactory6* dxgiFactory = nullptr;
IDXGISwapChain4* swapchain = nullptr;
ID3D12CommandAllocator* cmdAllocator = nullptr;
ID3D12GraphicsCommandList* cmdList = nullptr;
ID3D12CommandQueue* cmdQueue = nullptr;

// デバックレイヤーを有効化する
void EnableDebugLayer()
{
	ID3D12Debug* debugLayer = nullptr;
	if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugLayer)))) 
	{
		debugLayer->EnableDebugLayer();	// デバックレイヤーを有効化する
		debugLayer->Release();			// 有効化したらインターフェースを解放する
	}
}

#ifdef _DEBUG
int main()
{
#else
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
#endif

	DebugOutputFormatString("Show window test.");
	// getchar();

	// ウィンドウクラスの生成&登録
	WNDCLASSEX w	= {};
	w.cbSize		= sizeof(WNDCLASSEX);
	w.lpfnWndProc	= (WNDPROC)WindowProcedure;	// コールバック関数の指定
	w.lpszClassName = _T("DX12Sample");			// アプリケーションクラス名(適当でいいです)
	w.hInstance		= GetModuleHandle(0);		// ハンドルの取得
	
	RegisterClassEx(&w);	// アプリケーションクラス(こういうの作るからよろしくってOSに予告する)

	RECT wrc = { 0,0, window_width, window_height };	// ウィンドウサイズを決める

	// 関数を使ってウィンドウのサイズを補正する
	AdjustWindowRect(&wrc, WS_OVERLAPPEDWINDOW, false);	// ウィンドウのサイズはちょっと面倒なので関数を使って補正する

	//ウィンドウオブジェクトの生成
	HWND hwnd = CreateWindow
	(
		w.lpszClassName,		// クラス名指定
		_T("DX12テスト"),		// タイトルバーの文字
		WS_OVERLAPPEDWINDOW,	// タイトルバーと境界線があるウィンドウです
		CW_USEDEFAULT,			// 表示X座標はOSにお任せします
		CW_USEDEFAULT,			// 表示Y座標はOSにお任せします
		wrc.right  - wrc.left,	// ウィンドウ幅
		wrc.bottom - wrc.top,	// ウィンドウ高
		nullptr,				// 親ウィンドウハンドル
		nullptr,				// メニューハンドル
		w.hInstance,			// 呼び出しアプリケーションハンドル
		nullptr					// 追加パラメータ
	);

#ifdef _DEBUG
	//デバッグレイヤーをオンに
	//デバイス生成時前にやっておかないと、デバイス生成後にやると
	//デバイスがロスとしてしまうので注意
	EnableDebugLayer();
#endif

	//DirectX12まわり初期化
	//フィーチャレベル列挙
	D3D_FEATURE_LEVEL levels[] = 
	{
		D3D_FEATURE_LEVEL_12_1,
		D3D_FEATURE_LEVEL_12_0,
		D3D_FEATURE_LEVEL_11_1,
		D3D_FEATURE_LEVEL_11_0,
	};

	// DXGIのエラーメッセージを取得できるようにする
#ifdef _DEBUG
	CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(&dxgiFactory));
#else
	CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
#endif // _DEBUG

	auto result = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));

	// アダプター列挙用
	std::vector <IDXGIAdapter*> adapters;

	// ここに特定の名前を持つアダプターオブジェクトが入る
	IDXGIAdapter* tmpAdapter = nullptr;

	for (int i = 0; dxgiFactory->EnumAdapters(i, &tmpAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
	{
		adapters.push_back(tmpAdapter);
	}

	for (auto adpt : adapters) 
	{
		DXGI_ADAPTER_DESC adesc = {};
		adpt->GetDesc(&adesc);		// アダプターの説明オブジェクト取得
		
		std::wstring strDesc = adesc.Description;

		// 探したいアダプターの名前を確認
		if (strDesc.find(L"NVIDIA") != std::string::npos) 
		{
			tmpAdapter = adpt;
			break;
		}
	}


	// Direct3Dデバイスの初期化
	D3D_FEATURE_LEVEL featureLevel;
	for (auto l : levels) 
	{
		if (D3D12CreateDevice(nullptr, l, IID_PPV_ARGS(&device)) == S_OK)
		{
			featureLevel = l;
			break;	// 生成可能なバージョンが見つかったらループを打ち切り
		}
	}

	result = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAllocator));
	result = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAllocator, nullptr, IID_PPV_ARGS(&cmdList));

	// コマンドキュー
	D3D12_COMMAND_QUEUE_DESC cmdQueueDesc = {};
	cmdQueueDesc.Flags		= D3D12_COMMAND_QUEUE_FLAG_NONE;		// タイムアウトなし
	cmdQueueDesc.NodeMask	= 0;									// アダプターを一つしか使わない場合は0
	cmdQueueDesc.Priority	= D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;	// プライオリティ特に指定なし
	cmdQueueDesc.Type		= D3D12_COMMAND_LIST_TYPE_DIRECT;		// ここはコマンドリストと合わせる
	//コマンドキュー生成
	result = device->CreateCommandQueue(&cmdQueueDesc, IID_PPV_ARGS(&cmdQueue));

	// スワップチェイン
	DXGI_SWAP_CHAIN_DESC1 swapchainDesc = {};
	swapchainDesc.Width					= window_width;								// 画面解像度(幅)
	swapchainDesc.Height				= window_height;							// 画面解像度(高)
	swapchainDesc.Format				= DXGI_FORMAT_R8G8B8A8_UNORM;				// ピクセルフォーマット
	swapchainDesc.Stereo				= false;									// ステレオ表示フラグ
	swapchainDesc.SampleDesc.Count		= 1;										// マルチサンプルの指定
	swapchainDesc.SampleDesc.Quality	= 0;										// マルチサンプルの指定
	swapchainDesc.BufferUsage			= DXGI_USAGE_BACK_BUFFER;					// これで流用可
	swapchainDesc.BufferCount			= 2;										// ダブルバッファなら2でよい
	swapchainDesc.Scaling				= DXGI_SCALING_STRETCH;						// これでバックバッファは伸び縮み可能
	swapchainDesc.SwapEffect			= DXGI_SWAP_EFFECT_FLIP_DISCARD;			// フリップ後は速やかに破棄
	swapchainDesc.AlphaMode				= DXGI_ALPHA_MODE_UNSPECIFIED;				// 特になし
	swapchainDesc.Flags					= DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;	// ウィンドウ⇔フルスクリーン

	result = dxgiFactory->CreateSwapChainForHwnd
	(
		cmdQueue,						// コマンドキューオブジェクト
		hwnd,							// ウィンドウハンドル
		&swapchainDesc,					// スワップチェーン設定
		nullptr,						// ひとまず無視
		nullptr,						// ひとまず無視
		(IDXGISwapChain1**)&swapchain	// スワップチェインオブジェクト取得用
	);

	// ディスクリプタヒープの作成(Direct12魔導書:P81)
	D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
	heapDesc.Type			= D3D12_DESCRIPTOR_HEAP_TYPE_RTV;	// レンダーターゲットビューなのでRTV
	heapDesc.NodeMask		= 0;								// 複数のGPUがある場合に識別を行う為のビットフラグ
	heapDesc.NumDescriptors = 2;								// 表裏の2つ
	heapDesc.Flags			= D3D12_DESCRIPTOR_HEAP_FLAG_NONE;	// 特に指定なし

	ID3D12DescriptorHeap* rtvHeaps = nullptr;
	result = device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&rtvHeaps));
	// ここまでで「ビュー用のメモリを確保しただけ状態」

	// スワップチェインとメモリを紐付ける
	DXGI_SWAP_CHAIN_DESC swcDesc = {};
	result = swapchain->GetDesc(&swcDesc);
	std::vector<ID3D12Resource*> backBuffers(swcDesc.BufferCount);
	D3D12_CPU_DESCRIPTOR_HANDLE handle = rtvHeaps->GetCPUDescriptorHandleForHeapStart();

	// ガンマ補正に対応する
	// SRGBレンダーターゲットビューの設定
	D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
	rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;	// ガンマ補正あり(sRGB)
	rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;

	for (size_t i = 0; i < swcDesc.BufferCount; ++i) 
	{
		result = swapchain->GetBuffer(static_cast<UINT>(i), IID_PPV_ARGS(&backBuffers[i]));
		device->CreateRenderTargetView
		(
			backBuffers[i],	// バッファ―
			&rtvDesc, 		// 今回はnullptr
			handle			// ディスクリプタヒープハンドル
		);
		handle.ptr += device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
	}

	// 深度バッファの作成
	// 深度バッファの仕様
	D3D12_RESOURCE_DESC depthResDesc = {};
	depthResDesc.Dimension			= D3D12_RESOURCE_DIMENSION_TEXTURE2D;		// 2次元のテクスチャデータ
	depthResDesc.Width				= window_width;								// 幅と高さはレンダーターゲットと同じ
	depthResDesc.Height				= window_height;							// 上に同じ
	depthResDesc.DepthOrArraySize	= 1;										// テクスチャ配列でもないし3Dテクスチャでもない
	depthResDesc.Format				= DXGI_FORMAT_D32_FLOAT;					// 深度値書き込み用フォーマット
	depthResDesc.SampleDesc.Count	= 1;										// サンプルは1ピクセル当たり1つ
	depthResDesc.Flags				= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;	// 深度ステンシルとして使用
	
	depthResDesc.MipLevels			= 1;
	depthResDesc.Layout				= D3D12_TEXTURE_LAYOUT_UNKNOWN;
	depthResDesc.Alignment			= 0;

	// 深度値用ヒーププロパティ
	D3D12_HEAP_PROPERTIES depthHeapProp = {};
	depthHeapProp.Type					= D3D12_HEAP_TYPE_DEFAULT;			// DEFAULTだから後はUNKNOWNでよし
	depthHeapProp.CPUPageProperty		= D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
	depthHeapProp.MemoryPoolPreference	= D3D12_MEMORY_POOL_UNKNOWN;

	//このクリアバリューが重要な意味を持つ
	D3D12_CLEAR_VALUE depthClearValue = {};
	depthClearValue.DepthStencil.Depth	= 1.0f;					 // 深さ1(最大値)でクリア
	depthClearValue.Format				= DXGI_FORMAT_D32_FLOAT; // 32bit深度値としてクリア

	ID3D12Resource* depthBuffer = nullptr;
	result = device->CreateCommittedResource
	(
		&depthHeapProp,
		D3D12_HEAP_FLAG_NONE,
		&depthResDesc,
		D3D12_RESOURCE_STATE_DEPTH_WRITE, // デプス書き込みに使用
		&depthClearValue,
		IID_PPV_ARGS(&depthBuffer)
	);

	// 深度バッファビューの作成
	// 深度のためのデスクリプタヒープ作成
	D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};					// 深度に使う、それだけわかってろ。らしい
	dsvHeapDesc.NumDescriptors	= 1;								// 深度ビュー1つのみ
	dsvHeapDesc.Type			= D3D12_DESCRIPTOR_HEAP_TYPE_DSV;	// デプスステンシルビューとして使う
	//dsvHeapDesc.Flags			= D3D12_DESCRIPTOR_HEAP_FLAG_NONE;

	ID3D12DescriptorHeap* dsvHeap = nullptr;
	result = device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&dsvHeap));

	// 深度ビュー作成
	D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
	dsvDesc.Format			= DXGI_FORMAT_D32_FLOAT;			// デプス値に32bit使用
	dsvDesc.ViewDimension	= D3D12_DSV_DIMENSION_TEXTURE2D;	// 2Dテクスチャ
	dsvDesc.Flags			= D3D12_DSV_FLAG_NONE;				// フラグは特になし
	device->CreateDepthStencilView
	(
		depthBuffer,								  // ID3D12Resourceオブジェクトへのポインタ。
		&dsvDesc, 									  // D3D12_DEPTH_STENCIL_VIEW_DESC構造体へのポインター。
		dsvHeap->GetCPUDescriptorHandleForHeapStart()  
	);

	ID3D12Fence* fence = nullptr;
	UINT64 fenceVal = 0;
	result = device->CreateFence(fenceVal, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));


	// ウィンドウ表示
	ShowWindow(hwnd, SW_SHOW);

	//XMFLOAT3 vertices[] =
	//{
	//	//{ -1.0f, -1.0f, 0.0f },	// 左下
	//	//{ -1.0f,  1.0f, 0.0f },	// 左上
	//	//{  1.0f, -1.0f, 0.0f }	// 右下

	//	//{ -0.5f, -0.7f, 0.0f },	// 左下
	//	//{ -0.0f,  0.7f, 0.0f },	// 左上
	//	//{  0.5f, -0.7f, 0.0f }	// 右下

	//	{ -0.4f, -0.7f, 0.0f },	// 左下	: インデックス0
	//	{ -0.4f,  0.7f, 0.0f },	// 左上 : インデックス1
	//	{  0.4f, -0.7f, 0.0f },	// 右下 : インデックス2
	//	{  0.4f,  0.7f, 0.0f }	// 右上 : インデックス3
	//};

	//struct Vertex
	//{
	//	XMFLOAT3 pos;	// XYZ座標
	//	XMFLOAT2 uv;	// UV座標
	//};

	//Vertex vertices[] =
	//{
	//	 // 初期位置
	//	{ {-0.5f,-0.9f, 0.0f} ,{ 0.0f, 1.0f} }, // 左下
	//	{ {-0.5f, 0.9f, 0.0f} ,{ 0.0f, 0.0f} }, // 左上
	//	{ { 0.5f,-0.9f, 0.0f} ,{ 1.0f, 1.0f} }, // 右下
	//	{ { 0.5f, 0.9f, 0.0f} ,{ 1.0f, 0.0f} }, // 右上

	//	 // 左上
	//	{ {   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} }, // 右上

	//	 //3D化初期値
	//	{ {-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} }, // 右上
	//};

	// PMDヘッダ構造体
	struct PMDHeader 
	{
		float version;		 // 例:00 00 80 3F == 1.00
		char model_name[20]; // モデル名
		char comment[256];	 // モデルコメント
	};

	FILE* fp;
	PMDHeader pmdheader = {};
	char signature[3];	// シグネチャ
	
	auto err = fopen_s(&fp, "初音ミク.pmd", "rb");

	fread(signature, sizeof(signature), 1, fp);
	fread(&pmdheader, sizeof(pmdheader), 1, fp);

	// PMD頂点構造体
	struct PMDVertex
	{
		XMFLOAT3 pos;				// 頂点座標  :12バイト
		XMFLOAT3 normal;			// 法線ベクトル:12バイト
		XMFLOAT2 uv;				// UV座標   :8バイト
		unsigned short boneNo[2];	// ボーン番号 :4バイト
		unsigned char boneWeight;	// ボーン影響度:1バイト
		unsigned char edgeFlg;		// 輪郭線フラグ:1バイト
	}; // 合計38バイト:パディングされて40バイトにされズレが生じる可能性がある(今回は大丈夫らしい)

	// 頂点全て読み込む
	unsigned int vertNum; // 総頂点数
	fread(&vertNum, sizeof(vertNum), 1, fp);

#pragma pack(1) // ここから1バイトパッキング:アライメントは発生しない
	//PMDマテリアル構造体
	struct PMDMaterial
	{
		XMFLOAT3 diffuse;		// ディフューズ色
		float alpha;			// ディフューズα
		float specularity;		// スペキュラの強さ(乗算値)
		XMFLOAT3 specular;		// スペキュラ色
		XMFLOAT3 ambient;		// アンビエント色
		unsigned char toonIdx;	// トゥーン番号(後述)
		unsigned char edgeFlg;	// マテリアル毎の輪郭線フラグ

		//2バイトのパディングが発生!!

		unsigned int indicesNum; // このマテリアルが割り当たるインデックス数
		char texFilePath[20];	 // テクスチャファイル名(プラスアルファ…後述)
	};
	// 70バイトのはず…でもパディングが発生するため72バイト
	// #pragma packを使用することで、70バイトで定義
#pragma pack() // 1バイトパッキング解除

	// シェーダ側に投げられるマテリアルデータ
	struct MaterialForHlsl
	{
		XMFLOAT3 diffuse;	// ディフューズ色
		float alpha;		// ディフューズα
		XMFLOAT3 specular;	// スペキュラ色
		float specularity;	// スペキュラの強さ(乗算値)
		XMFLOAT3 ambient;	// アンビエント色
	};

	// それ以外のマテリアルデータ
	struct AdditionalMaterial
	{
		std::string texPath;// テクスチャファイルパス
		int toonIdx;		// トゥーン番号
		bool edgeFlg;		// マテリアル毎の輪郭線フラグ
	};

	//まとめたもの
	struct Material
	{
		unsigned int indicesNum;	// インデックス数
		MaterialForHlsl material;
		AdditionalMaterial additional;
	};

	constexpr unsigned int pmdvertex_size = 38;						// 頂点1つあたりのサイズ
	std::vector<unsigned char> vertices(vertNum * pmdvertex_size);	// バッファ確保
	fread(vertices.data(), vertices.size(), 1, fp);					// 一気に読み込み

	unsigned int indicesNum;//インデックス数
	fread(&indicesNum, sizeof(indicesNum), 1, fp);

	// リソース設定構造体
	D3D12_HEAP_PROPERTIES heapprop = {};
	heapprop.Type				   = D3D12_HEAP_TYPE_UPLOAD;			// ヒープの種別(mapする必要があるならUPLOAD)
	heapprop.CPUPageProperty	   = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;	// CPUのページング設定
	heapprop.MemoryPoolPreference  = D3D12_MEMORY_POOL_UNKNOWN;			// メモリプールが何処かを示す

	D3D12_RESOURCE_DESC resdesc = {};
	resdesc.Dimension			= D3D12_RESOURCE_DIMENSION_BUFFER;	// バッファに使うのでBUFFERを指定 
	resdesc.Width				= vertices.size();					// 幅で全部まかなうのでsizeof(全頂点)とする
	resdesc.Height				= 1;								// 幅で表現しているので1
	resdesc.DepthOrArraySize	= 1;								// 1でヨシ(らしい)
	resdesc.MipLevels			= 1;								// 1でヨシ(らしい)
	resdesc.Format				= DXGI_FORMAT_UNKNOWN;				// 画像ではないのでUNKNOWN
	resdesc.SampleDesc.Count	= 1;								// SampleDesc.Count= 1;とする(?)
	resdesc.Flags				= D3D12_RESOURCE_FLAG_NONE;			// NONEでヨシ
	resdesc.Layout				= D3D12_TEXTURE_LAYOUT_ROW_MAJOR;	// D3D12_TEXTURE_LAYOUT_ROW_MAJOR(P112を参照)

	//UPLOAD(確保は可能)
	ID3D12Resource* vertBuff = nullptr;

	result = device->CreateCommittedResource
	(
		&heapprop,							// ヒープ設定構造体のアドレス
		D3D12_HEAP_FLAG_NONE,				// 特に指定がない場合D3D12_HEAP_FLAG_NONEでよい(てか大概指定はない)
		&resdesc,							// リソース設定構造体のアドレス
		D3D12_RESOURCE_STATE_GENERIC_READ,	// GPU側からは読み取り専用なのでGENERIC_READ
		nullptr,							// 使わないのでnullptr
		IID_PPV_ARGS(&vertBuff)				// IID_PPV_ARGSにいまだ慣れない
	);

	// 頂点情報のコピー(マップ)
	//XMFLOAT3* vertMap = nullptr;
	unsigned char* vertMap = nullptr;
	result = vertBuff->Map(0, nullptr, (void**)&vertMap);
	std::copy(std::begin(vertices), std::end(vertices), vertMap);	// 書き込み
	vertBuff->Unmap(0, nullptr);	// マップ解除命令

	// 頂点バッファビューの作成
	D3D12_VERTEX_BUFFER_VIEW vbView = {};
	vbView.BufferLocation	= vertBuff->GetGPUVirtualAddress();	  // バッファの仮想アドレス
	vbView.SizeInBytes		= static_cast<UINT>(vertices.size()); // 全バイト数
	vbView.StrideInBytes	= pmdvertex_size;					  // 1頂点あたりのバイト数

	std::vector<unsigned short> indices(indicesNum);
	fread(indices.data(), indices.size() * sizeof(indices[0]), 1, fp);

	// PMDモデルのマテリアルを読み込む
	unsigned int materialNum;	// マテリアル数
	fread(&materialNum, sizeof(materialNum), 1, fp);

	//	転送用のデータ作成
	std::vector<Material> materials(materialNum);

	std::vector<PMDMaterial> pmdMaterials(materialNum);
	fread(pmdMaterials.data(), pmdMaterials.size() * sizeof(PMDMaterial), 1, fp);	// 一気に読み込む

	for (int i = 0; i < pmdMaterials.size(); ++i) 
	{
		materials[i].indicesNum				= pmdMaterials[i].indicesNum;
		materials[i].material.diffuse		= pmdMaterials[i].diffuse;
		materials[i].material.alpha			= pmdMaterials[i].alpha;
		materials[i].material.specular		= pmdMaterials[i].specular;
		materials[i].material.specularity	= pmdMaterials[i].specularity;
		materials[i].material.ambient		= pmdMaterials[i].ambient;
		//materials[i].additional.toonIdx		= pmdMaterials[i].toonIdx;
	}

	fclose(fp);

	// インデックスの実装
	// 頂点3っがセットの時計回り
	//unsigned short indices[] = { 0,1,2, 2,1,3 };

	ID3D12Resource* idxBuff = nullptr;
	
	//設定は、バッファのサイズ以外頂点バッファの設定を使いまわしてOKのはず
	resdesc.Width = indices.size() * sizeof(indices[0]);
	result = device->CreateCommittedResource
	(
		&heapprop,
		D3D12_HEAP_FLAG_NONE,
		&resdesc,
		D3D12_RESOURCE_STATE_GENERIC_READ,
		nullptr,
		IID_PPV_ARGS(&idxBuff)
	);

	//作ったバッファにインデックスデータをコピー
	unsigned short* mappedIdx = nullptr;
	idxBuff->Map(0, nullptr, (void**)&mappedIdx);
	std::copy(std::begin(indices), std::end(indices), mappedIdx);
	idxBuff->Unmap(0, nullptr);

	//インデックスバッファビューを作成
	D3D12_INDEX_BUFFER_VIEW ibView = {};
	ibView.BufferLocation	= idxBuff->GetGPUVirtualAddress();
	ibView.Format			= DXGI_FORMAT_R16_UINT;
	ibView.SizeInBytes		= static_cast<UINT>(indices.size() * sizeof(indices[0]));

	//マテリアルバッファを作成
	auto materialBuffSize = sizeof(MaterialForHlsl);
	materialBuffSize = (materialBuffSize + 0xff) & ~0xff;
	
	ID3D12Resource* materialBuff = nullptr;

	// ここのresdescとheappropを設定し直す必要がありそう?

	resdesc.Width = materialBuffSize * materialNum;
	result = device->CreateCommittedResource
	(
		&heapprop,
		D3D12_HEAP_FLAG_NONE,
		&resdesc,	//勿体ないけど仕方ないですね
		D3D12_RESOURCE_STATE_GENERIC_READ,
		nullptr,
		IID_PPV_ARGS(&materialBuff)
	);

	// マップマテリアルにコピー
	char* mapMaterial = nullptr;
	
	result = materialBuff->Map(0, nullptr, (void**)&mapMaterial);
	
	for (auto& m : materials) 
	{
		// アライメントサイズに違いがあるので、かなり強制的なキャストをしている
		*((MaterialForHlsl*)mapMaterial) = m.material;	// データコピー
		mapMaterial += materialBuffSize;				// 次のアライメント位置まで進める
	}
	materialBuff->Unmap(0, nullptr);
	
	// マテリアル用ディスクリプタヒープの作成
	ID3D12DescriptorHeap* materialDescHeap = nullptr;
	D3D12_DESCRIPTOR_HEAP_DESC materialDescHeapDesc = {};
	materialDescHeapDesc.NumDescriptors = materialNum;	// マテリアル数ぶん(定数1つ、テクスチャ3つ)
	materialDescHeapDesc.Flags			= D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
	materialDescHeapDesc.NodeMask		= 0;
	materialDescHeapDesc.Type			= D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;	// デスクリプタヒープ種別
	
	result = device->CreateDescriptorHeap(&materialDescHeapDesc, IID_PPV_ARGS(&materialDescHeap));//生成

	D3D12_CONSTANT_BUFFER_VIEW_DESC matCBVDesc = {};
	matCBVDesc.BufferLocation = materialBuff->GetGPUVirtualAddress();	// バッファアドレス
	matCBVDesc.SizeInBytes	  = static_cast<UINT>(materialBuffSize);	// マテリアルの256アライメントサイズ

	// 先頭を記録
	auto matDescHeapH = materialDescHeap->GetCPUDescriptorHandleForHeapStart();

	for (size_t i = 0; i < materialNum; i++)
	{
		device->CreateConstantBufferView(&matCBVDesc, matDescHeapH);
		matDescHeapH.ptr += device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
		matCBVDesc.BufferLocation += materialBuffSize;
	}

	ID3DBlob* vsBlob = nullptr;
	ID3DBlob* psBlob = nullptr;

	ID3DBlob* errorBlob = nullptr;
	result = D3DCompileFromFile
	(
		L"BaiscVertexShader.hlsl",							// シェーダー名
		nullptr,											// defineはなし
		D3D_COMPILE_STANDARD_FILE_INCLUDE,					// インクルードはデフォルト
		"BasicVS", "vs_5_0",								// 関数はBasicVS、対象シェーダーはvs_5_0
		D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,	// デバック用および最適化なし
		0,													// エフェクトコンパイルオプション(0推奨)
		&vsBlob,											// 受け取る為のポインタのアドレス
		&errorBlob											// エラー時はerrorBlobにメッセージが入る
	);
	if (FAILED(result))
	{
		if (result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
		{
			::OutputDebugStringA("VSファイルが見当たりません");
		}
		else
		{
			std::string errstr;
			errstr.resize(errorBlob->GetBufferSize());
			std::copy_n((char*)errorBlob->GetBufferPointer(), errorBlob->GetBufferSize(), errstr.begin());
			errstr += "\n";
			OutputDebugStringA(errstr.c_str());
		}
		exit(1);	// 行儀悪い、らしい
	}

	result = D3DCompileFromFile
	(
		L"BasicPixelShader.hlsl",							// シェーダー名
		nullptr,											// defineはなし
		D3D_COMPILE_STANDARD_FILE_INCLUDE,					// インクルードはデフォルト
		"BasicPS", "ps_5_0",								// 関数はBasicVS、対象シェーダーはvs_5_0
		D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,	// デバック用および最適化なし
		0,													// エフェクトコンパイルオプション(0推奨)
		&psBlob,											// 受け取る為のポインタのアドレス
		&errorBlob											// エラー時はerrorBlobにメッセージが入る
	);
	if (FAILED(result))
	{
		if (result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
		{
			::OutputDebugStringA("PSファイルが見当たりません");
		}
		else
		{
			std::string errstr;
			errstr.resize(errorBlob->GetBufferSize());
			std::copy_n((char*)errorBlob->GetBufferPointer(), errorBlob->GetBufferSize(), errstr.begin());
			errstr += "\n";
			OutputDebugStringA(errstr.c_str());
		}
		exit(1);
	}

	// 頂点レイアウト
	D3D12_INPUT_ELEMENT_DESC inputLayout[] =
	{
		{
			"POSITION",									// セマンティック名 
			0,											// 同じセマンティクス名の時に使うインデックス
			DXGI_FORMAT_R32G32B32_FLOAT, 				// フォーマット(要素数とビット数で型を現す)
			0, 											// 入力スロットインデックス
			D3D12_APPEND_ALIGNED_ELEMENT, 				// データのオフセット位置
			D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,	// 
			0 											// 一度に描画するインスタンスの数
		},

		{
			"NORMAL",
			0,
			DXGI_FORMAT_R32G32_FLOAT,
			0,
			D3D12_APPEND_ALIGNED_ELEMENT,
			D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
			0
		},

		{
			"TEXCOORD",
			0,
			DXGI_FORMAT_R32G32_FLOAT,
			0,
			D3D12_APPEND_ALIGNED_ELEMENT,
			D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
			0
		},

		{
			"BONE_NO",
			0,
			DXGI_FORMAT_R16G16_UINT,
			0,
			D3D12_APPEND_ALIGNED_ELEMENT,
			D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
			0
		},

		{
			"WEIGHT",
			0,
			DXGI_FORMAT_R8_UINT,
			0,
			D3D12_APPEND_ALIGNED_ELEMENT,
			D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
			0
		},

		{
			"EDGE_FLG",
			0,
			DXGI_FORMAT_R8_UINT,
			0,
			D3D12_APPEND_ALIGNED_ELEMENT,
			D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA,
			0
		},
	};
すみません、コードが長すぎたので二回に分けようかと思います

Sendou_Nanoha
記事: 4
登録日時: 3年前

Re: DirectX12の魔導書という参考書での質問

#2

投稿記事 by Sendou_Nanoha » 3年前

続きです

コード:

 
	// グラフィックパイプラインステートの作成
	// シェーダーのセット
	D3D12_GRAPHICS_PIPELINE_STATE_DESC gpipeline = {};

	gpipeline.pRootSignature = nullptr;		// あとで設定する

	gpipeline.VS.pShaderBytecode = vsBlob->GetBufferPointer();	// 頂点シェーダーデータを含むメモリブロックへのポインタ
	gpipeline.VS.BytecodeLength	 = vsBlob->GetBufferSize();		// 頂点シェーダーデータのサイズ
	gpipeline.PS.pShaderBytecode = psBlob->GetBufferPointer();	// ピクセルシェーダーデータを含むメモリブロックへのポインタ
	gpipeline.PS.BytecodeLength  = psBlob->GetBufferSize();		// ピクセルシェーダーデータのサイズ

	// サンプルマスクとラスタライザステートの設定
	// デフォルトのサンプルマスクを現す定数(0xffffffff)
	gpipeline.SampleMask = D3D12_DEFAULT_SAMPLE_MASK;

	// ブレンドステートの設定
	gpipeline.BlendState.AlphaToCoverageEnable  = false;
	gpipeline.BlendState.IndependentBlendEnable = false;

	D3D12_RENDER_TARGET_BLEND_DESC renderTargetBlendDesc = {};

	// ひとまず加算や乗算やαブレンディングは使用しない
	renderTargetBlendDesc.BlendEnable			= false;
	renderTargetBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
	// ひとまず論理演算は使用しない
	renderTargetBlendDesc.LogicOpEnable = false;

	gpipeline.BlendState.RenderTarget[0] = renderTargetBlendDesc;

	// ラスタライザの構造体内容説明
	// https://docs.microsoft.com/ja-jp/windows/win32/api/d3d12/ns-d3d12-d3d12_rasterizer_desc
	// まだアンチエイリアスは使わない為 false
	gpipeline.RasterizerState.MultisampleEnable = false;

	gpipeline.RasterizerState.CullMode		  = D3D12_CULL_MODE_NONE;	// カリングしない
	gpipeline.RasterizerState.FillMode		  = D3D12_FILL_MODE_SOLID;	// 中身を塗りつぶす
	gpipeline.RasterizerState.DepthClipEnable = true;					// 深度方向のクリッピングは有効に

	// TODO:01 ラスタライザステート自己追加部分
	gpipeline.RasterizerState.FrontCounterClockwise = false;
	gpipeline.RasterizerState.DepthBias				= D3D12_DEFAULT_DEPTH_BIAS;
	gpipeline.RasterizerState.DepthBiasClamp		= D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
	gpipeline.RasterizerState.SlopeScaledDepthBias	= D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
	gpipeline.RasterizerState.AntialiasedLineEnable = false;
	gpipeline.RasterizerState.ForcedSampleCount		= 0;
	gpipeline.RasterizerState.ConservativeRaster	= D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;

	gpipeline.DepthStencilState.DepthEnable    = true;						 // 深度バッファを使う
	gpipeline.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; // 書き込む
	gpipeline.DepthStencilState.DepthFunc	   = D3D12_COMPARISON_FUNC_LESS; // 深度値が小さいほうを採用
	gpipeline.DepthStencilState.StencilEnable  = false;						 // あとで

	gpipeline.DSVFormat = DXGI_FORMAT_D32_FLOAT;	// 32ビットfloatを深度値として使用

	// 入力レイアウトの設定
	gpipeline.InputLayout.pInputElementDescs = inputLayout;
	gpipeline.InputLayout.NumElements		 = _countof(inputLayout);

	gpipeline.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;	// カット無し

	// PrimitiveTopologyType(三角形で構成)
	gpipeline.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;   // 三角形で構成

	// レンダーターゲットの設定
	gpipeline.NumRenderTargets = 1;								//今は1つのみ
	gpipeline.RTVFormats[0]	   = DXGI_FORMAT_R8G8B8A8_UNORM;	//0~1に正規化されたRGBA

	// アンチエイリアシングの為のサンプル数設定(4章時点ではやらない)
	gpipeline.SampleDesc.Count   = 1;	// サンプリングは1ピクセルにつき1
	gpipeline.SampleDesc.Quality = 0;	// クオリティは最低

	// ルートシグネチャ
	ID3D12RootSignature* rootsignature = nullptr;

	// ルートシグネチャにスロットとテクスチャの関連を記述する
	// 空のルートシグネチャを作成(頂点だけ流して表示するだけの処理なので空で良い)
	D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
	rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;	// 頂点情報が(入力アセンブラ)があるという意味
	
	D3D12_DESCRIPTOR_RANGE descTblRange[2] = {};
	descTblRange[0].NumDescriptors						= 1;								// テクスチャひとつ
	descTblRange[0].RangeType							= D3D12_DESCRIPTOR_RANGE_TYPE_CBV;	// 種別はテクスチャ
	descTblRange[0].BaseShaderRegister					= 0;								// 0番スロットから
	descTblRange[0].OffsetInDescriptorsFromTableStart	= D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

	descTblRange[1].NumDescriptors						= 1;								// テクスチャひとつ
	descTblRange[1].RangeType							= D3D12_DESCRIPTOR_RANGE_TYPE_CBV;	// 種別はテクスチャ
	descTblRange[1].BaseShaderRegister					= 1;								// 1番スロットから
	descTblRange[1].OffsetInDescriptorsFromTableStart	= D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

	D3D12_ROOT_PARAMETER rootparam[2] = {};
	rootparam[0].ParameterType							= D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
	rootparam[0].DescriptorTable.pDescriptorRanges		= &descTblRange[0];				// デスクリプタレンジのアドレス
	rootparam[0].DescriptorTable.NumDescriptorRanges	= 1;							// デスクリプタレンジ数
	rootparam[0].ShaderVisibility						= D3D12_SHADER_VISIBILITY_ALL;	// 全てのシェーダから見える

	rootparam[1].ParameterType							= D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
	rootparam[1].DescriptorTable.pDescriptorRanges		= &descTblRange[1];				// デスクリプタレンジのアドレス
	rootparam[1].DescriptorTable.NumDescriptorRanges	= 1;							// デスクリプタレンジ数
	rootparam[1].ShaderVisibility						= D3D12_SHADER_VISIBILITY_ALL;	// 全てのシェーダから見える

	rootSignatureDesc.pParameters	= rootparam;	// ルートパラメータの先頭アドレス
	rootSignatureDesc.NumParameters = 2;			// ルートパラメータ数

	D3D12_STATIC_SAMPLER_DESC samplerDesc = {};
	samplerDesc.AddressU		 = D3D12_TEXTURE_ADDRESS_MODE_WRAP;				// 横繰り返し
	samplerDesc.AddressV		 = D3D12_TEXTURE_ADDRESS_MODE_WRAP;				// 縦繰り返し
	samplerDesc.AddressW		 = D3D12_TEXTURE_ADDRESS_MODE_WRAP;				// 奥行繰り返し
	samplerDesc.BorderColor		 = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;	// ボーダーの時は黒
	samplerDesc.Filter			 = D3D12_FILTER_MIN_MAG_MIP_POINT;				// 補間しない(ニアレストネイバー)
	samplerDesc.MaxLOD			 = D3D12_FLOAT32_MAX;							// ミップマップ最大値
	samplerDesc.MinLOD			 = 0.0f;										// ミップマップ最小値
	samplerDesc.ComparisonFunc	 = D3D12_COMPARISON_FUNC_NEVER;					// オーバーサンプリングの際リサンプリングしない?
	samplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;				// ピクセルシェーダからのみ可視

	rootSignatureDesc.pStaticSamplers	= &samplerDesc;
	rootSignatureDesc.NumStaticSamplers = 1;

	// バイナリコードの作成
	ID3DBlob* rootSigBlob = nullptr;
	result = D3D12SerializeRootSignature
	(
		&rootSignatureDesc,				// ルートシグネチャ設定
		D3D_ROOT_SIGNATURE_VERSION_1_0, // ルートシグネチャバージョン
		&rootSigBlob, 					// シェーダーを作った時と同じ TODO:01参照
		&errorBlob						// エラー処理も同様
	);

	// ルートシグネチャオブジェクトの作成
	result = device->CreateRootSignature
	(
		0,
		rootSigBlob->GetBufferPointer(),
		rootSigBlob->GetBufferSize(),
		IID_PPV_ARGS(&rootsignature)
	);

	// 使い終わったので解放
	rootSigBlob->Release();

	gpipeline.pRootSignature = rootsignature;
	
	// グラフィックパイプラインステートオブジェクトの生成
	ID3D12PipelineState* pipelinestate = nullptr;
	result = device->CreateGraphicsPipelineState
	(
		&gpipeline,						// D3D12_GRAPHICS_PIPELINE_STATE_DESC構造体のポインタ
		IID_PPV_ARGS(&pipelinestate)	// ID3D12PipelineStateインターフェイスへのポインターを受け取るメモリブロック
	);

	D3D12_VIEWPORT viewport = {};
	viewport.Width		= window_width;		// 出力先の幅(ピクセル数)
	viewport.Height		= window_height;	// 出力先の高さ(ピクセル数)
	viewport.TopLeftX	= 0;				// 出力先の左上座標X
	viewport.TopLeftY	= 0;				// 出力先の左上座標Y
	viewport.MaxDepth	= 1.0f;				// 深度最大値
	viewport.MinDepth	= 0.0f;				// 深度最小値

	D3D12_RECT scissorrect = {};
	scissorrect.top		= 0;								//切り抜き上座標
	scissorrect.left	= 0;								//切り抜き左座標
	scissorrect.right	= scissorrect.left + window_width;	//切り抜き右座標
	scissorrect.bottom	= scissorrect.top  + window_height;	//切り抜き下座標

	//WICテクスチャのロード
	TexMetadata metadata = {};
	ScratchImage scratchImg = {};
	result = LoadFromWICFile(L"img/kuroko.png", WIC_FLAGS_NONE, &metadata, scratchImg);
	auto img = scratchImg.GetImage(0, 0, 0);	// 生データ抽出

	//ノイズテクスチャの作成
	struct TexRGBA 
	{
		unsigned char R, G, B, A;
	};
	std::vector<TexRGBA> texturedata(256 * 256);

	for (auto& rgba : texturedata) 
	{
		rgba.R = rand() % 256;
		rgba.G = rand() % 256;
		rgba.B = rand() % 256;
		rgba.A = 255;	// アルファは1.0とする。
	}

	//WriteToSubresourceで転送する用のヒープ設定
	D3D12_HEAP_PROPERTIES texHeapProp = {};
	texHeapProp.Type				 = D3D12_HEAP_TYPE_CUSTOM;				// 特殊な設定なのでdefaultでもuploadでもなく
	texHeapProp.CPUPageProperty		 = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;	// ライトバックで
	texHeapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;				// 転送がL0つまりCPU側から直で
	texHeapProp.CreationNodeMask	 = 0;									// 単一アダプタのため0
	texHeapProp.VisibleNodeMask		 = 0;									// 単一アダプタのため0

	D3D12_RESOURCE_DESC resDesc = {};
	resDesc.Format				= metadata.format;											 // RGBAフォーマット
	resDesc.Width				= static_cast<UINT>(metadata.width);						 // 幅
	resDesc.Height				= static_cast<UINT>(metadata.height);						 // 高さ
	resDesc.DepthOrArraySize	= static_cast<uint16_t>(metadata.arraySize);				 // 2Dで配列でもないので1
	resDesc.SampleDesc.Count	= 1;														 // 通常テクスチャなのでアンチェリしない
	resDesc.SampleDesc.Quality	= 0;														 //
	resDesc.MipLevels			= static_cast<uint16_t>(metadata.mipLevels);				 // ミップマップしないのでミップ数は1つ
	resDesc.Dimension			= static_cast<D3D12_RESOURCE_DIMENSION>(metadata.dimension); // 2Dテクスチャ用
	resDesc.Layout				= D3D12_TEXTURE_LAYOUT_UNKNOWN;								 // レイアウトについては決定しない
	resDesc.Flags				= D3D12_RESOURCE_FLAG_NONE;									 // とくにフラグなし

	ID3D12Resource* texbuff = nullptr;
	result = device->CreateCommittedResource
	(
		&texHeapProp,
		D3D12_HEAP_FLAG_NONE, // 特に指定なし
		&resDesc,
		D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, // テクスチャ用(ピクセルシェーダから見る用)
		nullptr,
		IID_PPV_ARGS(&texbuff)
	);

	result = texbuff->WriteToSubresource
	(
		0,									// サブリソースインデックス
		nullptr,							// 書き込み領域の指定			 :全領域へコピー
		img->pixels,						// 書き込みたいデータアドレス	 :元データアドレス
		static_cast<UINT>(img->rowPitch),   // 1行当たりのデータサイズ		 :1ラインサイズ
		static_cast<UINT>(img->slicePitch)	// スライス当たりのデータサイズ  :全サイズ
	);

	//XMMATRIX matrix = XMMatrixIdentity();

	//シェーダ側に渡すための基本的な行列データ
	struct MatricesData 
	{
		XMMATRIX world;		// モデルを回転させたり移動させたりする行列
		XMMATRIX viewproj;	// ビューとプロジェクションの合成行列
	};

	//matrix.r[0].m128_f32[0] =  2.0f / window_width;
	//matrix.r[1].m128_f32[1] = -2.0f / window_height;
	
	//matrix.r[3].m128_f32[0] = -1.0f;
	//matrix.r[3].m128_f32[1] =  1.0f;

	//定数バッファ作成
	auto worldMat = XMMatrixRotationY(XM_PIDIV4);

	XMFLOAT3 eye(0, 10, -15);
	XMFLOAT3 target(0, 10, 0);
	XMFLOAT3 up(0, 1, 0);

	XMMATRIX viewMat = XMMatrixLookAtLH
	(
		XMLoadFloat3(&eye),		// 視点座標
		XMLoadFloat3(&target),	// 注視点座標
		XMLoadFloat3(&up)		// 上ベクトル
	);

	// プロジェクション行列
	XMMATRIX projMat = XMMatrixPerspectiveFovLH
	(
		XM_PIDIV2,						       // 画角は90°
		static_cast<float>(window_width)
		/ static_cast<float>(window_height),   // アスペクト比
		1.0f,								   // 近い方
		100.0f								   // 遠い方
	);

	ID3D12Resource* constBuff = nullptr;

	resdesc.Width = (sizeof(MatricesData) + 0xff) & ~0xff;

	device->CreateCommittedResource
	(
		&heapprop,
		D3D12_HEAP_FLAG_NONE,
		&resdesc,
		D3D12_RESOURCE_STATE_GENERIC_READ,
		nullptr,
		IID_PPV_ARGS(&constBuff)
	);

	//// マップによる定数のコピー
	//XMMATRIX* mapMatrix;	// マップ先を示すポインタ
	//result = constBuff->Map(0, nullptr, (void**)&mapMatrix);	// マップ
	//*mapMatrix = worldMat * viewMat * projMat;	// 行列の内容をコピー

	MatricesData* mapMatrix;	// マップ先を示すポインタ
	
	result = constBuff->Map(0, nullptr, (void**)&mapMatrix);	// マップ
	
	//行列の内容をコピー
	mapMatrix->world = worldMat;
	mapMatrix->viewproj = viewMat * projMat;

	ID3D12DescriptorHeap* basicDescHeap = nullptr;
	D3D12_DESCRIPTOR_HEAP_DESC descHeapDesc = {};
	descHeapDesc.Flags			= D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; // シェーダから見えるように
	descHeapDesc.NodeMask		= 0;										 // マスクは0
	descHeapDesc.NumDescriptors = 2;										 // ビューは今のところ1つだけ
	descHeapDesc.Type			= D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;	 // シェーダリソースビュー(および定数、UAVも)
	result = device->CreateDescriptorHeap(&descHeapDesc, IID_PPV_ARGS(&basicDescHeap));//生成

	//通常テクスチャビュー作成
	D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
	srvDesc.Format					= metadata.format;							// RGBA(0.0f~1.0fに正規化)
	srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;	// 後述
	srvDesc.ViewDimension			= D3D12_SRV_DIMENSION_TEXTURE2D;			// 2Dテクスチャ
	srvDesc.Texture2D.MipLevels		= 1;										// ミップマップは使用しないので1

	//デスクリプタの先頭ハンドルを取得しておく
	auto basicHeapHandle = basicDescHeap->GetCPUDescriptorHandleForHeapStart();

	device->CreateShaderResourceView
	(
		texbuff,		// ビューと関連付けるバッファ
		&srvDesc,		// 先ほど設定したテクスチャ設定情報
		basicHeapHandle	// ヒープのどこに割り当てるか
	);

	// 次の場所に移動
	//basicHeapHandle.ptr += device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

	D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
	cbvDesc.BufferLocation = constBuff->GetGPUVirtualAddress();
	cbvDesc.SizeInBytes = static_cast<UINT>(constBuff->GetDesc().Width);

	//定数バッファビューの作成
	device->CreateConstantBufferView(&cbvDesc, basicHeapHandle);

	MSG msg = {};
	float angle = 0.0f;
	while (true)
	{
		if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		//もうアプリケーションが終わるって時にmessageがWM_QUITになる
		if (msg.message == WM_QUIT) { break; }

		//worldMat = XMMatrixRotationY(angle);
		//*mapMatrix = worldMat * viewMat * projMat;

		worldMat = XMMatrixRotationY(angle);
		mapMatrix->world = worldMat;
		mapMatrix->viewproj = viewMat * projMat;

		if (GetAsyncKeyState(VK_LEFT )) { angle += 0.03f; }
		if (GetAsyncKeyState(VK_RIGHT)) { angle -= 0.03f; }

		//DirectX処理
		//バックバッファのインデックスを取得
		auto bbIdx = swapchain->GetCurrentBackBufferIndex();

		D3D12_RESOURCE_BARRIER BarrierDesc = {};
		BarrierDesc.Type					= D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;	// 遷移
		BarrierDesc.Flags					= D3D12_RESOURCE_BARRIER_FLAG_NONE;			// 特になし
		BarrierDesc.Transition.pResource	= backBuffers[bbIdx];						// バックバッファリソース
		BarrierDesc.Transition.Subresource	= D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;	// D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
		BarrierDesc.Transition.StateBefore	= D3D12_RESOURCE_STATE_PRESENT;				// 直前はPRESENT状態
		BarrierDesc.Transition.StateAfter	= D3D12_RESOURCE_STATE_RENDER_TARGET;		// 今からレンダーターゲット状態
		cmdList->ResourceBarrier(1, &BarrierDesc);										// バリア指定実行

		cmdList->SetPipelineState(pipelinestate);

		// ハンドルのアドレス(P87参照):イマイチわかってない
		auto rtvH = rtvHeaps->GetCPUDescriptorHandleForHeapStart();
		rtvH.ptr += static_cast<ULONG_PTR>(bbIdx * device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
		auto dsvH = dsvHeap->GetCPUDescriptorHandleForHeapStart();

		cmdList->OMSetRenderTargets
		(
			1,		// レンダーターゲット数(今は1つしか使ってない)
			&rtvH, 	// レンダーターゲットハンドルの先頭アドレス
			false, 	// 複数時に連続しているかどうか(マルチレンダーターゲットも際に使用)
			&dsvH	// 深度ステンシルバッファビューのハンドル(基本nullptrでよい)
		);

		// 画面クリア
		float clearColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // 黄色

		cmdList->ClearRenderTargetView(rtvH, clearColor, 0, nullptr);

		cmdList->ClearDepthStencilView
		(
			dsvH,					// デプスステンシルビューのハンドル
			D3D12_CLEAR_FLAG_DEPTH, // クリア先の指定
			1.0f,					// デプスクリア時の値
			0,						// ステンシルクリア時の値
			0,						// 「クリア範囲」の配列サイズ
			nullptr					// 「クリア範囲」配列
		);

		cmdList->RSSetViewports(1, &viewport);
		cmdList->RSSetScissorRects(1, &scissorrect);

		cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
		cmdList->IASetVertexBuffers(0, 1, &vbView);	// 頂点情報セット
		cmdList->IASetIndexBuffer(&ibView);

		cmdList->SetGraphicsRootSignature(rootsignature);

		//WVP変換行列
		cmdList->SetDescriptorHeaps(1, &basicDescHeap);
		cmdList->SetGraphicsRootDescriptorTable(0, basicDescHeap->GetGPUDescriptorHandleForHeapStart());

		//auto heapHandle = basicDescHeap->GetGPUDescriptorHandleForHeapStart();
		//heapHandle.ptr += device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
		//cmdList->SetGraphicsRootDescriptorTable(1, heapHandle);

		cmdList->SetDescriptorHeaps(1, &materialDescHeap);

		auto materialH = materialDescHeap->GetGPUDescriptorHandleForHeapStart();
		unsigned int idxOffset = 0;	// 最初はオフセットなし

		for (auto m : materials)
		{
			cmdList->SetGraphicsRootDescriptorTable(1, materialH);
			
			cmdList->DrawIndexedInstanced(m.indicesNum, 1, idxOffset, 0, 0);
			
			// ヒープポインターとインデックスを次に進める
			materialH.ptr += device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
			
			idxOffset += m.indicesNum;
		}


		//cmdList->DrawInstanced(vertNum, 1, 0, 0);
		//cmdList->DrawIndexedInstanced(indicesNum, 1, 0, 0, 0);

		BarrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
		BarrierDesc.Transition.StateAfter  = D3D12_RESOURCE_STATE_PRESENT;

		//命令のクローズ
		cmdList->Close();

		
		//コマンドリストの実行
		ID3D12CommandList* cmdlists[] = { cmdList };
		cmdQueue->ExecuteCommandLists(1, cmdlists);

		cmdQueue->Signal
		(
			fence,		// 先ほど作ったフェンスオブジェクト
			++fenceVal	// GPUの処理が完了した後になっているべき値(フェンス値)
		);

		// ビジループ
		while (fence->GetCompletedValue() != fenceVal) { ; }
		// プロセスの条件が成り立つかどうかを定期的にチェックする手法の一つ
		// なお、最近のPCはプロセッサ速度が、それぞれで異なる為、遅延時間が不正確であまり使用されない
		// 今回は説明のためにあえて使用しているらしい(イマイチわかっていない)
		// wiki調べ

		if (fence->GetCompletedValue() != fenceVal) 
		{
			// イベントハンドルの所得
			auto event = CreateEvent(nullptr, false, false, nullptr);
			
			fence->SetEventOnCompletion(fenceVal, event);
			
			// イベントが発生するまで持ち続ける
			WaitForSingleObject(event, INFINITE);

			// イベントハンドルを閉じる
			CloseHandle(event);
		}
		//フリップ
		swapchain->Present(0, 0);

		cmdAllocator->Reset();//キューをクリア
		cmdList->Reset(cmdAllocator, nullptr);//再びコマンドリストをためる準備

	}

	// もうクラスは使わないので登録解除する
	UnregisterClass(w.lpszClassName, w.hInstance);

	return 0;
}
 
どこが間違っているのか
ちゃんと見当も付けられずの質問ですみません。

アバター
あたっしゅ
記事: 663
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: DirectX12の魔導書という参考書での質問

#3

投稿記事 by あたっしゅ » 3年前

東上☆海美☆「
 魔導書買ったみみ。DirectX Tex をインストールしたところで止まっているみみ。

 グラボ(グラフィックボード)が対象外の可能性ありみみ。
使っているグラボを明記の事みみ。

 自分のは NVIDIA Geforce GTX 1070 Ti みみ。RTX の PC は、電源が不安定で、修理に出すつもりみみ。

 グラフィックスの本や資料での”あるある”として、
筆者の PC/グラボ/DirectX の版 では動くが、
他の PC/グラボ/DirectX の版で必要な初期化が抜けているので動かないとかみみ。

 だから、みんなで情報交換しましょうみみ。
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

Sendou_Nanoha
記事: 4
登録日時: 3年前

Re: DirectX12の魔導書という参考書での質問

#4

投稿記事 by Sendou_Nanoha » 3年前

返信ありがとうございます。
自分のグラフィックボードは、Intel(R) UHD Graphics630 だと思います
DirectX診断ツールのディスプレイから確認したのですが
見るとこ間違えてたら、すみません

アバター
あたっしゅ
記事: 663
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: DirectX12の魔導書という参考書での質問

#5

投稿記事 by あたっしゅ » 3年前

東上☆海美☆「
 魔導書の動作環境(はじめに p.Vi)は

NVIDIA GeForce GTX 1080
NVIDIA GeForce GTX 980

って書いてあるから、Intel 系だと、動かないことがあるかも。

 グラボをいっぱい持ってる奴は、プログラム組まずに、3D ベンチマークばかり。
 プログラムやる奴のグラボは、何故か貧弱。
というか、貧弱なグラボをなんとかしようとして、プログラミングに手を出すのか ?

 2/14(日)に、日本で、メガデモのイベントあったとは...
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

Sendou_Nanoha
記事: 4
登録日時: 3年前

Re: DirectX12の魔導書という参考書での質問

#6

投稿記事 by Sendou_Nanoha » 3年前

グラボの問題ですか
環境を変えるか何か、プログラム外の解決策も考えてみます
返信、ありがとうございました。
何か、進展がありましたら、また、報告させていただきます

fufuri

Re: DirectX12の魔導書という参考書での質問

#7

投稿記事 by fufuri » 2年前

同書のサンプルプログラムでは、D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV の
デスクリプタヒープを「座標変換用」と「マテリアル用」の2つ作成しており、
それぞれに対して SetDescriptorHeaps() を呼び出して、2つが同時に機能することを
想定しているようです。

確かに nVidia では問題なく動作したのですが、Intel HD ではだめでした。
SetDescriptorHeaps() のヘルプに下の特記があります。
 Only one descriptor heap of each type can be set at one time,
 which means a maximum of 2 heaps (one sampler, one CBV/SRV/UAV) can be set at one time.

これに従って、「座標変換」と「マテリアル」を1つのデスクリプタテーブルに
まとめるようにしたところ、私の手元では動作しました。

fufuri

Re: DirectX12の魔導書という参考書での質問

#8

投稿記事 by fufuri » 2年前

上の返信、「1つのデスクリプタヒープにまとめる」です。
失礼しました。

アバター
あたっしゅ
記事: 663
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: DirectX12の魔導書という参考書での質問

#9

投稿記事 by あたっしゅ » 2年前

東上☆海美☆「
ご報告、ありがとうございますみみ。
自分の魔導書習得は、停滞中みみ。
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

返信

“C言語何でも質問掲示板” へ戻る