4.Shader
이제 Shader부분을 클래스로 만들어주자
일단 기본적인 Vertex와 Pixel 쉐이더를 가지고 있을 Shader 클래스를 만들어주자
Shader.h
#pragma once
//쉐이더에서 리소스를 사용할 때 어디서사용할지 지칭하는
enum ShaderScope
{
//비트 플래그용도
SS_None = 0,
SS_VertexShader = (1 << 0),
SS_PixelShader = (1 << 1),
SS_Both= SS_VertexShader | SS_PixelShader,
};
//쉐이더 공용부
class Shader
{
public:
Shader(ComPtr<ID3D11Device> device);
virtual ~Shader();
virtual void Create(const wstring& path, const string& name, const string& version) abstract;
ComPtr<ID3DBlob> GetBlob() { return _blob; }
protected:
void LoadShaderFromFile(const wstring& path, const string& name, const string& version);
protected:
wstring _path;
string _name;
ComPtr<ID3D11Device> _device;
ComPtr<ID3DBlob> _blob = nullptr;
};
class VertexShader : public Shader
{
//부모클래스지정
using Super = Shader;
public:
VertexShader(ComPtr<ID3D11Device> device);
~VertexShader();
//VS
ComPtr<ID3D11VertexShader> GetComPtr() { return _vertexShader; }
virtual void Create(const wstring& path, const string& name, const string& version) override;
protected:
ComPtr<ID3D11VertexShader> _vertexShader = nullptr;
};
class PixelShader : public Shader
{
//부모클래스지정
using Super = Shader;
public:
PixelShader(ComPtr<ID3D11Device> device);
~PixelShader();
//PS
ComPtr<ID3D11PixelShader> GetComPtr() { return _pixelShader; }
virtual void Create(const wstring& path, const string& name, const string& version) override;
protected:
ComPtr<ID3D11PixelShader> _pixelShader = nullptr;
};
Shader.cpp
#include "pch.h"
#include "Shader.h"
Shader::Shader(ComPtr<ID3D11Device> device)
:_device(device)
{
}
Shader::~Shader()
{
}
/// <summary>
/// 쉐이더 로딩하는 함수
/// </summary>
/// <param name="path"></param>
/// <param name="name"></param>
/// <param name="version"></param>
/// <param name="blob"></param>
//쉐이더 파일을 건네주면 경로에 따라 로드해서 빌드한 결과물을 블롭에 전달
void Shader::LoadShaderFromFile(const wstring& path, const string& name, const string& version)
{
_path = path;
_name = name;
const uint32 compileFlag = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; //디버그 최적화 건너뛰기
HRESULT hr = ::D3DCompileFromFile(
path.c_str(),
nullptr,
D3D_COMPILE_STANDARD_FILE_INCLUDE,
name.c_str(),
version.c_str(),
compileFlag,
0,
_blob.GetAddressOf(),
nullptr
);
CHECK(hr);
}
VertexShader::VertexShader(ComPtr<ID3D11Device> device) : Super(device)
{
}
VertexShader::~VertexShader()
{
}
void VertexShader::Create(const wstring& path, const string& name, const string& version)
{
LoadShaderFromFile(path, name, version);
HRESULT hr = _device->CreateVertexShader(_blob->GetBufferPointer(),
_blob->GetBufferSize(), nullptr, _vertexShader.GetAddressOf());
CHECK(hr);
}
PixelShader::PixelShader(ComPtr<ID3D11Device> device) : Super(device)
{
}
PixelShader::~PixelShader()
{
}
void PixelShader::Create(const wstring& path, const string& name, const string& version)
{
LoadShaderFromFile(path, name, version);
HRESULT hr = _device->CreatePixelShader(_blob->GetBufferPointer(),
_blob->GetBufferSize(), nullptr, _pixelShader.GetAddressOf());
CHECK(hr);
}
이에 맞게 Game클래스도 수정해주자
블롭객체는 각 쉐이더에서 가지고 있기때문에 지워주고 한줄자리 코드들은 위로 옮겨주자
Game.h
//VS
shared_ptr<VertexShader> _vertexShader;
//RS
ComPtr<ID3D11RasterizerState> _rasterizerState = nullptr;
//PS
shared_ptr<PixelShader> _pixelShader;
Game.cpp
_vertexShader = make_shared<VertexShader>(_graphics->GetDevice());
_pixelShader = make_shared<PixelShader>(_graphics->GetDevice());
//정점정보
GeometryHelper::CreateRectangle(_geometry);
//정점버퍼
_vertexBuffer->Create(_geometry->GetVertices());
//IndexBuffer
_indexBuffer->Create(_geometry->GetIndices());
_vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0");
//인풋레이아웃
/// <summary>
/// 입력이 어떻게 이뤄져있는지
/// </summary>
_inputLayout->Create(VertexTextureData::descs, _vertexShader->GetBlob());
_pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0");
이제 쉐이더에 추가해서 정보를 지정해주고 cpu와 gpu사이의 통신창구를 만들어줘서 SRT 연산을 가능하게 하는
상수버퍼를 클래스로 만들어주자
그리고 주의해야할점이 템플릿클래스는 cpp파일에 구현부를 만들면 안된다! 라는 것이다
그리고 상수버퍼에는 deviceContext도 사용하기 때문에 생성자에 deviceContext도 받아주게 하자
ConstantBuffer.h
#pragma once
//템플릿클래스는 cpp파일에 구현부를 만들면 안된다!
template<typename T>
class ConstantBuffer
{
public:
ConstantBuffer(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext)
:_device(device),_deviceContext(deviceContext)
{
}
~ConstantBuffer(){}
ComPtr<ID3D11Buffer> GetComPtr() { return _constantBuffer; }
//상수버퍼 - cpu메모리 -> gpu 복사
//1단계 버퍼만들기
void Create()
{
D3D11_BUFFER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Usage = D3D11_USAGE_DYNAMIC; //CPU Write + GPU Read
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.ByteWidth = sizeof(T);
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; //매프레임마다 gpu에 고속복사
HRESULT hr = _device->CreateBuffer(&desc, nullptr, _constantBuffer.GetAddressOf());
CHECK(hr);
}
void CopyData(const T& data)
{
D3D11_MAPPED_SUBRESOURCE subResouce;
ZeroMemory(&subResouce, sizeof(subResouce));
//맵을 통해 값을 넣어줄 준비를 한다. 이후 값을 넣고(복사해주고) UNMAP
_deviceContext->Map(_constantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResouce);
::memcpy(subResouce.pData, &data, sizeof(data)); //바로 cpu-> gpu 넘어가게 된다.
_deviceContext->Unmap(_constantBuffer.Get(), 0);
}
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11DeviceContext> _deviceContext;
ComPtr<ID3D11Buffer> _constantBuffer;
};
이에 맞게 Game클래스도 바꿔주자
Game.h
shared_ptr<ConstantBuffer<TransformData>> _constantBuffer;
Game.cpp
_constantBuffer = make_shared<ConstantBuffer<TransformData>>(_graphics->GetDevice(), _graphics->GetDeviceContext());
void Game::Update()
{
//크기 회전 이동
Matrix matScale = Matrix::CreateScale(_localScale/3);
Matrix matRotation = Matrix::CreateRotationX(_localRotation.x);
matRotation *= Matrix::CreateRotationY(_localRotation.y);
matRotation *= Matrix::CreateRotationZ(_localRotation.z);
Matrix matTranslation = Matrix::CreateTranslation(_localposition);
Matrix matWorld = matScale * matRotation * matTranslation; //SRT
_transformData.matWorld = matWorld;
_constantBuffer->CopyData(_transformData);
}
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer->GetComPtr().GetAddressOf());
그리고 마지막으로 쉐이더리소스뷰 즉 각 텍스처에 관한 코드를 클래스로 만들어주자
Texture.h
#pragma once
//SRV - 이미지를 어떻게 쓸것인가 - 텍스처
class Texture
{
public:
Texture(ComPtr<ID3D11Device> device);
~Texture();
ComPtr<ID3D11ShaderResourceView> GetComPtr() { return _shaderResourceView; }
void Create(const wstring& path);
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11ShaderResourceView> _shaderResourceView;
};
Texture.cpp
#include "pch.h"
#include "Texture.h"
Texture::Texture(ComPtr<ID3D11Device> device)
:_device(device)
{
}
Texture::~Texture()
{
}
void Texture::Create(const wstring& path)
{
DirectX::TexMetadata md;
DirectX::ScratchImage img;
HRESULT hr = ::LoadFromWICFile(path.c_str(), WIC_FLAGS_NONE, &md, img);
CHECK(hr);
//쉐이더리소스뷰 만들기
hr = ::CreateShaderResourceView(_device.Get(), img.GetImages(), img.GetImageCount(), md, _shaderResourceView.GetAddressOf());
CHECK(hr);
}
이에 맞게 Game 클래스 코드도 수정해주자
Game.h
//SRV - 이미지를 어떻게 쓸것인가 - 텍스처
shared_ptr<Texture> _texture1;
Game.cpp
_texture1 = make_shared<Texture>(_graphics->GetDevice());
/// <summary>
/// 쉐이더 리소스 뷰
/// </summary>
_texture1->Create(L"cat.png");
동일한 결과가 나온다
5.레스터라이저와 State
이제 레스터라이저와 남아있는 Comptr을 클래스로 만들어주자
RasterizerState.h
#pragma once
class RasterizerState
{
public:
RasterizerState(ComPtr<ID3D11Device> device);
~RasterizerState();
ComPtr<ID3D11RasterizerState> GetComPtr() { return _rasterizerState; }
void Create();
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11RasterizerState> _rasterizerState;
};
RasterizerState.cpp
#include "pch.h"
#include "RasterizerState.h"
RasterizerState::RasterizerState(ComPtr<ID3D11Device> device)
:_device(device)
{
}
RasterizerState::~RasterizerState()
{
}
void RasterizerState::Create()
{
D3D11_RASTERIZER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
//기본 솔리드 / 백
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_BACK;
desc.FrontCounterClockwise = false;
HRESULT hr = _device->CreateRasterizerState(&desc, _rasterizerState.GetAddressOf());
CHECK(hr);
}
SamplerState.h
#pragma once
class SamplerState
{
public:
SamplerState(ComPtr<ID3D11Device> device);
~SamplerState();
ComPtr<ID3D11SamplerState> GetComPtr() { return _samplerState; }
void Create();
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11SamplerState> _samplerState;
};
SamplerState.cpp
#include "pch.h"
#include "SamplerState.h"
SamplerState::SamplerState(ComPtr<ID3D11Device> device)
:_device(device)
{
}
SamplerState::~SamplerState()
{
}
void SamplerState::Create()
{
D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
desc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
desc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
//순서대로 RGBA
desc.BorderColor[0] = 1;
desc.BorderColor[1] = 0;
desc.BorderColor[2] = 0;
desc.BorderColor[3] = 1;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.MaxAnisotropy = 16;
desc.MaxLOD = FLT_MAX;
desc.MinLOD = FLT_MIN;
desc.MipLODBias = 0.0f;
HRESULT hr = _device->CreateSamplerState(&desc, _samplerState.GetAddressOf());
CHECK(hr);
}
BlendState.h
#pragma once
class BlendState
{
public:
BlendState(ComPtr<ID3D11Device> device);
~BlendState();
const float* GetBlendFactor() { return &_blendFactor; }
uint32 GetSampleMask() { return _sampleMask; }
ComPtr<ID3D11BlendState> GetComPtr() { return _blendState; }
void Create(D3D11_RENDER_TARGET_BLEND_DESC blendDesc =
{
true, // BlendEnable
D3D11_BLEND_SRC_ALPHA, // SrcBlend
D3D11_BLEND_INV_SRC_ALPHA, // DestBlend
D3D11_BLEND_OP_ADD, // BlendOp
D3D11_BLEND_ONE, // SrcBlendAlpha
D3D11_BLEND_ZERO, // DestBlendAlpha
D3D11_BLEND_OP_ADD, // BlendOpAlpha
D3D11_COLOR_WRITE_ENABLE_ALL // RenderTargetWriteMask
}, float factor = 0.f);
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11BlendState> _blendState;
float _blendFactor = 0.f;
uint32 _sampleMask = 0xFFFFFFFF;
};
BlendState.cpp
#include "pch.h"
#include "BlendState.h"
BlendState::BlendState(ComPtr<ID3D11Device> device)
:_device(device)
{
}
BlendState::~BlendState()
{
}
void BlendState::Create(D3D11_RENDER_TARGET_BLEND_DESC blendDesc, float factor)
{
_blendFactor = factor;
D3D11_BLEND_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.AlphaToCoverageEnable = false;
desc.IndependentBlendEnable = false;
desc.RenderTarget[0] = blendDesc;
HRESULT hr = _device->CreateBlendState(&desc, _blendState.GetAddressOf());
CHECK(hr);
}
'게임공부 > Directx11' 카테고리의 다른 글
[Directx11][C++]12. 프레임워크 제작4(GameObject,Component) (1) | 2024.08.13 |
---|---|
[Directx11][C++]11. 프레임워크 제작3(Pipeline) (0) | 2024.08.12 |
[Directx11][C++]9. 프레임워크 제작(Graphics,Input Assembler,Geometry) (0) | 2024.07.31 |
[Directx11]8. Simple Math (0) | 2024.07.15 |
[Directx11]7. RasterizerState, SampleState, BlendState (0) | 2024.07.10 |