공부/DirectX12

DirectX 인덱스 버퍼 버그 해결

ayuriK152 2025. 3. 23. 19:24

 어떤 버그인지는 바로 전 포스트에 정리해 뒀으니 이쪽을 참고하면 될 듯 하고..

https://ayurik152.tistory.com/13

 

DirectX12 인덱스 버퍼 데이터 버그 디버깅 중..

정말 골치아픈 버그가 생겼고, 지금 얘 때문에 2주 정도 진전이 없다. 코드상에 문제가 전혀 없어보이기 때문인데다 PIX를 사용한 런타임 디버깅을 얼마 전에 알았기 때문이다.  지금 엔진 테스

ayurik152.tistory.com

 

 웃기게도 포스트를 올리고 1시간쯤 더 코드를 리뷰하다가 원인을 발견했다. 이전에 엔진에서 바로 사용할 수 있도록 기본적인 도형들을 만들어둔다고 했었는데.. 얘네도 당연히 메시니까 버퍼를 만들어줘야한다.

void ResourceManager::CreateDefaultResources()
{
	//==========Shader==========
	D3D_SHADER_MACRO skinnedDefines[] =
	{
		"SKINNED", "1", NULL, NULL
	};

	auto stdVS = make_shared<Shader>(L"Default.hlsl", nullptr, ShaderType::VS);
	Add<Shader>(L"standardVS", stdVS);
	auto skinnedVS = make_shared<Shader>(L"Default.hlsl", skinnedDefines, ShaderType::VS);
	Add<Shader>(L"skinnedVS", skinnedVS);
	auto opaquePS = make_shared<Shader>(L"Default.hlsl", nullptr, ShaderType::PS);
	Add<Shader>(L"opaquePS", opaquePS);


	//==========Texture==========
	auto tex = make_shared<Texture>(L"white1x1.dds");
	Add<Texture>(L"Tex_Default", tex);


	//==========Material==========
	auto defaultMat = make_shared<Material>("Default", 0, 0, -1);
	Add<Material>(L"Mat_Default", defaultMat);


	//==========Mesh==========
	shared_ptr<Mesh> boxMesh = make_shared<Mesh>();
	boxMesh->CreateBasicCube();
	Add<Mesh>(L"Mesh_BasicBox", boxMesh);

	shared_ptr<Mesh> sphereMesh = make_shared<Mesh>();
	sphereMesh->CreateBasicSphere();
	Add<Mesh>(L"Mesh_BasicSphere", sphereMesh);

	shared_ptr<Mesh> quadMesh = make_shared<Mesh>();
	quadMesh->CreateBasicQuad();
	Add<Mesh>(L"Mesh_BasicQuad", quadMesh);
}

 

 이게 엔진에서 기본적으로 준비해두는 리소스들이다. 여기서 마지막 Mesh 주석 이후의 세 가지가 기본 도형들의 메시 데이터 생성부인데 저 CreateBasic~~() 메소드들을 조금 자세히 들여다보자.

void Mesh::CreateBasicCube()
{
	CreateBasicCube(1.5f, 1.5f, 1.5f, 3);
}

void Mesh::CreateBasicCube(float width, float height, float depth, UINT numSubdivisions)
{
	shared_ptr<Geometry> geo = GeometryGenerator::CreateBox(width, height, depth, numSubdivisions);
	shared_ptr<SubMesh> subMesh = make_shared<SubMesh>(geo);
	subMesh->CreateBuffer();
	_submeshes.push_back(subMesh);
}

void Mesh::CreateBasicSphere()
{
	return CreateBasicSphere(1.0f, 3);
}

void Mesh::CreateBasicSphere(float radius, UINT numSubdivisions)
{
	shared_ptr<Geometry> geo = GeometryGenerator::CreateGeosphere(radius, numSubdivisions);
	shared_ptr<SubMesh> subMesh = make_shared<SubMesh>(geo);
	subMesh->CreateBuffer();
	_submeshes.push_back(subMesh);
}

void Mesh::CreateBasicQuad()
{
	shared_ptr<Geometry> geo = GeometryGenerator::CreateQuad();
	shared_ptr<SubMesh> subMesh = make_shared<SubMesh>(geo);
	subMesh->CreateBuffer();
	_submeshes.push_back(subMesh);
}

 

 대강 이런식이다. 오버로드를 통해서 오브젝트의 수치를 정할건지 프리셋을 따를건지 고를 수 있도록 구현해뒀는데, 지금 중요한건 그게 아니다. 각 메소드를 살펴보면 두번째 줄에서 서브메시를 생성하고 그 다음 줄에서 버퍼를 생성하고 있다. 얘네도 메시니까 당연히 버퍼를 생성해줘야되는게 맞다. 근데 난 저 코드들을 보고 순간 번쩍이면서 생각난 것이 있다. 난 외부 리소스를 불러들였을 때 수동으로 버퍼를 만들어 준 적이 없는데?

 

SubMesh 클래스의 생성자를 한 번 살펴보도록 하자.

SubMesh::SubMesh()
{
	_material = RESOURCE->Get<Material>(L"Mat_Default");
}

SubMesh::SubMesh(shared_ptr<Geometry> geo) : _geometry(geo)
{
	_material = RESOURCE->Get<Material>(L"Mat_Default");
	CreateBuffer();
}

 

 생성자에 기하구조를 파라미터로 넘겨서 서브메시를 생성하는 경우 CreateBuffer()를 수행해서 자체적으로 버퍼를 만들고 있음을 알 수 있다. 뭐야 그럼 기본도형들은 버퍼를 두번 중복해서 생성하는거네,,,? 이걸 알자마자 수동으로 버퍼를 만들어주던 코드를 주석처리했고, 문제는 말끔히 사라졌다.

드디어 글리치가 사라진 미유

 

 혹시 몰라서 기본도형 메시를 여러개 생성해서 검증도 해봤지만 문제는 없었다. 드디어 이 지옥같은 디버깅이 끝났다.. 해방감도 느껴지지만 한편으로는 터무니없는 이유라 좀 허무하기도 하다,, 얼른 SkinnedMesh를 구현하도록 하자.