• 티스토리 홈
  • 프로필사진
    유니얼
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
유니얼
  • 프로필사진
    유니얼
    • 분류 전체보기 (295)
      • Unity (17)
        • 게임 개발 (5)
      • Unreal (24)
        • 게임 개발 (20)
      • DirectX (36)
      • 코딩테스트 (91)
        • 프로그래머스 (25)
        • 백준 (66)
      • Google Workspace (1)
      • Programing (102)
        • C# (68)
        • C++ (24)
        • JavaScript (10)
      • 게임 서버 프로그래밍 (17)
      • Web (6)
        • 슈퍼코딩 (6)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
    등록된 댓글이 없습니다.
  • 최근 공지
    등록된 공지가 없습니다.
# Home
# 공지사항
#
# 태그
# 검색결과
# 방명록
  • [DirectX11] ResourceManager
    2024년 03월 04일
    • 유니얼
    • 작성자
    • 2024.03.04.:35
    728x90

    DirectX 11로 게임 엔진 아키텍처 만들기

    이번 블로그 글에서는 ResourceManager와 Resource관리에 대해 알아보고자 합니다. 특히, DirectX 11을 사용하여 텍스처, 메시, 셰이더와 같은 자원들을 효율적으로 관리하는 것을 구현하는 것을 목표로 만들었습니다. 이를 위해 ResourceManager 구현 방법과 함께, ResourceBase와ResourceManager 의 역할과 구현 방법에 대해 상세히 다루어, 게임의 구조를 보다 효율적으로 관리하는 방법을 탐구할 예정입니다.

     

    Result

    참고강의 링크:

    https://www.inflearn.com/course/directx11-%EA%B2%8C%EC%9E%84%EA%B0%9C%EB%B0%9C-%EB%8F%84%EC%95%BD%EB%B0%98/dashboard

     

    [게임 프로그래머 도약반] DirectX11 입문 강의 - 인프런

    게임 프로그래머 공부에 있어서 필수적인 DirectX 11 지식을 초보자들의 눈높이에 맞춰 설명하는 강의입니다., [사진][사진] [사진] 게임 개발자는 Unreal, Unity만 사용할 줄 알면 되는 거 아닌가요? 엔

    www.inflearn.com

    ResourceBase 클래스

    ResourceBase는 모든 자원의 기본 클래스입니다. 이 클래스는 자원의 공통 속성과 메서드를 정의합니다.

    ResourceBase.h

    #pragma once
    
    // 자원 유형을 나타내는 열거형
    enum class ResourceType : uint8
    {
    	None = -1,
    	Mesh,
    	Shader,
    	Texture,
    	Material,
    	Animation,
    	End,
    };
    
    // 사용 가능한 자원 유형의 수
    enum {
    	RESOURCE_TYPE_COUNT = static_cast<uint8>(ResourceType::End)
    };
    
    // 모든 자원의 기본 클래스
    class ResourceBase
    {
    public:
    	ResourceBase(ResourceType type); // 생성자
    	virtual ~ResourceBase(); // 가상 소멸자
    
    	ResourceType GetType() { return _type; } // 자원 유형 반환
    
    	void SetName(const wstring& name) { _name = name; } // 자원 이름 설정
    	const wstring& GetName() { return _name; } // 자원 이름 반환
    	uint32 GetId() { return _id; } // 자원 ID 반환
    
    protected:
    	virtual void Load(const wstring& path) {} // 자원 로딩 (가상 함수)
    	virtual void Save(const wstring& path) {} // 자원 저장 (가상 함수)
    
    protected:
    	ResourceType _type = ResourceType::None; // 자원 유형
    	wstring _name; // 자원 이름
    	wstring _path; // 자원 경로
    	uint32 _id = 0; // 자원 ID
    };

    ResourceBase.cpp

    #include "pch.h"
    #include "ResourceBase.h"
    
    ResourceBase::ResourceBase(ResourceType type) :
    	_type(type)
    {
    
    }
    
    ResourceBase::~ResourceBase()
    {
    }

    ResourceManager 클래스 개요

    ResourceManager 클래스는 게임 내 모든 자원(텍스처, 메시, 셰이더, 재료, 애니메이션 등)을 관리합니다. 이 클래스는 자원의 로딩, 저장, 검색, 해제를 담당하며, 자원의 재사용을 최대화하여 성능을 최적화합니다.

    클래스 설계

    ResourceManager 클래스의 주요 구성 요소는 다음과 같습니다:

    • 자원 저장소: array<KeyObject, RESOURCE_TYPE_COUNT>를 사용하여 다양한 유형의 자원을 저장합니다. 여기서 KeyObject는 map<wstring, shared_ptr<ResourceBase>> 타입입니다.
    • 디바이스 컨텍스트: DirectX 11 디바이스 컨텍스트(ComPtr<ID3D11Device>)를 저장하여 자원 생성에 사용합니다.
    • 템플릿 기반 로딩 및 접근: 자원의 유형에 따라 템플릿 함수를 제공하여 로딩(Load), 추가(Add), 검색(Get)을 수행합니다.

    핵심 기능 구현

    1, 자원 로딩

    자원을 로딩하는 과정은 키와 경로를 기반으로 합니다. 자원이 이미 저장소에 있는지 확인한 후, 존재하지 않는 경우 새로 로딩하여 저장소에 추가합니다.

    // 자원 로딩 메서드 구현
    template<typename T>
    inline shared_ptr<T> ResourceManager::Load(const wstring& key, const wstring& path)
    {
    	// 자원 유형을 결정
    	ResourceType resourceType = GetResourceType<T>();
    	KeyObject& keyObjMap = _resources[static_cast<uint8>(resourceType)];
    
    	// 이미 로드된 자원 검색
    	auto findIt = keyObjMap.find(key);
    	if (findIt != keyObjMap.end()) {
    		return static_pointer_cast<T>(findIt->second);
    	}
    
    	// 새 자원 로드 및 저장
    	shared_ptr<T> object = make_shared<T>(_device);
    	object->Load(path);
    	keyObjMap[key] = object;
    
    	return object;
    }

    2, 자원 추가 및 검색

    자원을 저장소에 추가하는 Add 메서드와, 저장된 자원을 검색하는 Get 메서드를 구현합니다. 이 메서드들은 자원의 유형을 자동으로 식별하여 적절한 저장소에 액세스합니다.

    // 자원 추가 메서드 구현
    template<typename T>
    inline bool ResourceManager::Add(const wstring& key, shared_ptr<T> object)
    {
    	ResourceType resourceType = GetResourceType<T>();
    	KeyObject& keyObjMap = _resources[static_cast<uint8>(resourceType)];
    
    	auto findIt = keyObjMap.find(key);
    	if (findIt != keyObjMap.end()) {
    		return false; // 이미 존재하는 키
    	}
    
    	keyObjMap[key] = object; // 자원 추가
    
    	return true;
    }
    
    // 자원 검색 메서드 구현
    template<typename T>
    inline shared_ptr<T> ResourceManager::Get(const wstring& key)
    {
    	ResourceType resourceType = GetResourceType<T>();
    	KeyObject& keyObjMap = _resources[static_cast<uint8>(resourceType)];
    
    	auto findIt = keyObjMap.find(key);
    	if (findIt != keyObjMap.end()) {
    		return static_pointer_cast<T>(findIt->second);
    	}
    	return nullptr; // 자원을 찾지 못함
    }
    
    // 자원 유형 반환 메서드 구현
    template<typename T>
    inline ResourceType ResourceManager::GetResourceType()
    {
    	// T 유형에 따라 적절한 ResourceType 반환
    	if (std::is_same_v<T, Mesh>)
    		return ResourceType::Mesh;
    	if (std::is_same_v<T, Shader>)
    		return ResourceType::Shader;
    	if (std::is_same_v<T, Texture>)
    		return ResourceType::Texture;
    	if (std::is_same_v<T, Material>)
    		return ResourceType::Material;
    	if (std::is_same_v<T, Animation>)
    		return ResourceType::Animation;
    
    	assert(false); // 지원되지 않는 유형
    	return ResourceType::None;
    }

    3, 기본 자원 생성

    엔진 초기화 시 기본 자원(텍스처, 메시, 셰이더, 재료, 애니메이션)을 생성합니다. 이는 개발자가 즉시 사용할 수 있는 기본 세트를 제공합니다.

    // 기본 텍스처 생성 함수
    void ResourceManager::CreateDefaultTexture()
    {
    	// Unity 로고 텍스처 생성
    	{
    		auto texture = make_shared<Texture>(_device); // Texture 객체 생성
    		texture->SetName(L"UnityLogo"); // 텍스처 이름 설정
    		texture->Create(L"UnityLogo.png"); // 텍스처 파일 로드
    		Add(texture->GetName(), texture); // ResourceManager에 텍스처 추가
    	}
    
    	// Snake 이미지 텍스처 생성
    	{
    		auto texture = make_shared<Texture>(_device); // Texture 객체 생성
    		texture->SetName(L"Snake"); // 텍스처 이름 설정
    		texture->Create(L"Snake.bmp"); // 텍스처 파일 로드
    		Add(texture->GetName(), texture); // ResourceManager에 텍스처 추가
    	}
    }
    
    // 기본 메시 생성 함수
    void ResourceManager::CreateDefaultMesh()
    {
    	// Rectangle 메시 생성
    	{
    		shared_ptr<Mesh> mesh = make_shared<Mesh>(_device); // Mesh 객체 생성
    		mesh->SetName(L"Rectangle"); // 메시 이름 설정
    		mesh->CreateDefaultRectangle(); // 기본 사각형 메시 생성
    		Add(mesh->GetName(), mesh); // ResourceManager에 메시 추가
    	}
    }
    
    // 기본 쉐이더 생성 함수
    void ResourceManager::CreateDefaultShader()
    {
    	auto vertexShader = make_shared<VertexShader>(_device); // VertexShader 객체 생성
    	vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0"); // 정점 쉐이더 로드
    
    	auto inputLayout = make_shared<InputLayout>(_device); // InputLayout 객체 생성
    	inputLayout->Create(VertexTextureData::descs, vertexShader->GetBlob()); // 입력 레이아웃 생성
    
    	auto pixelShader = make_shared<PixelShader>(_device); // PixelShader 객체 생성
    	pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0"); // 픽셀 쉐이더 로드
    
    	// Shader 객체 생성 및 설정
    	shared_ptr<Shader> shader = make_shared<Shader>();
    	shader->SetName(L"Default"); // 쉐이더 이름 설정
    	shader->_vertexShader = vertexShader; // 정점 쉐이더 설정
    	shader->_inputLayout = inputLayout; // 입력 레이아웃 설정
    	shader->_pixelShader = pixelShader; // 픽셀 쉐이더 설정
    
    	Add(shader->GetName(), shader); // ResourceManager에 쉐이더 추가
    }
    
    // 기본 재료 생성 함수
    void ResourceManager::CreateDefaultMaterial()
    {
    	shared_ptr<Material> material = make_shared<Material>(); // Material 객체 생성
    	material->SetName(L"Default"); // 재료 이름 설정
    	material->SetShader(Get<Shader>(L"Default")); // Default 쉐이더 설정
    	material->SetTexture(Get<Texture>(L"UnityLogo")); // UnityLogo 텍스처 설정
    	Add(material->GetName(), material); // ResourceManager에 재료 추가
    }
    
    // 기본 애니메이션 생성 함수
    void ResourceManager::CreateDefaultAnimation()
    {
    	shared_ptr<Animation> animation = make_shared<Animation>(); // Animation 객체 생성
    
    	animation->SetName(L"SnakeAnim"); // 애니메이션 이름 설정
    	animation->SetTexture(Get<Texture>(L"Snake")); // Snake 텍스처 설정
    	animation->SetLoop(true); // 반복 설정
    
    	// 애니메이션 키프레임 추가
    	animation->AddKeyFrame(KeyFrame{ Vec2{0.f,0.f}, Vec2{100.f,100.f}, 0.1f });
    	animation->AddKeyFrame(KeyFrame{ Vec2{100.f,0.f}, Vec2{100.f,100.f}, 0.1f });
    	animation->AddKeyFrame(KeyFrame{ Vec2{200.f,0.f}, Vec2{100.f,100.f}, 0.1f });
    	animation->AddKeyFrame(KeyFrame{ Vec2{300.f,0.f}, Vec2{100.f,100.f}, 0.1f });
    
    	Add(animation->GetName(), animation); // ResourceManager에 애니메이션 추가
    
    	// 애니메이션 저장 및 로드 예제 (XML, JSON 등을 사용할 수 있음)
    	animation->Save(L"TestAnim.xml"); // 애니메이션 상태 저장
    
    	shared_ptr<Animation> anim2 = make_shared<Animation>(); // 새 Animation 객체 생성
    	anim2->Load(L"TestAnim.xml"); // 저장된 애니메이션 상태 로드
    }

    이 예시는 매우 기본적인 구조를 보여줍니다. 실제 게임 엔진에서는 자원의 종류가 다양하고, 로딩 및 관리 로직이 더 복잡할 수 있습니다.

    전체코드

    ResourceManager.h

    #pragma once
    
    #include "ResourceBase.h"
    
    // 필요한 클래스 선언
    class Mesh;
    class Shader;
    class Texture;
    class Material;
    class Animation;
    
    // 자원 관리자 클래스
    class ResourceManager
    {
    public:
    	ResourceManager(ComPtr<ID3D11Device> device); // 생성자
    
    	void Init(); // 초기화 메서드
    
    	// 자원 로딩
    	template<typename T>
    	shared_ptr<T> Load(const wstring& key, const wstring& path);
    
    	// 자원 추가
    	template<typename T>
    	bool Add(const wstring& key, shared_ptr<T> object);
    
    	// 자원 검색
    	template<typename T>
    	shared_ptr<T> Get(const wstring& key);
    
    	// 자원 유형 반환
    	template<typename T>
    	ResourceType GetResourceType();
    
    private:
    	// 기본 자원 생성 메서드
    	void CreateDefaultTexture();
    	void CreateDefaultMesh();
    	void CreateDefaultShader();
    	void CreateDefaultMaterial();
    	void CreateDefaultAnimation();
    
    private:
    	ComPtr<ID3D11Device> _device; // DirectX 11 디바이스
    
    	// 자원 저장을 위한 컨테이너
    	using KeyObject = map<wstring, shared_ptr<ResourceBase>>;
    	array<KeyObject, RESOURCE_TYPE_COUNT> _resources;
    };
    
    // 자원 로딩 메서드 구현
    template<typename T>
    inline shared_ptr<T> ResourceManager::Load(const wstring& key, const wstring& path)
    {
    	// 자원 유형을 결정
    	ResourceType resourceType = GetResourceType<T>();
    	KeyObject& keyObjMap = _resources[static_cast<uint8>(resourceType)];
    
    	// 이미 로드된 자원 검색
    	auto findIt = keyObjMap.find(key);
    	if (findIt != keyObjMap.end()) {
    		return static_pointer_cast<T>(findIt->second);
    	}
    
    	// 새 자원 로드 및 저장
    	shared_ptr<T> object = make_shared<T>(_device);
    	object->Load(path);
    	keyObjMap[key] = object;
    
    	return object;
    }
    
    // 자원 추가 메서드 구현
    template<typename T>
    inline bool ResourceManager::Add(const wstring& key, shared_ptr<T> object)
    {
    	ResourceType resourceType = GetResourceType<T>();
    	KeyObject& keyObjMap = _resources[static_cast<uint8>(resourceType)];
    
    	auto findIt = keyObjMap.find(key);
    	if (findIt != keyObjMap.end()) {
    		return false; // 이미 존재하는 키
    	}
    
    	keyObjMap[key] = object; // 자원 추가
    
    	return true;
    }
    
    // 자원 검색 메서드 구현
    template<typename T>
    inline shared_ptr<T> ResourceManager::Get(const wstring& key)
    {
    	ResourceType resourceType = GetResourceType<T>();
    	KeyObject& keyObjMap = _resources[static_cast<uint8>(resourceType)];
    
    	auto findIt = keyObjMap.find(key);
    	if (findIt != keyObjMap.end()) {
    		return static_pointer_cast<T>(findIt->second);
    	}
    	return nullptr; // 자원을 찾지 못함
    }
    
    // 자원 유형 반환 메서드 구현
    template<typename T>
    inline ResourceType ResourceManager::GetResourceType()
    {
    	// T 유형에 따라 적절한 ResourceType 반환
    	if (std::is_same_v<T, Mesh>)
    		return ResourceType::Mesh;
    	if (std::is_same_v<T, Shader>)
    		return ResourceType::Shader;
    	if (std::is_same_v<T, Texture>)
    		return ResourceType::Texture;
    	if (std::is_same_v<T, Material>)
    		return ResourceType::Material;
    	if (std::is_same_v<T, Animation>)
    		return ResourceType::Animation;
    
    	assert(false); // 지원되지 않는 유형
    	return ResourceType::None;
    }

    ResourceManager.cpp

    #include "pch.h" // 프로젝트의 사전 컴파일 헤더 파일
    #include "ResourceManager.h" // ResourceManager 클래스 정의 포함
    #include "Texture.h" // Texture 클래스 정의 포함
    #include "Mesh.h" // Mesh 클래스 정의 포함
    #include "Shader.h" // Shader 클래스 정의 포함
    #include "Material.h" // Material 클래스 정의 포함
    #include "Animation.h" // Animation 클래스 정의 포함
    
    // ResourceManager 클래스 생성자
    ResourceManager::ResourceManager(ComPtr<ID3D11Device> device) :
    	_device(device) // DirectX 11 디바이스를 멤버 변수에 할당
    {
    }
    
    // 자원 관리자 초기화 함수
    void ResourceManager::Init()
    {
    	CreateDefaultTexture(); // 기본 텍스처 생성
    	CreateDefaultMesh(); // 기본 메시 생성
    	CreateDefaultShader(); // 기본 쉐이더 생성
    	CreateDefaultMaterial(); // 기본 재료 생성
    	CreateDefaultAnimation(); // 기본 애니메이션 생성
    }
    
    // 기본 텍스처 생성 함수
    void ResourceManager::CreateDefaultTexture()
    {
    	// Unity 로고 텍스처 생성
    	{
    		auto texture = make_shared<Texture>(_device); // Texture 객체 생성
    		texture->SetName(L"UnityLogo"); // 텍스처 이름 설정
    		texture->Create(L"UnityLogo.png"); // 텍스처 파일 로드
    		Add(texture->GetName(), texture); // ResourceManager에 텍스처 추가
    	}
    
    	// Snake 이미지 텍스처 생성
    	{
    		auto texture = make_shared<Texture>(_device); // Texture 객체 생성
    		texture->SetName(L"Snake"); // 텍스처 이름 설정
    		texture->Create(L"Snake.bmp"); // 텍스처 파일 로드
    		Add(texture->GetName(), texture); // ResourceManager에 텍스처 추가
    	}
    }
    
    // 기본 메시 생성 함수
    void ResourceManager::CreateDefaultMesh()
    {
    	// Rectangle 메시 생성
    	{
    		shared_ptr<Mesh> mesh = make_shared<Mesh>(_device); // Mesh 객체 생성
    		mesh->SetName(L"Rectangle"); // 메시 이름 설정
    		mesh->CreateDefaultRectangle(); // 기본 사각형 메시 생성
    		Add(mesh->GetName(), mesh); // ResourceManager에 메시 추가
    	}
    }
    
    // 기본 쉐이더 생성 함수
    void ResourceManager::CreateDefaultShader()
    {
    	auto vertexShader = make_shared<VertexShader>(_device); // VertexShader 객체 생성
    	vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0"); // 정점 쉐이더 로드
    
    	auto inputLayout = make_shared<InputLayout>(_device); // InputLayout 객체 생성
    	inputLayout->Create(VertexTextureData::descs, vertexShader->GetBlob()); // 입력 레이아웃 생성
    
    	auto pixelShader = make_shared<PixelShader>(_device); // PixelShader 객체 생성
    	pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0"); // 픽셀 쉐이더 로드
    
    	// Shader 객체 생성 및 설정
    	shared_ptr<Shader> shader = make_shared<Shader>();
    	shader->SetName(L"Default"); // 쉐이더 이름 설정
    	shader->_vertexShader = vertexShader; // 정점 쉐이더 설정
    	shader->_inputLayout = inputLayout; // 입력 레이아웃 설정
    	shader->_pixelShader = pixelShader; // 픽셀 쉐이더 설정
    
    	Add(shader->GetName(), shader); // ResourceManager에 쉐이더 추가
    }
    
    // 기본 재료 생성 함수
    void ResourceManager::CreateDefaultMaterial()
    {
    	shared_ptr<Material> material = make_shared<Material>(); // Material 객체 생성
    	material->SetName(L"Default"); // 재료 이름 설정
    	material->SetShader(Get<Shader>(L"Default")); // Default 쉐이더 설정
    	material->SetTexture(Get<Texture>(L"UnityLogo")); // UnityLogo 텍스처 설정
    	Add(material->GetName(), material); // ResourceManager에 재료 추가
    }
    
    // 기본 애니메이션 생성 함수
    void ResourceManager::CreateDefaultAnimation()
    {
    	shared_ptr<Animation> animation = make_shared<Animation>(); // Animation 객체 생성
    
    	animation->SetName(L"SnakeAnim"); // 애니메이션 이름 설정
    	animation->SetTexture(Get<Texture>(L"Snake")); // Snake 텍스처 설정
    	animation->SetLoop(true); // 반복 설정
    
    	// 애니메이션 키프레임 추가
    	animation->AddKeyFrame(KeyFrame{ Vec2{0.f,0.f}, Vec2{100.f,100.f}, 0.1f });
    	animation->AddKeyFrame(KeyFrame{ Vec2{100.f,0.f}, Vec2{100.f,100.f}, 0.1f });
    	animation->AddKeyFrame(KeyFrame{ Vec2{200.f,0.f}, Vec2{100.f,100.f}, 0.1f });
    	animation->AddKeyFrame(KeyFrame{ Vec2{300.f,0.f}, Vec2{100.f,100.f}, 0.1f });
    
    	Add(animation->GetName(), animation); // ResourceManager에 애니메이션 추가
    
    	// 애니메이션 저장 및 로드 예제 (XML, JSON 등을 사용할 수 있음)
    	animation->Save(L"TestAnim.xml"); // 애니메이션 상태 저장
    
    	shared_ptr<Animation> anim2 = make_shared<Animation>(); // 새 Animation 객체 생성
    	anim2->Load(L"TestAnim.xml"); // 저장된 애니메이션 상태 로드
    }

    결론

    ResourceManager 클래스는 게임 엔진에서 자원을 효율적으로 관리하는 데 필수적인 구성 요소입니다. DirectX 11과 같은 그래픽 API를 사용하여 자원 관리 시스템을 구현함으로써, 게임의 성능을 최적화하고 개발 과정을 보다 수월하게 만들 수 있습니다.

    반응형
    다음글
    다음 글이 없습니다.
    이전글
    이전 글이 없습니다.
    댓글
조회된 결과가 없습니다.
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
목차
표시할 목차가 없습니다.
    • 안녕하세요
    • 감사해요
    • 잘있어요

    티스토리툴바