1. GameEngineDefaultRenderer
컴포넌트 구조. GameEngeActor에서 GameEngineDefaultRender의 인스턴스 생성.
<hide/>
//void Player::Start()
{
//렌더러 생성
Renderer = CreateComponent<GameEngineDefaultRenderer>();
//렌더러 스케일 설정
Renderer->GetTransform().SetLocalScale({ 100, 100, 100 });
//렌더링 파이프 라인 세팅
Renderer->SetPipeLine("Color");
//상수 버퍼 링크
Renderer->PipeLineHelper.SetConstantBufferLink("ResultColor", Color);
}
1-0. 멤버 변수
<hide/>
class GameEngineDefaultRenderer : public GameEngineRenderer
{
public:
//리소스(상수버퍼, 텍스처 등)관리용 인터페이스 클래스
GameEngineShaderResourcesHelper PipeLineHelper;
private:
//렌더러가 가지고 있는 렌더링 파이프 라인
GameEngineRenderingPipeLine* PipeLine;
//그외 함수들
//
};
1-1. SetPipeLine(const stirng& _Name )
호출자 : GameEngineActor (렌더러가 만들어진 직후 호출)
하는 역할 : PipeLine을 검색 후 할당하고, 그 PipeLine이 필요로 하는 리소스를 확인한다.
확인 후, 필요한 데이터를 BufferMap에 Insert 한다.
<hide/>
void GameEngineDefaultRenderer::SetPipeLine(const std::string& _Name)
{
PipeLine = GameEngineRenderingPipeLine::Find(_Name);
if (nullptr == PipeLine)
{
MsgBoxAssert("존재하지 않는 파이프라인을 세팅하려고 했습니다.");
return;
}
//PipeLine의 리소스 체크
//필요한 리소스를 ResourcesHelper의 Map에 Insert
PipeLineHelper.ResourcesCheck(PipeLine);
//ResourcesHelpr의 ConstantBufferMap에 Transformdata가 있다면
//"자동"으로 렌더러의 TransformData와 쉐이더의 TransformData를 링크 시켜준다.
if (true == PipeLineHelper.IsConstantBufferSetter("TRANSFORMDATA"))
{
PipeLineHelper.SetConstantBufferLink("TRANSFORMDATA", &GetTransformData(), sizeof(GetTransformData()));
}
}
1-2. Render
호출자 : GameEngineCamera::Render
하는 역할 : 모든 리소스를 세팅하고, 정해진 렌더링 파이프 라인에 맞춰 렌더링 해준다.
<hide/>
void GameEngineDefaultRenderer::Render(float _DeltaTime)
{
if (nullptr == PipeLine)
{
MsgBoxAssert("랜더링 파이프라인이 세팅되지 않으면 랜더링을 할수 없습니다.");
}
// 준비된 모든 리소스들을 다 세팅해준다.
PipeLineHelper.AllResourcesSetting();
//렌더링
PipeLine->Rendering();
}
2. GameEngineShaderResourcesHelper
리소스(상수 버퍼, 텍스처 등) 관리용 인터페이스 클래스.
2-0. 멤버 변수
<hide/>
class GameEngineShaderResourcesHelper
{
friend GameEngineShader;
private:
//GameEngineShader의 ConstantBufferMap과 TextureSetterMap을 그대로 복사 받는 컨테이너
std::multimap<std::string, GameEngineConstantBufferSetter> ConstantBufferSetterMap;
std::multimap<std::string, GameEngineTextureSetter> TextureSetterMap;
//기타 함수들
};
2-1. ResourcesCheck & ShaderCheck
호출자 : GameEngineDefaultRenderer::SetPipeLine
하는 역할 : 쉐이더의 상수 버퍼 데이터와 텍스처 버퍼 데이터를 ResourcesHelper의 Map에 복사한다.
SettingFunction에 알맞는 함수를 연결해준다.
<hide/>
void GameEngineShaderResourcesHelper::ResourcesCheck(GameEngineRenderingPipeLine* _Line)
{
ShaderCheck(_Line->GetVertexShader());
ShaderCheck(_Line->GetPixelShader());
}
void GameEngineShaderResourcesHelper::ShaderCheck(GameEngineShader* _Shader)
{
for (const std::pair<std::string, GameEngineConstantBufferSetter>& Data : _Shader->ConstantBufferMap)
{
std::multimap<std::string, GameEngineConstantBufferSetter>::iterator InsertIter =
ConstantBufferMap.insert(std::make_pair(Data.first, Data.second));
GameEngineConstantBufferSetter& Setter = InsertIter->second;
//쉐이더 타입에 알맞는 Setting함수를 SettingFunction과 연결
switch (InsertIter->second.ShaderType)
{
case ShaderType::Vertex:
Setter.SettingFunction = std::bind(&GameEngineConstantBuffer::VSSetting, Setter.Res, Setter.BindPoint);
break;
case ShaderType::Pixel:
Setter.SettingFunction = std::bind(&GameEngineConstantBuffer::PSSetting, Setter.Res, Setter.BindPoint);
break;
default:
break;
}
}
for (const std::pair<std::string, GameEngineTextureSetter>& Data : _Shader->TextureSetterMap)
{
TextureSetterMap.insert(std::make_pair(Data.first, Data.second));
}
}
2-2. ConstantBufferSeterMap & TextureSetterMap
하는 역할 : GameEngineShader에 있는 ConstantBufferSetterMap과 TextureSetterMap의 데이터를 복사받는다.
GameEngineShader에 데이터 세팅 호출자는 GameEngineShader::ShaderResCheck()다.
MultiMap인 이유 : 픽셀 쉐이더, 버텍스 쉐이더에서 동일한 상수 버퍼를 사용한다면, 동일한 상수 버퍼의 이름이 Map에 들어가는데 이것은 즉 키값이 중복된다는 것이다. 이런 중복된 키를 처리하기 위해서 MultiMap을 사용했다.
중복된 키값에서 자료구조는 list다.
MultiMap을 사용한다면 lower_bound는 StartIterator가 되고 upper_bound는 EndIterator가 된다.
2-3. SetConstantBufferLink
호출자 : GameEngineDefaultRenderer::SetPipeLine (TransformData) & GameEngineActor (그 외 상수 버퍼)
하는 역할 : GameEngineConstantBufferSetter의 Data와 Size에 값을 할당한다. 이때 Data는 우리가 전달하려는 데이터의 포인터 주소, Size는 그 데이터의 크기다.
주의점 : Link를 할 경우 상수 버퍼와 Data는 포인터 형태로 이어진다. 이는 댕글링 포인터가 일어날 가능성이 있다는 말이다. 렌더러가 있는 자신 Actor의 데이터를 참조하면 문제가 없다. Actor가 사라지면 렌더러도 사라져서 댕글링 포인터가 일어날 일이 없어진다.
그러나 외부 Actor의 데이터를 참조할 경우, 만약 외부 Actor가 죽을경우 그 사실을 렌더러는 모르기 때문에 이미 delete된 외부 Actor의 데이터를 참조하려 할 것이다. 이런 경우는 Link하는 것이 매우 위험하다. New를 하자.
<hide/>
//사용자 인터페이스 함수
template<typename Res>
void SetConstantBufferLink(const std::string& _Name, const Res& Data)
{
SetConstantBufferLink(_Name , &Data, sizeof(Res));
}
//실제 함수
void GameEngineShaderResourcesHelper::SetConstantBufferLink(
const std::string& _Name,
const void* _Data,
UINT _Size)
{
if (false == IsConstantBufferSetter(_Name))
{
MsgBox("존재하지 않는 상수버퍼를 세팅하려고 했습니다.");
return;
}
//주의! 전달하려는 데이터는 최소 16바이트 이상이여야 한다.
if (16 > _Size)
{
MsgBox("최소한 16바이트 이상의 세팅을 해줘야 합니다.");
return;
}
//TransformData -> TRANSFORMDATA
std::string Name = GameEngineString::ToUpperReturn(_Name);
//멀티맵 순회
std::multimap<std::string, GameEngineConstantBufferSetter>::iterator NameStartIter
= ConstantBufferMap.lower_bound(Name);
std::multimap<std::string, GameEngineConstantBufferSetter>::iterator NameEndIter
= ConstantBufferMap.upper_bound(Name);
for (; NameStartIter != NameEndIter ; ++NameStartIter)
{
NameStartIter->second.SetData = _Data;
NameStartIter->second.Size = _Size;
}
}
2-3-1. SetConstantBufferNew
호출자 : GameEngineActor
하는 역할 : Link와는 달리, 넘겨 받는 Data를 깊은 복사 한다. 깊은 복사를 할 때 ConstantBufferSetter에 있는 OriginalData의 메모리에 데이터를 보관한다.
<hide/>
void GameEngineShaderResourcesHelper::SetConstantBufferNew(const std::string& _Name, const void* _Data, UINT _Size)
{
if (false == IsConstantBufferSetter(_Name))
{
MsgBox("존재하지 않는 상수버퍼를 세팅하려고 했습니다.");
return;
}
if (16 > _Size)
{
MsgBox("최소한 16바이트 이상의 세팅을 해줘야 합니다.");
return;
}
std::string Name = GameEngineString::ToUpperReturn(_Name);
std::multimap<std::string, GameEngineConstantBufferSetter>::iterator NameStartIter
= ConstantBufferMap.lower_bound(Name);
std::multimap<std::string, GameEngineConstantBufferSetter>::iterator NameEndIter
= ConstantBufferMap.upper_bound(Name);
for (; NameStartIter != NameEndIter; ++NameStartIter)
{
if (0 == NameStartIter->second.OriginalData.size()
|| NameStartIter->second.OriginalData.size() != _Size)
{
NameStartIter->second.OriginalData.resize(_Size);
}
NameStartIter->second.SetData = &NameStartIter->second.OriginalData[0];
memcpy_s(&NameStartIter->second.OriginalData[0], _Size, _Data, _Size);
NameStartIter->second.Size = _Size;
}
}
2-4. AllResourcesSetting
호출자 : GameEngineDefaultRenderer::Render
하는 역할 : ResourcesHelper의 ConstantBufferSetterMap을 순회하면서 Setter의 Setting() 함수를 호출한다.
<hide/>
void GameEngineShaderResourcesHelper::AllResourcesSetting()
{
for (const std::pair<std::string, GameEngineConstantBufferSetter>& Setter : ConstantBufferMap)
{
Setter.second.Setting();
}
}
3. GameEngineConstantBufferSetter
버텍스 쉐이더, 픽셀 쉐이더의 상수 버퍼 개수만큼 생성되는 클래스.
서로 다른 쉐이더에서 동일한 상수 버퍼를 만들려 하면, 새로 만들어지는 것이 아니라 이미 존재하는 상수 버퍼의 포인터 주소를 리턴한다. >> 따라서 구분할 정보가 필요한데 그 역할을 하는 것이 GameEngineConstantBufferSetter.
ConstantBufferSetter은 상수 버퍼의 주소를 가지고 있고 ShaderType, BindPoint, Name, 버퍼에 쓸 Data*, Size, OrignialData, SettingFunction 등을 들고 있다.
3-0. 멤버 변수
<hide/>
//이 부분은 텍스처도 상속받을 수 있게 별도로 상속 클래스로 만듬
class ShaderResSetter : public GameEngineNameObject
{
public:
ShaderType ShaderType;
int BindPoint;
std::function<void()> SettingFunction; //버텍스, 픽셀에 따라 Setting함수가 달라지니 functional사용
};
class GameEngineConstantBuffer;
class GameEngineConstantBufferSetter : public ShaderResSetter
{
public:
GameEngineConstantBuffer* Res;
// 각자가 가진 정보에 대한 주소
const void* SetData;
UINT Size;
// 자기메모리로 할당할 것이다.
std::vector<char> OriginalData;
//그외 함수들
};
3-1. Setting
호출자 : GameEngineShaderResourcesHelper::AllResourcesSetting
하는 역할 : 그래픽 카드에 존재하는 상수 버퍼 메모리에 접근해서 Data를 쓴 다음, 그 상수 버퍼와 쉐이더의 상수 버퍼를 이어준다.
<hide/>
void GameEngineConstantBufferSetter::Setting() const
{
Res->ChangeData(SetData, Size);
SettingFunction();
}
4. GameEngineConstantBuffer
실제 DirectX에서 사용하는 Buffer 관련 데이터를 가지고 있고, Buffer 생성, 삭제, 보관 등 사용자 인터페이스를 제공하는 클래스
4-0. 멤버 변수
<hide/>
class GameEngineConstantBuffer : public GameEngineNameObject
{
private:
//상수 버퍼 보관 컨테이너
static std::map<std::string, std::map<int, GameEngineConstantBuffer*>> NamedRes;
//Device를 통해 만들어진 버퍼의 메모리 주소
ID3D11Buffer* Buffer;
//Buffer에 대한 정보
D3D11_BUFFER_DESC BufferDesc;
//Reflection으로 부터 추출한 BufferDesc
D3D11_SHADER_BUFFER_DESC ShaderDesc;
//기타 함수들
};
4-1. Create
호출자 : 다양하지만... GameEngineShader::ShaderResCheck
하는 역할 : 생성할 때 상수 버퍼를 감싸는 GameEngineConstantBuffer가 동적 생성되고 이후 DirectX의 상수 버퍼를 만든다.
이때 이미 존재하는 상수 버퍼를 또 만들려고 하면 생성하는 것이 아닌 이미 존재하는 상수 버퍼의 주소를 리턴한다.
<hide/>
static GameEngineConstantBuffer* CreateAndFind(
const std::string& _Name,
D3D11_SHADER_BUFFER_DESC _Desc,
ID3D11ShaderReflectionConstantBuffer* _CBufferPtr
)
{
GameEngineConstantBuffer* FindBuffer = Find(_Name, _Desc.Size);
//이미 존재하는 상수버퍼라면 그 주소를 리턴
if (nullptr != FindBuffer)
{
return FindBuffer;
}
//GameEngineConstantBuffer 동적 생성
GameEngineConstantBuffer* NewBuffer = CreateResName(_Name, _Desc.Size);
//DirectX의 Buffer 생성
NewBuffer->Create(_Desc, _CBufferPtr);
return NewBuffer;
}
//DirectX의 상수 버퍼 생성
void GameEngineConstantBuffer::Create(const D3D11_SHADER_BUFFER_DESC& _Desc, ID3D11ShaderReflectionConstantBuffer* _CBufferPtr)
{
ShaderDesc = _Desc;
BufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
BufferDesc.ByteWidth = ShaderDesc.Size;
BufferDesc.Usage = D3D11_USAGE::D3D11_USAGE_DYNAMIC;
BufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_FLAG::D3D11_CPU_ACCESS_WRITE;
BufferDesc.MiscFlags = 0;
BufferDesc.StructureByteStride = 0;
//생성은 메모리와 관련된 일이므로 Device가 맡는다
if (S_OK != GameEngineDevice::GetDevice()->CreateBuffer(&BufferDesc, nullptr, &Buffer))
{
MsgBoxAssert("상수버퍼 생성에 실패했습니다.");
}
}
4-2. ChangeData
호출자 : GameEngineShaderResourcesHelper::AllResourcesSetting
하는 역할 : 그래픽 카드에 있는 상수 버퍼 메모리에 접근해서 그래픽 카드 잠시 Lock 하고 데이터를 쓴 후 다시 그래픽 카드를 Unlock 해준다.
<hide/>
void GameEngineConstantBuffer::ChangeData(const void* _Data, size_t _Size) const
{
if (_Data == nullptr)
{
MsgBoxAssertString(GetNameCopy() + " 데이터를 세팅해주지 않았습니다.");
}
if (BufferDesc.ByteWidth != _Size)
{
MsgBoxAssertString(GetNameCopy() + " 상수버퍼의 바이트 크기가 서로 맞지 않습니다.");
}
static D3D11_MAPPED_SUBRESOURCE SettingResources = {};
memset(&SettingResources, 0, sizeof(SettingResources));
// 그래픽카드 Lock & SettingResources에 그래픽카드 버퍼 접근권한 획득
GameEngineDevice::GetContext()->Map(Buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &SettingResources);
if (nullptr == SettingResources.pData)
{
MsgBoxAssert("그래픽카드 버퍼에 접근하지 못했습니다..");
}
// 상수 버퍼 메모리에 데이터 쓰기
memcpy_s(SettingResources.pData, BufferDesc.ByteWidth, _Data, BufferDesc.ByteWidth);
// Unlock.
GameEngineDevice::GetContext()->Unmap(Buffer, 0);
}
4-3. VSSetting & PSSetting
호출자 : GameEngineShaderResourcesHelper::AllResourcesSetting
하는 역할 : 그래픽 카드의 상수 버퍼와 쉐이더에 있는 CBuffer을 연결해준다.
<hide/>
void GameEngineConstantBuffer::VSSetting(int _BindPoint)
{
GameEngineDevice::GetContext()->VSSetConstantBuffers(_BindPoint, 1, &Buffer);
}
void GameEngineConstantBuffer::PSSetting(int _BindPoint)
{
GameEngineDevice::GetContext()->PSSetConstantBuffers(_BindPoint, 1, &Buffer);
}
'DirectX > 공부 내용' 카테고리의 다른 글
DirectX::FrameAnimation (0) | 2022.07.15 |
---|---|
DirectX:: Atlas Texture 처리 (0) | 2022.07.14 |
DirectX::GameEngineTexture & GameEngineSampler (0) | 2022.07.12 |
C++ Functional (0) | 2022.07.12 |
DirectX::동차 좌표계 (0) | 2022.07.06 |