전체 코드 : https://github.com/HyangRim/DirectX11-Engine-Client
GitHub - HyangRim/DirectX11-Engine-Client
Contribute to HyangRim/DirectX11-Engine-Client development by creating an account on GitHub.
github.com
Resource Manager와 동적 리소스 로딩 시스템
핵심 기능
- 템플릿 기반 리소스 관리
- 동적 로딩 : 필요 시점에 리소스 로드
- 메모리 풀링 : 리소스 재사용으로 성능 최적화
- 픽셀 레벨 접근 : 텍스쳐 데이터 실시간 분석
ResourceManager 핵심 구조
1. 기본 아키텍쳐
class ResourceManager
{
DECLARE_SINGLE(ResourceManager);
public:
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);
shared_ptr<Texture> GetOrAddTexture(const wstring& _key, const wstring& _path);
shared_ptr<Model> GetOrAddModel(const wstring& _key, const wstring& _path);
private:
using KeyObjMap = map<wstring, shared_ptr<ResourceBase>>;
array<KeyObjMap, RESOURCE_TYPE_COUNT> m_resources;
};
2. 템플릿 기반 리소스 관리
template<typename T>
shared_ptr<T> ResourceManager::Load(const wstring& _key, const wstring& _path)
{
ResourceType resourceType = GetResourceType<T>();
KeyObjMap& keyObjMap = m_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>();
object->Load(_path);
object->SetName(_key);
keyObjMap[_key] = object;
return object;
}
template<typename T>
ResourceType ResourceManager::GetResourceType()
{
if (std::is_same_v<T, Mesh>)
return ResourceType::Mesh;
else if (std::is_same_v<T, Shader>)
return ResourceType::Shader;
else if (std::is_same_v<T, Texture>)
return ResourceType::Texture;
else if (std::is_same_v<T, Material>)
return ResourceType::Material;
else if (std::is_same_v<T, Model>)
return ResourceType::Model;
return ResourceType::None;
}
핵심 기능
- 타입 안정성 : 컴파일 타입에 리소스 타입 검증
- 중복 로딩 방지 : 키 기반 캐싱으로 메모리 절약
- 자동 타입 추론 : is_same_v로 리소스 타입 자동 분류
모델 및 애니메이션 리소스 관리
1. 모델 리소스 구조
class Model : public ResourceBase, public enable_shared_from_this<Model>
{
public:
void ReadMaterial(const wstring& _filename);
void ReadModel(const wstring& _filename);
void ReadAnimation(const wstring& _tag, const wstring& _filename);
// 태그 기반 애니메이션 관리
shared_ptr<ModelAnimation> GetAnimationByTag(const wstring& _tag);
unordered_map<wstring, shared_ptr<ModelAnimation>>& GetAnimations() { return m_animations; }
private:
// 리소스 캐싱
void BindCacheInfo();
// 리소스 컨테이너
vector<shared_ptr<Material>> m_materials;
vector<shared_ptr<ModelBone>> m_bones;
vector<shared_ptr<ModelMesh>> m_meshes;
unordered_map<wstring, shared_ptr<ModelAnimation>> m_animations;
};
2. 동적 애니메이션 로딩
void Model::ReadAnimation(const wstring& _tag, const wstring& _filename)
{
wstring fullPath = _modelPath + _filename + L".clip";
shared_ptr<FileUtils> file = make_shared<FileUtils>();
file->Open(fullPath, FileMode::Read);
shared_ptr<ModelAnimation> animation = make_shared<ModelAnimation>();
// 애니메이션 메타데이터 로드
animation->m_name = Utils::ToWString(file->Read<string>());
animation->m_duration = file->Read<float>();
animation->m_frameRate = file->Read<float>();
animation->m_frameCount = file->Read<uint32>();
uint32 keyframesCount = file->Read<uint32>();
// 키프레임 데이터 로드
for (uint32 i = 0; i < keyframesCount; i++)
{
shared_ptr<ModelKeyframe> keyframe = make_shared<ModelKeyframe>();
keyframe->m_boneName = Utils::ToWString(file->Read<string>());
uint32 size = file->Read<uint32>();
if (size > 0)
{
keyframe->m_transforms.resize(size);
void* ptr = &keyframe->m_transforms[0];
file->Read(&ptr, sizeof(ModelKeyframeData) * size);
}
animation->keyframes[keyframe->m_boneName] = keyframe;
}
// 태그 기반 저장
m_animations[_tag] = animation;
}
셰이더 관리
1. 동적 셰이더 상수 버퍼 관리
class Shader
{
public:
// 다양한 타입의 상수 버퍼 관리
void PushGlobalData(const Matrix& _view, const Matrix& _projection);
void PushTransformData(const TransformDesc& _desc);
void PushLightData(const LightDesc& _desc);
void PushMaterialData(const MaterialDesc& _desc);
void PushBoneData(const BoneDesc& _desc);
void PushHealthBarData(float _healthRatio, float _manaRatio, int _type = 0);
private:
// 상수 버퍼 컨테이너
GlobalDesc m_globalDesc;
shared_ptr<ConstantBuffer<GlobalDesc>> m_globalBuffer;
ComPtr<ID3DX11EffectConstantBuffer> m_globalEffectBuffer;
TransformDesc m_transformDesc;
shared_ptr<ConstantBuffer<TransformDesc>> m_transformBuffer;
ComPtr<ID3DX11EffectConstantBuffer> m_transformEffectBuffer;
// ... 기타 상수 버퍼들
};
Character Select Scene에서의 동적 리소스 로딩 사례
1. 런타임 리소스 로딩
void CharacterSelectScene::LoadCharacterSelectSceneImages()
{
LoadCharacterListSlotImages();
LoadCharacterImages();
LoadCharacterSkinListSlotImages();
LoadBackGround();
LoadCharacterFullAndHalfImages();
}
void CharacterSelectScene::LoadCharacterFullAndHalfImages()
{
shared_ptr<Shader> shader = make_shared<Shader>(L"ImageShader.fx");
auto SetupUIMaterial = [&](shared_ptr<Material> material) {
material->SetShader(shader);
material->SetRenderQueue(RenderQueue::Transparent);
material->SetTransparent(true);
material->SetRenderingMode(RenderingMode::Forward);
};
wstring prefixTagFull = L"Full";
wstring prefixTagHalf = L"Half";
wstring prefixPath = L"..\\Resources\\Textures\\UI\\CharacterSelectScene\\CharacterImages\\";
for (int i = 0; i < characterNames.size(); i++)
{
for (int j = 0; j < skinCount[i]; j++)
{
// Full Image 동적 로딩
shared_ptr<Material> charFullImage = make_shared<Material>();
SetupUIMaterial(charFullImage);
wstring tag = L"Char" + prefixTagFull + L"_" + characterNames[i] + L"_S00" + to_wstring(j);
wstring path = prefixPath + characterNames[i] + L"\\" + tag + L".png";
auto charFullTexture = RESOURCES->Load<Texture>(tag, path);
charFullImage->SetDiffuseMap(charFullTexture);
RESOURCES->Add(tag, charFullImage);
// Half Image 동적 로딩
shared_ptr<Material> charHalfImage = make_shared<Material>();
SetupUIMaterial(charHalfImage);
tag = L"Char" + prefixTagHalf + L"_" + characterNames[i] + L"_S00" + to_wstring(j);
path = prefixPath + characterNames[i] + L"\\" + tag + L".png";
auto charHalfTexture = RESOURCES->Load<Texture>(tag, path);
charHalfImage->SetDiffuseMap(charHalfTexture);
RESOURCES->Add(tag, charHalfImage);
}
}
}
2. 멀티스레드 리소스 로딩
class LumiaIsland : public Scene
{
private:
// 멀티스레드 로딩용 함수
static DWORD WINAPI BackgroundLoadingThread(LPVOID _param);
void ProcessMainThreadTasks();
private:
CRITICAL_SECTION m_loadingCS;
HANDLE m_loadingThread;
atomic<bool> m_loadingComplete{false};
// 메인 스레드 작업 큐
queue<function<void()>> m_mainThreadTasks;
CRITICAL_SECTION m_mainThreadTasksCS;
atomic<bool> m_objectsCreated{false};
};
DWORD WINAPI LumiaIsland::BackgroundLoadingThread(LPVOID _param)
{
LumiaIsland* scene = static_cast<LumiaIsland*>(_param);
// 백그라운드에서 리소스 로딩
EnterCriticalSection(&scene->m_loadingCS);
{
// 대용량 리소스들을 백그라운드에서 로딩
scene->LoadHeavyResources();
}
LeaveCriticalSection(&scene->m_loadingCS);
scene->m_loadingComplete = true;
return 0;
}
void LumiaIsland::ProcessMainThreadTasks()
{
EnterCriticalSection(&m_mainThreadTasksCS);
{
while (!m_mainThreadTasks.empty())
{
auto task = m_mainThreadTasks.front();
m_mainThreadTasks.pop();
task();
}
}
LeaveCriticalSection(&m_mainThreadTasksCS);
}'DirectX11 > Eternal Return 모작' 카테고리의 다른 글
| [DirectX 11 Eternal Return 모작] 9. 아이템 시스템 & 제작 시스템 (0) | 2025.09.03 |
|---|---|
| [DirectX 11 Eternal Return 모작] 8. State Machine & Delegate (0) | 2025.09.03 |
| [DirectX 11 Eternal Return 모작] 6. Scene (0) | 2025.09.02 |
| [DirectX 11 Eternal Return 모작] 5. Component (0) | 2025.09.02 |
| [DirectX 11 Eternal Return 모작] 4. Shader & Material (0) | 2025.09.02 |