충돌과 관련된 부분과 Picking과 관련된 부분을 공부하게 될텐데 앞서서 정리를 해본다.
RenderManager로 편리하게 쉐이더 코드를 연결했는데
조금씩 문제가 일어나고 있다.
쉐이더가 많아지고 동일한 쉐이더를 항상 사용하는게 아니다 보니까 각기 사용하는 방식이 달라지는데 그 때 마다 Init을 하게 되면 기본에 있던 애들이 날아가기 때문에 이 방식을 고수 할 수 없다. 쉐이더를 여러개를 써서 상황에 따라서 물체를 배치하거나 이런 부분이 필요하기 때문이다.
void RenderManager::Init(shared_ptr<Shader> shader)
{
_shader = shader;
_globalBuffer = make_shared<ConstantBuffer<GlobalDesc>>();
_globalBuffer->Create();
_globalEffectBuffer = _shader->GetConstantBuffer("GlobalBuffer"); // Global.fx의 GlobalBuffer가 매핑이 된다.
_transformBuffer = make_shared<ConstantBuffer<TransformDesc>>();
_transformBuffer->Create();
_transformEffectBuffer = _shader->GetConstantBuffer("TransformBuffer");
_lightBuffer = make_shared<ConstantBuffer<LightDesc>>();
_lightBuffer->Create();
_lightEffectBuffer = _shader->GetConstantBuffer("LightBuffer");
_materialBuffer = make_shared<ConstantBuffer<MaterialDesc>>();
_materialBuffer->Create();
_materialEffectBuffer = _shader->GetConstantBuffer("MaterialBuffer");
_boneBuffer = make_shared<ConstantBuffer<BoneDesc>>();
_boneBuffer->Create();
_boneEffectBuffer = _shader->GetConstantBuffer("BoneBuffer");
_keyframeBuffer = make_shared<ConstantBuffer<KeyframeDesc>>();
_keyframeBuffer->Create();
_keyframeEffectBuffer = _shader->GetConstantBuffer("KeyframeBuffer");
_tweenBuffer = make_shared<ConstantBuffer<InstancedTweenDesc>>();
_tweenBuffer->Create();
_tweenEffectBuffer = _shader->GetConstantBuffer("TweenBuffer");
}
global buffer는 그렇다 치더라도 나머지 부분들은 물체마다 있는 것이기 때문에 이렇게 넣는게 적합하지 않다라는 생각이 든다.
설계적인 부분에서 설명을 해보자면
처음에 설계를 할 때 너무 겁을 먹고 고민할 필요는 없다.
어디에 배치할지 모를 때는 지금처럼 Manager에 배치해서 작업을 하다가 나중에 위기 의식이 생기면 고치면 된다.
포폴을 만들 때도 바로 좋은 구조를 만들기 보다는 이런 저런 방식으로 실습을 하다 보면 방식이 옳다면 계속 나아가게 되겠지만 문제가 있으면 언젠가 꼬여서 후회할 일이 생긴다. 그럼 그 때 고치면 된다.
RenderManager에서 작업했던 코드들을 어디에 넣으면 될까가 고민이다.
분산하는 것도 방법이지만 어디서 뭘 관리하는지 기억이 안날 수 있다.
공용으로 모아 놓고서 필요한 것을 사용하되 물체마다 할 수 있게끔 만들어주면 될 것이고,
물체라고 하기엔 GameObject가 들고 있는 건 아니고 Shader와 연관이 있어서 Shader에서 뭔가 긁어 오는 부분이다. 그러다 보니까 쉐이더 코드에다가 얘네들을 이전시키는 게 가장 지금으로는 합리적이라는 생각이 든다.
1. RenderManager에서 Shader 관련 코드들을 Shader로 옮기기
Shader에서 잡동사니들을 관리한다.
RenderManager.h의
GlobalDesc _globalDesc;
shared_ptr<ConstantBuffer<GlobalDesc>> _globalBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _globalEffectBuffer;
TransformDesc _transformDesc;
shared_ptr<ConstantBuffer<TransformDesc>> _transformBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _transformEffectBuffer;
LightDesc _lightDesc;
shared_ptr<ConstantBuffer<LightDesc>> _lightBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _lightEffectBuffer;
MaterialDesc _materialDesc;
shared_ptr<ConstantBuffer<MaterialDesc>> _materialBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _materialEffectBuffer;
BoneDesc _boneDesc;
shared_ptr<ConstantBuffer<BoneDesc>> _boneBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _boneEffectBuffer;
KeyframeDesc _keyframeDesc;
shared_ptr<ConstantBuffer<KeyframeDesc>> _keyframeBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _keyframeEffectBuffer;
InstancedTweenDesc _tweenDesc;
shared_ptr<ConstantBuffer<InstancedTweenDesc>> _tweenBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _tweenEffectBuffer;
이 코드를 Shader.h로 옮겨준다.
// 정보를 밀어 넣기 위해
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 PushKeyframeData(const KeyframeDesc& desc);
void PushTweenData(const InstancedTweenDesc& desc);
이 push 시리즈들도 Shader.h로 옮겨준다.
Shader에서 얘네들을 관리하도록 만들어 본다.
RenderManager::Init에서 모든 버퍼들을 만들어 주고, 찾아주고 하는데
Shader에 다 몰빵해서 넣는다는 것은 한번에 모든 애들을 사용하는 경우는 사실상 없을 것이다.
Push 시리즈들을 다 만들기 보다는 필요한 애들마다 각각 만들어서 사용하는 방식으로 만들어 볼 것이다.
원래 했던 방식은 RenderManager::Init에서 싹 다 만드는 거였다.
RenderManager::Init의 globalBuffer 부분과
RenderManager::PushGlobalData의 코드를 Shader::PushGlobalData로 옮기고 수정한다.
void Shader::PushGlobalData(const Matrix& view, const Matrix& projection)
{
if (_globalEffectBuffer == nullptr)
{
_globalBuffer = make_shared<ConstantBuffer<GlobalDesc>>();
_globalBuffer->Create();
_globalEffectBuffer = GetConstantBuffer("GlobalBuffer"); // Global.fx의 GlobalBuffer가 매핑이 된다.
}
_globalDesc.V = view;
_globalDesc.P = projection;
_globalDesc.VP = view * projection;
_globalDesc.VInv = view.Invert();
_globalBuffer->CopyData(_globalDesc);
_globalEffectBuffer->SetConstantBuffer(_globalBuffer->GetComPtr().Get()); // 00. Global.fx의 GlobalBuffer로 밀어 넣는 작업을 해주고 있는 거다.
}
필요한 애들만 얘를 쓰고 그 때 마다 이런 식으로 연동을 해서 캐싱을 하는 방식으로 이어지게 된다고 볼 수 있다.
마찬가지로 transform과 나머지 잡동사니 정보들도 긁어서 똑같이 갖고 오면 된다.
void Shader::PushTransformData(const TransformDesc& desc)
{
if (_transformEffectBuffer == nullptr)
{
_transformBuffer = make_shared<ConstantBuffer<TransformDesc>>();
_transformBuffer->Create();
_transformEffectBuffer = GetConstantBuffer("TransformBuffer");
}
_transformDesc = desc;
_transformBuffer->CopyData(_transformDesc);
_transformEffectBuffer->SetConstantBuffer(_transformBuffer->GetComPtr().Get());
}
void Shader::PushLightData(const LightDesc& desc)
{
if (_lightEffectBuffer == nullptr)
{
_lightBuffer = make_shared<ConstantBuffer<LightDesc>>();
_lightBuffer->Create();
_lightEffectBuffer = GetConstantBuffer("LightBuffer");
}
_lightDesc = desc;
_lightBuffer->CopyData(_lightDesc);
_lightEffectBuffer->SetConstantBuffer(_lightBuffer->GetComPtr().Get());
}
void Shader::PushMaterialData(const MaterialDesc& desc)
{
if (_materialEffectBuffer == nullptr)
{
_materialBuffer = make_shared<ConstantBuffer<MaterialDesc>>();
_materialBuffer->Create();
_materialEffectBuffer = GetConstantBuffer("MaterialBuffer");
}
_materialDesc = desc;
_materialBuffer->CopyData(_materialDesc);
_materialEffectBuffer->SetConstantBuffer(_materialBuffer->GetComPtr().Get());
}
void Shader::PushBoneData(const BoneDesc& desc)
{
if (_boneEffectBuffer == nullptr)
{
_boneBuffer = make_shared<ConstantBuffer<BoneDesc>>();
_boneBuffer->Create();
_boneEffectBuffer = GetConstantBuffer("BoneBuffer");
}
_boneDesc = desc;
_boneBuffer->CopyData(_boneDesc);
_boneEffectBuffer->SetConstantBuffer(_boneBuffer->GetComPtr().Get());
}
void Shader::PushKeyframeData(const KeyframeDesc& desc)
{
if (_keyframeEffectBuffer == nullptr)
{
_keyframeBuffer = make_shared<ConstantBuffer<KeyframeDesc>>();
_keyframeBuffer->Create();
_keyframeEffectBuffer = GetConstantBuffer("KeyframeBuffer");
}
_keyframeDesc = desc;
_keyframeBuffer->CopyData(_keyframeDesc);
_keyframeEffectBuffer->SetConstantBuffer(_keyframeBuffer->GetComPtr().Get());
}
void Shader::PushTweenData(const InstancedTweenDesc& desc)
{
if (_transformEffectBuffer == nullptr)
{
_tweenBuffer = make_shared<ConstantBuffer<InstancedTweenDesc>>();
_tweenBuffer->Create();
_tweenEffectBuffer = GetConstantBuffer("TweenBuffer");
}
_tweenDesc = desc;
_tweenBuffer->CopyData(_tweenDesc);
_tweenEffectBuffer->SetConstantBuffer(_tweenBuffer->GetComPtr().Get());
}
2. RenderManager 코드를 삭제하고, 이름을 BindShaderDesc로 바꾸기
이제 RenderManager를 어떻게 해야 할까
이동한 것은 삭제하고
class RenderManager
{
DECLARE_SINGLE(RenderManager);
public:
// 셰이더 마다 연결해줘야 되는게 달라질테니까 셰이더를 세팅하는 부분
void Init(shared_ptr<Shader> shader);
void Update();
private:
shared_ptr<Shader> _shader;
이 부분을 다 삭제한다.
RenderManager.cpp의 코드도 다 삭제한다.
struct 관련된 정보들은 RenderManager.h에 들고 있긴 해야 한다.
옮기긴 그러니 파일이름을 BindShaderDesc로 바꾼다.
Shader의 Description 잡동사니들을 저장하는 용도로 수정을 해본다.
Engine/02. Managers 필터에서 Engine/98. Utils 필터로 옮긴다.
Shader.h에
#include"BindShaderDesc.h"
를 추가한다.
완성된 Shader코드는 다음과 같다.
#pragma once
#include "Pass.h"
#include "Technique.h"
#include"BindShaderDesc.h"
struct ShaderDesc
{
ComPtr<ID3DBlob> blob;
ComPtr<ID3DX11Effect> effect;
};
class Shader
{
public:
friend struct Pass;
public:
Shader(wstring file);
~Shader();
wstring GetFile() { return _file; }
ComPtr<ID3DX11Effect> Effect() { return _shaderDesc.effect; }
void Draw(UINT technique, UINT pass, UINT vertexCount, UINT startVertexLocation = 0);
void DrawIndexed(UINT technique, UINT pass, UINT indexCount, UINT startIndexLocation = 0, INT baseVertexLocation = 0);
void DrawInstanced(UINT technique, UINT pass, UINT vertexCountPerInstance, UINT instanceCount, UINT startVertexLocation = 0, UINT startInstanceLocation = 0);
void DrawIndexedInstanced(UINT technique, UINT pass, UINT indexCountPerInstance, UINT instanceCount, UINT startIndexLocation = 0, INT baseVertexLocation = 0, UINT startInstanceLocation = 0);
void Dispatch(UINT technique, UINT pass, UINT x, UINT y, UINT z);
ComPtr<ID3DX11EffectVariable> GetVariable(string name);
ComPtr<ID3DX11EffectScalarVariable> GetScalar(string name);
ComPtr<ID3DX11EffectVectorVariable> GetVector(string name);
ComPtr<ID3DX11EffectMatrixVariable> GetMatrix(string name);
ComPtr<ID3DX11EffectStringVariable> GetString(string name);
ComPtr<ID3DX11EffectShaderResourceVariable> GetSRV(string name);
ComPtr<ID3DX11EffectRenderTargetViewVariable> GetRTV(string name);
ComPtr<ID3DX11EffectDepthStencilViewVariable> GetDSV(string name);
ComPtr<ID3DX11EffectUnorderedAccessViewVariable> GetUAV(string name);
ComPtr<ID3DX11EffectConstantBuffer> GetConstantBuffer(string name);
ComPtr<ID3DX11EffectShaderVariable> GetShader(string name);
ComPtr<ID3DX11EffectBlendVariable> GetBlend(string name);
ComPtr<ID3DX11EffectDepthStencilVariable> GetDepthStencil(string name);
ComPtr<ID3DX11EffectRasterizerVariable> GetRasterizer(string name);
ComPtr<ID3DX11EffectSamplerVariable> GetSampler(string name);
private:
void CreateEffect();
ComPtr<ID3D11InputLayout> CreateInputLayout(ComPtr<ID3DBlob> fxBlob, D3DX11_EFFECT_SHADER_DESC* effectVsDesc, vector<D3D11_SIGNATURE_PARAMETER_DESC>& params);
private:
wstring _file;
ShaderDesc _shaderDesc;
D3DX11_EFFECT_DESC _effectDesc;
shared_ptr<StateBlock> _initialStateBlock;
vector<Technique> _techniques;
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 PushKeyframeData(const KeyframeDesc& desc);
void PushTweenData(const InstancedTweenDesc& desc);
private:
GlobalDesc _globalDesc;
shared_ptr<ConstantBuffer<GlobalDesc>> _globalBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _globalEffectBuffer;
TransformDesc _transformDesc;
shared_ptr<ConstantBuffer<TransformDesc>> _transformBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _transformEffectBuffer;
LightDesc _lightDesc;
shared_ptr<ConstantBuffer<LightDesc>> _lightBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _lightEffectBuffer;
MaterialDesc _materialDesc;
shared_ptr<ConstantBuffer<MaterialDesc>> _materialBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _materialEffectBuffer;
BoneDesc _boneDesc;
shared_ptr<ConstantBuffer<BoneDesc>> _boneBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _boneEffectBuffer;
KeyframeDesc _keyframeDesc;
shared_ptr<ConstantBuffer<KeyframeDesc>> _keyframeBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _keyframeEffectBuffer;
InstancedTweenDesc _tweenDesc;
shared_ptr<ConstantBuffer<InstancedTweenDesc>> _tweenBuffer;
ComPtr<ID3DX11EffectConstantBuffer> _tweenEffectBuffer;
};
class ShaderManager
{
public:
static ShaderDesc GetEffect(wstring fileName);
private:
static unordered_map<wstring, ShaderDesc> shaders;
};
#include "pch.h"
#include "Shader.h"
#include "Utils.h"
Shader::Shader(wstring file) : _file(L"..\\\\Shaders\\\\" + file)
{
_initialStateBlock = make_shared<StateBlock>();
{
DC->RSGetState(_initialStateBlock->RSRasterizerState.GetAddressOf());
DC->OMGetBlendState(_initialStateBlock->OMBlendState.GetAddressOf(), _initialStateBlock->OMBlendFactor, &_initialStateBlock->OMSampleMask);
DC->OMGetDepthStencilState(_initialStateBlock->OMDepthStencilState.GetAddressOf(), &_initialStateBlock->OMStencilRef);
}
CreateEffect();
}
Shader::~Shader()
{
}
void Shader::CreateEffect()
{
_shaderDesc = ShaderManager::GetEffect(_file);
_shaderDesc.effect->GetDesc(&_effectDesc);
for (UINT t = 0; t < _effectDesc.Techniques; t++)
{
Technique technique;
technique.technique = _shaderDesc.effect->GetTechniqueByIndex(t);
technique.technique->GetDesc(&technique.desc);
technique.name = Utils::ToWString(technique.desc.Name);
for (UINT p = 0; p < technique.desc.Passes; p++)
{
Pass pass;
pass.pass = technique.technique->GetPassByIndex(p);
pass.pass->GetDesc(&pass.desc);
pass.name = Utils::ToWString(pass.desc.Name);
pass.pass->GetVertexShaderDesc(&pass.passVsDesc);
pass.passVsDesc.pShaderVariable->GetShaderDesc(pass.passVsDesc.ShaderIndex, &pass.effectVsDesc);
for (UINT s = 0; s < pass.effectVsDesc.NumInputSignatureEntries; s++)
{
D3D11_SIGNATURE_PARAMETER_DESC desc;
HRESULT hr = pass.passVsDesc.pShaderVariable->GetInputSignatureElementDesc(pass.passVsDesc.ShaderIndex, s, &desc);
CHECK(hr);
pass.signatureDescs.push_back(desc);
}
pass.inputLayout = CreateInputLayout(_shaderDesc.blob, &pass.effectVsDesc, pass.signatureDescs);
pass.stateBlock = _initialStateBlock;
technique.passes.push_back(pass);
}
_techniques.push_back(technique);
}
for (UINT i = 0; i < _effectDesc.ConstantBuffers; i++)
{
ID3DX11EffectConstantBuffer* iBuffer;
iBuffer = _shaderDesc.effect->GetConstantBufferByIndex(i);
D3DX11_EFFECT_VARIABLE_DESC vDesc;
iBuffer->GetDesc(&vDesc);
}
for (UINT i = 0; i < _effectDesc.GlobalVariables; i++)
{
ID3DX11EffectVariable* effectVariable;
effectVariable = _shaderDesc.effect->GetVariableByIndex(i);
D3DX11_EFFECT_VARIABLE_DESC vDesc;
effectVariable->GetDesc(&vDesc);
}
}
ComPtr<ID3D11InputLayout> Shader::CreateInputLayout(ComPtr<ID3DBlob> fxBlob, D3DX11_EFFECT_SHADER_DESC* effectVsDesc, vector<D3D11_SIGNATURE_PARAMETER_DESC>& params)
{
std::vector<D3D11_INPUT_ELEMENT_DESC> inputLayoutDesc;
for (D3D11_SIGNATURE_PARAMETER_DESC& paramDesc : params)
{
D3D11_INPUT_ELEMENT_DESC elementDesc;
elementDesc.SemanticName = paramDesc.SemanticName;
elementDesc.SemanticIndex = paramDesc.SemanticIndex;
elementDesc.InputSlot = 0;
elementDesc.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
elementDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
elementDesc.InstanceDataStepRate = 0;
if (paramDesc.Mask == 1)
{
if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_UINT32)
elementDesc.Format = DXGI_FORMAT_R32_UINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_SINT32)
elementDesc.Format = DXGI_FORMAT_R32_SINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_FLOAT32)
elementDesc.Format = DXGI_FORMAT_R32_FLOAT;
}
else if (paramDesc.Mask <= 3)
{
if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_UINT32)
elementDesc.Format = DXGI_FORMAT_R32G32_UINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_SINT32)
elementDesc.Format = DXGI_FORMAT_R32G32_SINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_FLOAT32)
elementDesc.Format = DXGI_FORMAT_R32G32_FLOAT;
}
else if (paramDesc.Mask <= 7)
{
if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_UINT32)
elementDesc.Format = DXGI_FORMAT_R32G32B32_UINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_SINT32)
elementDesc.Format = DXGI_FORMAT_R32G32B32_SINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_FLOAT32)
elementDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
}
else if (paramDesc.Mask <= 15)
{
if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_UINT32)
elementDesc.Format = DXGI_FORMAT_R32G32B32A32_UINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_SINT32)
elementDesc.Format = DXGI_FORMAT_R32G32B32A32_SINT;
else if (paramDesc.ComponentType == D3D_REGISTER_COMPONENT_FLOAT32)
elementDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
}
string name = paramDesc.SemanticName;
std::transform(name.begin(), name.end(), name.begin(), toupper);
if (name == "POSITION")
{
elementDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
}
if (Utils::StartsWith(name, "INST") == true)
{
elementDesc.InputSlot = 1;
elementDesc.AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
elementDesc.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
elementDesc.InstanceDataStepRate = 1;
}
if (Utils::StartsWith(name, "SV_") == false)
inputLayoutDesc.push_back(elementDesc);
}
const void* code = effectVsDesc->pBytecode;
UINT codeSize = effectVsDesc->BytecodeLength;
if (inputLayoutDesc.size() > 0)
{
ComPtr<ID3D11InputLayout> inputLayout;
HRESULT hr = DEVICE->CreateInputLayout
(
&inputLayoutDesc[0]
, inputLayoutDesc.size()
, code
, codeSize
, inputLayout.GetAddressOf()
);
CHECK(hr);
return inputLayout;
}
return nullptr;
}
void Shader::Draw(UINT technique, UINT pass, UINT vertexCount, UINT startVertexLocation)
{
_techniques[technique].passes[pass].Draw(vertexCount, startVertexLocation);
}
void Shader::DrawIndexed(UINT technique, UINT pass, UINT indexCount, UINT startIndexLocation, INT baseVertexLocation)
{
_techniques[technique].passes[pass].DrawIndexed(indexCount, startIndexLocation, baseVertexLocation);
}
void Shader::DrawInstanced(UINT technique, UINT pass, UINT vertexCountPerInstance, UINT instanceCount, UINT startVertexLocation, UINT startInstanceLocation)
{
_techniques[technique].passes[pass].DrawInstanced(vertexCountPerInstance, instanceCount, startVertexLocation, startInstanceLocation);
}
void Shader::DrawIndexedInstanced(UINT technique, UINT pass, UINT indexCountPerInstance, UINT instanceCount, UINT startIndexLocation, INT baseVertexLocation, UINT startInstanceLocation)
{
_techniques[technique].passes[pass].DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation);
}
void Shader::Dispatch(UINT technique, UINT pass, UINT x, UINT y, UINT z)
{
_techniques[technique].passes[pass].Dispatch(x, y, z);
}
ComPtr<ID3DX11EffectVariable> Shader::GetVariable(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str());
}
ComPtr<ID3DX11EffectScalarVariable> Shader::GetScalar(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsScalar();
}
ComPtr<ID3DX11EffectVectorVariable> Shader::GetVector(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsVector();
}
ComPtr<ID3DX11EffectMatrixVariable> Shader::GetMatrix(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsMatrix();
}
ComPtr<ID3DX11EffectStringVariable> Shader::GetString(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsString();
}
ComPtr<ID3DX11EffectShaderResourceVariable> Shader::GetSRV(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsShaderResource();
}
ComPtr<ID3DX11EffectRenderTargetViewVariable> Shader::GetRTV(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsRenderTargetView();
}
ComPtr<ID3DX11EffectDepthStencilViewVariable> Shader::GetDSV(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsDepthStencilView();
}
ComPtr<ID3DX11EffectConstantBuffer> Shader::GetConstantBuffer(string name)
{
return _shaderDesc.effect->GetConstantBufferByName(name.c_str());
}
ComPtr<ID3DX11EffectShaderVariable> Shader::GetShader(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsShader();
}
ComPtr<ID3DX11EffectBlendVariable> Shader::GetBlend(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsBlend();
}
ComPtr<ID3DX11EffectDepthStencilVariable> Shader::GetDepthStencil(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsDepthStencil();
}
ComPtr<ID3DX11EffectRasterizerVariable> Shader::GetRasterizer(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsRasterizer();
}
ComPtr<ID3DX11EffectSamplerVariable> Shader::GetSampler(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsSampler();
}
ComPtr<ID3DX11EffectUnorderedAccessViewVariable> Shader::GetUAV(string name)
{
return _shaderDesc.effect->GetVariableByName(name.c_str())->AsUnorderedAccessView();
}
unordered_map<wstring, ShaderDesc> ShaderManager::shaders;
ShaderDesc ShaderManager::GetEffect(wstring fileName)
{
if (shaders.count(fileName) == 0)
{
ComPtr<ID3DBlob> blob;
ComPtr<ID3DBlob> error;
INT flag = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_PACK_MATRIX_ROW_MAJOR;
HRESULT hr = ::D3DCompileFromFile(fileName.c_str(), NULL, D3D_COMPILE_STANDARD_FILE_INCLUDE, NULL, "fx_5_0", flag, NULL, blob.GetAddressOf(), error.GetAddressOf());
if (FAILED(hr))
{
if (error != NULL)
{
string str = (const char*)error->GetBufferPointer();
MessageBoxA(NULL, str.c_str(), "Shader Error", MB_OK);
}
assert(false);
}
ComPtr<ID3DX11Effect> effect;
hr = ::D3DX11CreateEffectFromMemory(blob->GetBufferPointer(), blob->GetBufferSize(), 0, DEVICE.Get(), effect.GetAddressOf());
CHECK(hr);
shaders[fileName] = ShaderDesc{blob, effect};
}
ShaderDesc desc = shaders.at(fileName);
ComPtr<ID3DX11Effect> effect;
desc.effect->CloneEffect(D3DX11_EFFECT_CLONE_FORCE_NONSINGLE, effect.GetAddressOf());
return ShaderDesc{desc.blob, effect};
}
void Shader::PushGlobalData(const Matrix& view, const Matrix& projection)
{
if (_globalEffectBuffer == nullptr)
{
_globalBuffer = make_shared<ConstantBuffer<GlobalDesc>>();
_globalBuffer->Create();
_globalEffectBuffer = GetConstantBuffer("GlobalBuffer"); // Global.fx의 GlobalBuffer가 매핑이 된다.
}
_globalDesc.V = view;
_globalDesc.P = projection;
_globalDesc.VP = view * projection;
_globalDesc.VInv = view.Invert();
_globalBuffer->CopyData(_globalDesc);
_globalEffectBuffer->SetConstantBuffer(_globalBuffer->GetComPtr().Get()); // 00. Global.fx의 GlobalBuffer로 밀어 넣는 작업을 해주고 있는 거다.
}
void Shader::PushTransformData(const TransformDesc& desc)
{
if (_transformEffectBuffer == nullptr)
{
_transformBuffer = make_shared<ConstantBuffer<TransformDesc>>();
_transformBuffer->Create();
_transformEffectBuffer = GetConstantBuffer("TransformBuffer");
}
_transformDesc = desc;
_transformBuffer->CopyData(_transformDesc);
_transformEffectBuffer->SetConstantBuffer(_transformBuffer->GetComPtr().Get());
}
void Shader::PushLightData(const LightDesc& desc)
{
if (_lightEffectBuffer == nullptr)
{
_lightBuffer = make_shared<ConstantBuffer<LightDesc>>();
_lightBuffer->Create();
_lightEffectBuffer = GetConstantBuffer("LightBuffer");
}
_lightDesc = desc;
_lightBuffer->CopyData(_lightDesc);
_lightEffectBuffer->SetConstantBuffer(_lightBuffer->GetComPtr().Get());
}
void Shader::PushMaterialData(const MaterialDesc& desc)
{
if (_materialEffectBuffer == nullptr)
{
_materialBuffer = make_shared<ConstantBuffer<MaterialDesc>>();
_materialBuffer->Create();
_materialEffectBuffer = GetConstantBuffer("MaterialBuffer");
}
_materialDesc = desc;
_materialBuffer->CopyData(_materialDesc);
_materialEffectBuffer->SetConstantBuffer(_materialBuffer->GetComPtr().Get());
}
void Shader::PushBoneData(const BoneDesc& desc)
{
if (_boneEffectBuffer == nullptr)
{
_boneBuffer = make_shared<ConstantBuffer<BoneDesc>>();
_boneBuffer->Create();
_boneEffectBuffer = GetConstantBuffer("BoneBuffer");
}
_boneDesc = desc;
_boneBuffer->CopyData(_boneDesc);
_boneEffectBuffer->SetConstantBuffer(_boneBuffer->GetComPtr().Get());
}
void Shader::PushKeyframeData(const KeyframeDesc& desc)
{
if (_keyframeEffectBuffer == nullptr)
{
_keyframeBuffer = make_shared<ConstantBuffer<KeyframeDesc>>();
_keyframeBuffer->Create();
_keyframeEffectBuffer = GetConstantBuffer("KeyframeBuffer");
}
_keyframeDesc = desc;
_keyframeBuffer->CopyData(_keyframeDesc);
_keyframeEffectBuffer->SetConstantBuffer(_keyframeBuffer->GetComPtr().Get());
}
void Shader::PushTweenData(const InstancedTweenDesc& desc)
{
if (_transformEffectBuffer == nullptr)
{
_tweenBuffer = make_shared<ConstantBuffer<InstancedTweenDesc>>();
_tweenBuffer->Create();
_tweenEffectBuffer = GetConstantBuffer("TweenBuffer");
}
_tweenDesc = desc;
_tweenBuffer->CopyData(_tweenDesc);
_tweenEffectBuffer->SetConstantBuffer(_tweenBuffer->GetComPtr().Get());
}
이렇게 Shader 코드가 완성이 되었다.
3. RenderManager를 통해서 하는 부분을 shader를 통해 하도록 수정하기
이제 지금껏 작업했던 코드들을 싹 다 고쳐준다. Engine을 빌드하고 에러를 고쳐가며 문제를 해결하면 된다.
EnginePch.h에서 #include RenderManager.h 를 삭제하고
Define.h에서도 RenderManager를 삭제한다.
Camera의
void Camera::Update()
{
UpdateMatrix();
//RENDER->PushGlobalData(Camera::S_MatView, Camera::S_MatProjection);
}
주석처리를 하고,
ModelAnimator.h에
shared_ptr<Shader> GetShader() { return _shader; }
를 만들어 주고,
InstancingManager::RenderAnimRenderer에서
RENDER->PushTweenData(*tweenDesc.get());
를
vec[0]->GetModelAnimator()->GetShader()->PushTweenData(*tweenDesc.get());
이렇게 넣어주면 된다.
그 다음에
Light::Update에서
// RENDER->PushLightData(_desc);
일단 주석처리 한다.
Material::Update에서
RENDER->PushMaterialData(_desc);
을
_shader->PushMaterialData(_desc);
이렇게 고치면 된다.
ModelAnimator::RenderInstancing의
RENDER->PushBoneData(boneDesc);
은
_shader->PushBoneData(boneDesc);
ModelRenderer::RenderInstancing의
RENDER->PushBoneData(boneDesc);
은
_shader->PushBoneData(boneDesc);
Engine을 빌드하면 빌드가 된다.
4. MeshRenderer, ModelRenderer, ModelAnimator에서 Camera와 Light 부분 shader를 통해 케어하기
남은건 Camera랑 Light와 관련된 부분을 케어하는 것이다.
Camera와 Light는 Shader와 관련된 부분을 업데이트 하는 부분을 어디서 할 것인가가 고민이다.
Scene에서 camera와 light와 관련된 부분을 들고 있는게 이 때문이다.
프로그램이 돌아갈 수 있게 일시적인 코드를 넣어준다.
Scene.h에
unordered_set<shared_ptr<GameObject>> GetObjects() { return _objects; }
shared_ptr<GameObject> GetCamera() { return _cameras.empty() ? nullptr : *_cameras.begin(); }
shared_ptr<GameObject> GetLight() { return _lights.empty() ? nullptr : *_lights.begin(); }
이걸 추가하고, 이걸 이용해서 임시 처리를 해보도록 한다.
지금 단계에서는 Update를 하는 애가 누구누구 있냐면 Rendering을 하는 모든 애들
MeshRenderer, ModelRenderer, ModelAnimator 3총사에 대해서 관련된 부분들을 처리할 필요가 있다.
MeshRenderer에 가서
MeshRenderer::RenderInstancing에서 Camera와 Light와 관련된 부분을 처리해 보도록 한다.
MeshRenderer.cpp에
#include "Light.h"
을 추가하고,
MeshRenderer::RenderInstancing에
// GlobalData
shader->PushGlobalData(Camera::S_MatView, Camera::S_MatProjection);
// Light
auto lightObj = SCENE->GetCurrentScene()->GetLight();
if(lightObj)
shader->PushLightData(lightObj->GetLight()->GetLightDesc());
이 코드를 추가한뒤
복사 해서
ModelRenderer에 가서 붙여 넣고 수정한다.
ModelRenderer.cpp에
#include "Camera.h"
#include "Light.h"
를 추가하고
ModelRenderer::RenderInstancing에
// GlobalData
_shader->PushGlobalData(Camera::S_MatView, Camera::S_MatProjection);
// Light
auto lightObj = SCENE->GetCurrentScene()->GetLight();
if (lightObj)
_shader->PushLightData(lightObj->GetLight()->GetLightDesc());
붙여 넣고 수정한다.
이걸 또 복사해서
ModelAnimator.cpp에
#include "Camera.h"
#include "Light.h"
를 추가하고
ModelAnimator::RenderInstancing에
// GlobalData
_shader->PushGlobalData(Camera::S_MatView, Camera::S_MatProjection);
// Light
auto lightObj = SCENE->GetCurrentScene()->GetLight();
if (lightObj)
_shader->PushLightData(lightObj->GetLight()->GetLightDesc());
붙여 넣는다.
Engine을 빌드한다.
이제 RenderManager를 사용하지 않고, Shader에서 막바로 필요한 코드를 알아서 사용하게 될 것이기 때문에 훨씬 더 자유롭게 사용할 수 있다.
Client를 빌드하면 RenderManager가 하던 코드들에서 에러가 난다. 싹다 주석처리 한다.
5. 테스트하기
정상적으로 되는지가 궁금하니 Main.cpp의 WinMain에서
desc.app = make_shared<TextureBufferDemo>(); // 실행 단위
이렇게 해주고 실행을 한다.
코드는 바뀌었지만 정상적으로 실행이 된다.
이제는 쉐이더마다 독립적으로 각기마다 이펙트를 연결해가지고 할 수 있게 되었기 때문에 우리가 이전에 연결했던 그 Skybox 쉐이더 이런 것도 혼용해 가지고 여러개를 쉐이더를 불러서 사용할 준비가 끝났다.
이게 변화의 시작이다.
Camera와 Light 관련된 부분이 한 두개가 아니기 때문에 나중에 어떻게 될 것인가, 카메라는 어떤 경우는 나중에는 찍는 물체들이 레이어에 따라 가지고 정해진 물체만 찍을 것인데 그 물체를 어떻게 찍을지를 어떻게 할 것인가가 또 고민이고, 라이팅도 조명이 한 두개가 있는게 아니라 여러개가 있을 것이기 때문에 그럴 때 누가 업데이트 할것인지 여러 이슈들이 꼬여 있다.
그건 그 때 가서 고민하면 된다.
1차적으로 RenderManager를 제거 하고 Shader 코드에다가 모든 구조를 다 몰빵해가지고 넣어주는 개선 작업을 완료 했다.
본격적으로 다음주부터 쉐이더를 여러개를 등장 시켜서 작업할 것이기 때문에 그것에 관한 처리를 해 보았다.
'DirectX' 카테고리의 다른 글
79_Sphere Collider (0) | 2024.03.28 |
---|---|
78_Viewport (0) | 2024.03.27 |
76_StructureBuffer (0) | 2024.03.23 |
75_TextureBuffer (0) | 2024.03.22 |
74_System Value 분석 (0) | 2024.03.22 |
댓글