프로그래밍 공부
작성일
2023. 10. 18. 16:27
작성자
WDmil
728x90

이전에 사용하던 ID3D11ShaderResourceView* srv 를 따로 만들어서

한개의 객체당 한개의 srv를 생성하는것 이 아닌. srv를 공통으로 사용할 경우. 같은 srv를 사용하도록 만들어보자.


Texture

#pragma once

class Texture
{
private:
	// 복사생성자가 아니라 그대로 참조형 생성자로 이동시켜 사용한다
	Texture(ID3D11ShaderResourceView* srv, ScratchImage& image, wstring file);
	~Texture();

public:
	void PSSet(UINT slot = 0);

public:
	static Texture* Add(wstring file);
	static void Delete();

private:
	wstring file;

	ScratchImage image;

	ID3D11ShaderResourceView* srv;

	static unordered_map<wstring, Texture*> textures;
};

Srv를 따로 만들어놓을 Texture class를 구현한다.

 

각 객체의 srv를 생성할 때. Add 함수를 통하여. Texture를 생성하도록 구현한다.

 

생성자는 private으로 정의되어. 자기자신 이외에는 참조할 수 없도록 제한하여. static함수 처럼 사용하도록 한다.

 

private 변수로 file, image, srv를 가지게하여. 해당 Texture가 어떤 file을 가지는지, image가 어떤건지. srv는 어떤걸 사용하는지 확인할 수 있게 하고.

 

static형태로 unordered_map textures를 만들어서 전역에서 해당 textures데이터를 사용할 수 있게 한다.


#include "Framework.h"

unordered_map<wstring, Texture*> Texture::textures;

Texture::Texture(ID3D11ShaderResourceView* srv, ScratchImage& image, wstring file)
    : srv(srv), image(move(image)), file(file)
{
}

Texture::~Texture()
{
    srv->Release();
}

void Texture::PSSet(UINT slot)
{
    // 배열형대로 받을 수도 있다.
    DC->PSSetShaderResources(slot, 1, &srv);
}

Texture* Texture::Add(wstring file)
{
    if (textures.count(file) > 0)
        return textures[file];

    ScratchImage image;
    LoadFromWICFile(file.c_str(), WIC_FLAGS_NONE, nullptr, image);
    ID3D11ShaderResourceView* srv;

    // srv할당
    CreateShaderResourceView(DEVICE, image.GetImages(),
        image.GetImageCount(), image.GetMetadata(), &srv);

    textures[file] = new Texture(srv, image, file);
    return textures[file];
}

void Texture::Delete()
{
    for (pair<wstring, Texture*> texture : textures)
        delete texture.second;
}

cpp파일은 위와같이 구성한다.

 

생성자에서 받아온 데이터를 자기자신의 변수로 대입하고. 소멸자에서는 동적으로 생성된 srv를 날려주는 코드를 넣는다.

 

이때, ScratchImage 형태는. 항상 원본값을 가져와야한다.  객체 특성상 복사대입이 불가능하기 때문에. 원본대입을 사용한다.

 

PSSet을 통해. srv를 PSSetShaderResources로 넘겨주는 함수를 같이 기입한다.

 

Texture::Add를 정의하여.

받아온 wstring file에 대한. Key값이 map배열에 존재하는지 확인하고. 있을경우 반환.

없을경우. srv 객체를 생성하는 과정을 거쳐준다.

 

Delete()를 사용할 경우. 현재 기입된 srv를 전부 날려준다.


이제 만들어진 Texture를 Object에서 사용해보자.

 

srv텍스쳐는 Material에 속해야 함으로. Material에서 정의한다.


Material

#pragma once

class Material
{
public:
	Material(wstring shderFIle);
	~Material();

	void Set();

	void SetShader(wstring shaderFile);

	void SetDiffuseMap(wstring textureFile);

private:
	VertexShader* vertexShader;
	PixelShader* pixelShader;

	Texture* diffuseMap = nullptr;
};

전에 정의해놓았던 Material에 Texture* 형태의 diffuseMap을 추가한다.

#include "Framework.h"

Material::Material(wstring shderFIle)
{
	SetShader(shderFIle);
}

Material::~Material()
{
}

void Material::Set()
{
	if (diffuseMap)
		diffuseMap->PSSet(0);
	vertexShader->Set();
	pixelShader->Set();
}

void Material::SetShader(wstring shaderFile)
{
	vertexShader = Shader::AddVS(shaderFile);
	pixelShader = Shader::AddPS(shaderFile);
}

void Material::SetDiffuseMap(wstring textureFile)
{
	diffuseMap = Texture::Add(textureFile);
}

그후, Set()함수에서 정의할 때. diffuseMap의 PSSet을 활용하여 PixelShader의 Reginumber를 같이 정의해준다.

 

SetDiffuseMap을 통하여. Texture::Add함수를 사용하여 현재 데이터의 Texture를 생성해준다.

 

위와같이 구성하였다면, Scene에서 Object의 Texture를 수정해줄 수 있을것이다.


Scene에서 Object의 Texture 수정하기

이제 위에서 만들어놓은 객체를 사용해 Scene에서 만들었던 Object의 Texture를 수정해보자.

TutorialScene::TutorialScene()
{
    cube = new Cube();

    cube->GetMetrial()->SetDiffuseMap(L"Textures/Landscape/box.png");
}

구현은 간단하다. 위와같이 그냥 생성한 오브젝트의 위치에 SetDiffusemap을 호출하여. map을 정의해주면 된다.

그렇게 했을 때. 전의 cube와 같은 cube가 생성되면 성공이다.


ImGui데이터 설정은 너무 길기 때문에 따로 링크를 걸어놓겠다.

 

위 링크대로 ImGui를 설치한뒤. 헤더도 같이 기입하였다면 DirectX에서 사용할 준비가 되었다는 뜻이다.

 

 

우선, Winmain이 선언되어있는 cpp파일로 이동하여 몃가지를 추가하자.

 

위 WndProc부분에 ImGui를 사용해 데이터를 조정할 수 있도록 패킹을 씌워주는것이다.

 

데이터를 중간에 빼서 수정한 다음에 데이터를 다시 기입해주는 역할을 한다.

 


GameManager를 설정해놓은 부분에서 데이터를 다시 정의해보자.

#include "Framework.h"
#include "GameManager.h"

#include "Scenes/TutorialScene.h"
#include "Scenes/GridScene.h"

GameManager::GameManager()
{
	Create();

	SceneManager::Get()->Create("Grid", new GridScene());
	SceneManager::Get()->Create("Start", new TutorialScene());
	//SceneManager::Get()->Create("Game", new GameScene());

	SceneManager::Get()->Add("Grid");
	//SceneManager::Get()->Add("Game");
	SceneManager::Get()->Add("Start");

}

GameManager::~GameManager()
{
	Delete();
}

void GameManager::Update()
{
	KEY->Update();
	Timer::Get()->Update();

	SceneManager::Get()->Update();
}

void GameManager::Render()
{
	SceneManager::Get()->PreRender();

	Device::Get()->Clear();

	SceneManager::Get()->Render();
	SceneManager::Get()->PostRender();

	// 항상 기본적으로 다루어주어야하는 Frame
	ImGui_ImplDX11_NewFrame();
	ImGui_ImplWin32_NewFrame();
	ImGui::NewFrame();

	string fps = "FPS : " + to_string(Timer::Get()->GetFPS());
	ImGui::Text(fps.c_str());

	SceneManager::Get()->GUIRender();

	ImGui::Render();
	ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());

	Device::Get()->Present();
}

void GameManager::Create()
{
	Device::Get();
	Keyboard::Get();
	Timer::Get();
	Environment::Get();
	SceneManager::Get();

	ImGui::CreateContext();
	ImGui::StyleColorsDark();

	ImGui_ImplWin32_Init(hWnd);
	ImGui_ImplDX11_Init(DEVICE, DC);
}

void GameManager::Delete()
{
	Device::Delete();
	Keyboard::Delete();
	Timer::Delete();
	Shader::Delete();
	Texture::Delete();
	Environment::Delete();
	SceneManager::Delete();

	ImGui_ImplDX11_Shutdown();
	ImGui_ImplWin32_Shutdown();

	ImGui::DestroyContext();
}

GameManager부분에서 ImGui의 표시부를 생성할 수 있다.

 

또한 생성할때, Gui부분에서 데이터를 어느부분을 가져올지 또한 정의해줄 수 있다.

 

그 이후, ShutDown할때 주의해야 하는데,

항상 DX11부터 Shoutdown해주어야 한다.

 

Dx11이 꺼지기 전에 Win32가 꺼지면 동작사항 상 순서가 엇갈려서 코드가 터진다.

 

정상 동작시 UI가 나타난다.

728x90