1. rasterizer, samplerState, blendState 클래스
애매한 3 총사, rasterizer, samplerState, blendState 3 총사를 정리하고,
다시 조립하는 것을 해볼 것이다.
03.Rasterizer에 RasterizerState,
04.PixelShader에 SamplerState,
05.OutputMeger에 BlendState 클래스를 추가한다.
Rasterizer는 VS에서 PS로 넘어가기 전에 Rasterizer에 대한 옵션을 선택할 수 있는 거,
SamplerState는 uv매핑을 할 때 어떤 식으로 할지 옵션과 관련
BlendState는 최종적으로 화면이 출력이 될 때 어떤 식으로 생상을 섞을지와 관련이 있었다.
#pragma once
class RasterizerState
{
public:
RasterizerState(ComPtr<ID3D11Device> device);
~RasterizerState();
ComPtr<ID3D11RasterizerState> GetComPtr() { return _rasterizerState; }
void Create();
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11RasterizerState> _rasterizerState;
};
#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);
}
Rasterizer는 이렇게 만들어 주면 되고,
마찬가지로 SamplerState도
#pragma once
class SamplerState
{
public:
SamplerState(ComPtr<ID3D11Device> device);
~SamplerState();
ComPtr<ID3D11SamplerState> GetComPtr() { return _samplerState; }
void Create();
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11SamplerState> _samplerState;
};
#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;
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도 비슷한 느낌으로 채워주면 된다.
#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,
D3D11_BLEND_SRC_ALPHA,
D3D11_BLEND_INV_SRC_ALPHA,
D3D11_BLEND_OP_ADD,
D3D11_BLEND_ONE,
D3D11_BLEND_ZERO,
D3D11_BLEND_OP_ADD,
D3D11_COLOR_WRITE_ENABLE_ALL
}, float factor = 0.f);
private:
ComPtr<ID3D11Device> _device;
ComPtr<ID3D11BlendState> _blendState;
float _blendFactor = 0.f;
uint32 _sampleMask = 0xFFFFFFFF;
};
#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(D3D11_BLEND_DESC));
desc.AlphaToCoverageEnable = false;
desc.IndependentBlendEnable = false;
desc.RenderTarget[0] = blendDesc;
HRESULT hr = _device->CreateBlendState(&desc, _blendState.GetAddressOf());
CHECK(hr);
}
Game클래스에서 옮겨준 부분은 삭제한다.
2. rasterizer, samplerState, blendState 클래스 적용
pch.h에 가서,
#include "RasterizerState.h"
#include "SamplerState.h"
#include "BlendState.h"
이렇게 추가하고,
Game.h로 가서 옮겨줬던 부분
//ComPtr<ID3D11RasterizerState> _rasterizerState = nullptr;
shared_ptr<RasterizerState> _rasterizerState;
//ComPtr<ID3D11SamplerState> _samplerState = nullptr;
shared_ptr<SamplerState> _samplerState;
//ComPtr<ID3D11BlendState> _blendState = nullptr;
shared_ptr<BlendState> _blendState;
이렇게 해주면,
#pragma once
class Game
{
public:
Game();
~Game();
public:
void Init(HWND hwnd);
void Update();
void Render();
private:
HWND _hwnd;
shared_ptr<Graphics> _graphics;
private:
shared_ptr<Geometry<VertexTextureData>> _geometry;
shared_ptr<VertexBuffer> _vertexBuffer;
shared_ptr<IndexBuffer> _indexBuffer;
shared_ptr<InputLayout> _inputLayout;
shared_ptr<VertexShader> _vertexShader;
shared_ptr<RasterizerState> _rasterizerState;
shared_ptr<PixelShader> _pixelShader;
shared_ptr<Texture> _texture1;
shared_ptr<SamplerState> _samplerState;
shared_ptr<BlendState> _blendState;
private:
TransformData _transformData;
shared_ptr<ConstantBuffer<TransformData>> _constantBuffer;
Vec3 _localPosition = { 0.f, 0.f, 0.f };
Vec3 _localRotation = { 0.f, 0.f, 0.f };
Vec3 _localScale = { 1.f, 1.f, 1.f };
};
이제 ComPtr이 없게 정리가 되었다.
Game.cpp에서 shared_ptr로 변환한 변수들을 채워준다.
Game::Init에
_rasterizerState = make_shared<RasterizerState>(_graphics->GetDevice());
_samplerState = make_shared<SamplerState>(_graphics->GetDevice());
_blendState = make_shared<BlendState>(_graphics->GetDevice());
_rasterizerState->Create();
_samplerState->Create();
_blendState->Create();
//CreateRasterizerState();
//CreateSamplerState();
//CreateBlendState();
인자를 넣어줄 수도 있지만 일단 기본 인자로 한다.
빌드를 하면 에러가 나는데 하나씩 수정해 주면 된다.
Game::Render에서
// RS
_deviceContext->RSSetState(_rasterizerState->GetComPtr().Get());
_deviceContext->PSSetSamplers(0, 1, _samplerState->GetComPtr().GetAddressOf());
// OM
_deviceContext->OMSetBlendState(_blendState->GetComPtr().Get(), nullptr, 0xFFFFFFFF);
이렇게 수정하고 빌드를 하면 통과된다.
// OM
_deviceContext->OMSetBlendState(_blendState->GetComPtr().Get(), _blendState->GetBlendFactor(), _blendState->GetSampleMask());
이렇게 하면 조금 더 맞춰 준 것에 정확해진다.
실행하면 이미지가 잘 나온다.
이렇게 1차적으로 정리가 끝났다.
3. Pipeline 클래스 공용부
부품들을 래핑 해서 관리할 수 있다 까지는 됐지만,
추가적으로 어떤 애들을 뭉쳐서 관리해야 될 것인가가 관건이다.
Game::Render에서 나중에 가면 물체 단위로 뭔가를 만들어 주게 된다.
다양한 게임 엑터들을 배치해서 하나씩 그려 주세요가 코드 흐름이 된다고 볼 수 있다.
그리고 매번 _deviceContext→IASet~~ 으로 세팅하는 부분들도 별도의 클래스로 빼가지고 관리를 해야 되겠다는 얘기가 된다.
렌더링 파이프라인 자체를 하나의 클래스로 빼가지고 이중으로 관리를 하는 거다. 장점은 대포를 쏜 다음에 대포에 총알 장전을 하듯, 렌더링 파이프라인이 하나의 큰 대포라고 보면 된다.
물체마다 갈아 끼우는 부분이 있을 텐데, 갈아 끼우는 부분만 하나의 포탄으로 만들어서 갈아 끼울 수 있게끔 만들어 주는 게 핵심이다.
현재 렌더링 파이프라인을 보면
void Game::Render()
{
_graphics->RenderBegin();
// IA - VS - RS - PS - OM
{
uint32 stride = sizeof(VertexTextureData);
uint32 offset = 0;
auto _deviceContext = _graphics->GetDeviceContext();
// IA
// 코딩하는게 아니라 세팅하는 거
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
_deviceContext->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
_deviceContext->IASetInputLayout(_inputLayout->GetComPtr().Get()); // 어떻게 생겨먹은 애인지 묘사해줘야 해
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 삼각형으로 인지를 해달라 부탁
// VS
// 코딩 가능
_deviceContext->VSSetShader(_vertexShader->GetComPtr().Get(), nullptr, 0);
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer->GetComPtr().GetAddressOf());
// RS
_deviceContext->RSSetState(_rasterizerState->GetComPtr().Get());
// PS
_deviceContext->PSSetShader(_pixelShader->GetComPtr().Get(), nullptr, 0);
_deviceContext->PSSetShaderResources(0, 1, _texture1->GetComPtr().GetAddressOf());
// _deviceContext->PSSetShaderResources(1, 1, _shaderResourceView2.GetAddressOf());
_deviceContext->PSSetSamplers(0, 1, _samplerState->GetComPtr().GetAddressOf());
// OM
_deviceContext->OMSetBlendState(_blendState->GetComPtr().Get(), _blendState->GetBlendFactor(), _blendState->GetSampleMask());
// _deviceContext->Draw(_vertices.size(), 0);
_deviceContext->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}
_graphics->RenderEnd();
}
_deviceContext를 이용해서 세팅을 하고 있다.
이 부분 자체를 편리하게 세팅할 수 있게 Pipeline이라는 이름으로 만들어 본다.
Pilpeline 필터에 Pipeline이란 이름으로 클래스를 추가한다.
deviceContext가 핵심이다.
다른 device가 다른 애들을 만들어 주는 데 사용되기 때문에 device가 핵심이었지만,
파이프라인은 deviceContext가 렌더링 파이프라인과 나머지 리소스들을 묶어주는, 자원을 매핑해 주는 게 역할을 해주기 때문에, deviceContext가 핵심이다.
#pragma once
// 기본적으로 모든애들이 공통적으로 사용하는 정보를 빼준다.이걸 세팅해서 포탄을 갈아 끼우는 것 처럼 작업을 해준다.
struct PipelineInfo
{
// Game.h에서 어떤 애들은 물체마다 고유하게 변하는 애들이 있고,
// shader 같이 물체마다 공유해서 사용하는 애들도 있다.
// 그런 부분들을 분리해서 관리해 본다.
// 이런 옵션들을 이용해 렌더링 파이프 라인을 고칠 수 있다고 연결을 해 놓는 거
shared_ptr<InputLayout> inputLayout;
shared_ptr<VertexShader> vertexShader; // 상용 엔진의 경우 공용 shader 하나를 돌려 쓰고, 일부 특정 물체는 전용 shader를 쓰는 경우가 많다.
shared_ptr<PixelShader> pixelShader;
shared_ptr<RasterizerState> rasterizerState;
shared_ptr<BlendState> blendState;
D3D11_PRIMITIVE_TOPOLOGY topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
};
// 이 정보를 토대로 포탄을 갈아 끼는 거다.
class Pipeline
{
public:
Pipeline(ComPtr<ID3D11DeviceContext> deviceContext);
~Pipeline();
void UpdatePipeline(PipelineInfo info); // 정보를 갈아 끼운다.
private:
ComPtr<ID3D11DeviceContext> _deviceContext;
};
#include "pch.h"
#include "Pipeline.h"
Pipeline::Pipeline(ComPtr<ID3D11DeviceContext> deviceContext)
: _deviceContext(deviceContext)
{
}
Pipeline::~Pipeline()
{
}
void Pipeline::UpdatePipeline(PipelineInfo info)
{
// Game::Render의 일부를 꺼내 온다. 일단 다 가져 온 다음에 걸러냈다.
// IA
// vertexBuffer, indexBuffer는 나중에
_deviceContext->IASetInputLayout(info.inputLayout->GetComPtr().Get()); // 어떻게 생겨먹은 애인지 묘사해줘야 해
_deviceContext->IASetPrimitiveTopology(info.topology); // 삼각형으로 인지를 해달라 부탁
// VS
// 왜 ConstantBuffer를 세팅하는 부분은 왜 info에 포함되지 않는걸까? ->상수 버퍼는 사용할지 말지가 명확하지 않기 때문이다.
// 물체 마다 달라질 수 있는 부분은 따로 별도의 함수를 빼줄 것이고, 여기서는 일반적인 공용 부분만 묶어준다. 그래서 여기서 뺐다.
if(info.vertexShader)
_deviceContext->VSSetShader(info.vertexShader->GetComPtr().Get(), nullptr, 0);
// RS
if(info.rasterizerState) // 이것도 사실 옵션이긴 하다. 있으면 세팅해준다.
_deviceContext->RSSetState(info.rasterizerState->GetComPtr().Get());
// PS
// shaderResource, sampler도 사용할지 말지 모르니 건너 띈다.
if(info.pixelShader)
_deviceContext->PSSetShader(info.pixelShader->GetComPtr().Get(), nullptr, 0);
// OM
if(info.blendState)
_deviceContext->OMSetBlendState(info.blendState->GetComPtr().Get(), info.blendState->GetBlendFactor(), info.blendState->GetSampleMask());
}
여기서 하고 싶은 이야기는 PipelineInfo라는 걸 채워서 넣어주면 기본적인 공통적인 부분들을 다 채워주게 된다.
4. Pipeline 클래스 세부
그다음에 세부적으로 필요한 나머지 부분들을 채워주게 된다.
Game::Render에서 지금까지는 테스트 용도로 사용했으니까 상수 버퍼가 있다고 가정을 하고, 텍스쳐가 있어서 셰이더를 넘겨주고 하는 걸 만들어서 잘 맞아떨어졌지만 이건 그때 그 때 달라질 수 있는 거니까 이런 식으로 하나의 함수로 다 만들어 주면 안되는 거였다.
그럼 나머지 부분을 하나씩 챙겨 준다.
// 버텍스 버퍼, 인덱스 버퍼를 채워주는 거
void SetVertexBuffer(shared_ptr<VertexBuffer> buffer);
void SetIndexBuffer(shared_ptr<IndexBuffer> buffer);
를 Pipeline.h에 선언하고, 구현을 해준다.
void Pipeline::SetVertexBuffer(shared_ptr<VertexBuffer> buffer)
{
uint32 stride = buffer->GetStride();
uint32 offset = buffer->GetOffset();
// Game::Render를 참고해서 만들어 보면
_deviceContext->IASetVertexBuffers(0, 1, buffer->GetComPtr().GetAddressOf(), &stride, &offset);
}
void Pipeline::SetIndexBuffer(shared_ptr<IndexBuffer> buffer)
{
_deviceContext->IASetIndexBuffer(buffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
}
이런 식으로 공용적이지 않은 부분들, 그 때 그 때 달라지는 부분들은 알아서 조립해 채우라고 열어준다.
ContantBuffer가 조금 복잡하다.
Game::Render에서 보면
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer->GetComPtr().GetAddressOf());
_constantBuffer가 어떻게 만들어졌는지 보면,
shared_ptr<ConstantBuffer<TransformData>> _constantBuffer;
ConstantBuffer에 TransformData를 담는 버퍼라고 타입이 정해져 있는데, TransformData는 그 때 그 때 달라질 수 있다. 하드코딩 해 줄 수 없기 때문에
Pipeline.h로 돌아가서 template으로 만들어 준다.
함수에 적용하는 건 적용한 애만 헤더에 만들어 주면 되고, 나머지 애들만 cpp에 만들어 주면 된다.
template<typename T>
void SetConstantBuffer(uint32 slot, shared_ptr<ConstantBuffer<T>> buffer)
{
_deviceContext->VSSetConstantBuffers(slot, 1, buffer->GetComPtr().GetAddressOf());
}
보면 VS영역에 Set을 해주는 거라 VS에서만 사용하는 건가 싶지만,
_deviceContext->PSSetConstantBuffers(slot, 1, buffer->GetComPtr().GetAddressOf());
PS 버전도 있다. 그 말은 상수 버퍼는 꼭 VS단에서만 사용하는 게 아니라는 얘기가 된다.
Default.hlsl을 만들 때 VS에서만 사용했었지만 나중에 다른 식으로 만들 때라면 어떤 용도로 사용할지 명시해 주는 것이고, 그걸 scope라는 걸로 받아 줄 것이다.
Shader.h에
enum ShaderScope
{
SS_None = 0,
SS_VertexShader = (1 << 0), // 1
SS_PixelShader = (1 << 1), // 비트 연산 2, 비트플래그 용도로 활용할 거란 힌트를 주는 거
SS_Both = SS_VertexShader | SS_PixelShader
};
이렇게 해줬었어. 비트 플래그가 싫다면 그냥 enum 숫자로 해서 if else로 하는 방식으로 만들어 줄 수도 있다.
template<typename T>
void SetConstantBuffer(uint32 slot, uint32 scope, shared_ptr<ConstantBuffer<T>> buffer)
{
if(scope & SS_VertexShader)
_deviceContext->VSSetConstantBuffers(slot, 1, buffer->GetComPtr().GetAddressOf());
if (scope & SS_PixelShader)
_deviceContext->PSSetConstantBuffers(slot, 1, buffer->GetComPtr().GetAddressOf());
}
이렇게 만들어 주면 된다.
그다음에 SetTexture, SetSamplerState도 마찬가지다.
// slot은 chiikawa일지 hachiware일지
// 텍스쳐를 받아서 세팅해 주는 부분까지 연동
void SetTexture(uint32 slot, uint32 scope, shared_ptr<Texture> texture);
void SetSamplerState(uint32 slot, uint32 scope, shared_ptr<SamplerState> samplerState);
선언하고, 구현부를 만든다.
void Pipeline::SetTexture(uint32 slot, uint32 scope, shared_ptr<Texture> texture)
{
if(scope & SS_VertexShader)
_deviceContext->VSSetShaderResources(slot, 1, texture->GetComPtr().GetAddressOf());
if (scope & SS_PixelShader)
_deviceContext->PSSetShaderResources(slot, 1, texture->GetComPtr().GetAddressOf());
}
void Pipeline::SetSamplerState(uint32 slot, uint32 scope, shared_ptr<SamplerState> samplerState)
{
if (scope & SS_VertexShader)
_deviceContext->VSSetSamplers(0, 1, samplerState->GetComPtr().GetAddressOf());
if (scope & SS_PixelShader)
_deviceContext->PSSetSamplers(0, 1, samplerState->GetComPtr().GetAddressOf());
}
이렇게 Pipeline은 완성이 되었고,
공용적인 부분, 그리고 세부적으로 하나씩 채우는 부분까지 만들어 놨다.
그리고 마지막에 DrawIndexed라고 그림을 그려주는 부분이 포함되어야 하다.
void Draw(uint32 vertexCount, uint32 startVertexLocation);
void DrawIndexed(uint32 indexCount, uint32 startIndexLocation, uint32 baseVertexLocation);
이 둘의 차이는 무엇일까?
DrawIndexed는 indexBuffer까지 적용하는 경우 사용한다.
일반적인 정점만 이용할 때는 draw 버전을 사용했다. Game::Render에서 주석 처리 했던 부분을 복원해서 사용해서 구현해 준다.
void Pipeline::Draw(uint32 vertexCount, uint32 startVertexLocation)
{
_deviceContext->Draw(vertexCount, startVertexLocation);
}
void Pipeline::DrawIndexed(uint32 indexCount, uint32 startIndexLocation, uint32 baseVertexLocation)
{
_deviceContext->DrawIndexed(indexCount, startIndexLocation, baseVertexLocation);
}
여기까지 적용하면 끝난 거다.
빌드를 하면 성공한다.
전체적인 파이프라인 과정을 파이프라인과 클래스로 묶어준 것이다.
결국 한번 더 원하는 방식으로 묶어 줄 수 있게 되었다.
5. Pipeline 클래스 적용
파이프라인이라는 게 결국 렌더링 파이프라인을 묘사하는 것이니까,
pch.h에 가서
#include "Pipeline.h"
을 추가하고,
Game.h에 가서,
shared_ptr<Pipeline> _pipeline;
을 추가한다.
Game::Init에 가서
_pipeline = make_shared<Pipeline>(_graphics->GetDeviceContext());
을 추가한다.
Pipeline으로 Game::Render에서 하나씩 묶어줬던 것을 공용적인 건 하나로 묶어서 할 수 있게 되었다.
Game::Render에 가서 PipelineInfo를 만들어 준다. 한 번 더 묶을 것이기 때문에 아직 끝난 게 아니다.
void Game::Render()
{
_graphics->RenderBegin();
// IA - VS - RS - PS - OM
{
PipelineInfo info;
info.inputLayout = _inputLayout;
info.vertexShader = _vertexShader;
info.pixelShader = _pixelShader;
info.rasterizerState = _rasterizerState;
info.blendState = _blendState;
_pipeline->UpdatePipeline(info);
이렇게 하면 굉장히 많은 부분이 한 번에 챙겨지게 된다.
핵심적인 부분들은 일단 다 챙겨진다고 볼 수 있다.
챙겨진 부분들은 Game::Render에서 삭제해 준다.
나머지 부분도 한번 더 묶어서 오브젝트로 관리할 수 있게 된다.
void Game::Render()
{
_graphics->RenderBegin();
// IA - VS - RS - PS - OM
{
PipelineInfo info;
info.inputLayout = _inputLayout;
info.vertexShader = _vertexShader;
info.pixelShader = _pixelShader;
info.rasterizerState = _rasterizerState;
info.blendState = _blendState;
_pipeline->UpdatePipeline(info);
auto _deviceContext = _graphics->GetDeviceContext();
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
_deviceContext->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer->GetComPtr().GetAddressOf());
_deviceContext->PSSetShaderResources(0, 1, _texture1->GetComPtr().GetAddressOf());
_deviceContext->PSSetSamplers(0, 1, _samplerState->GetComPtr().GetAddressOf());
_deviceContext->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}
_graphics->RenderEnd();
}
일단 여기까지 정리가 된 것이다.
이제 직은 하나하나 부분들은 인위적으로 세팅하는 부분이 들어간다고 볼 수 있다.
void Game::Render()
{
_graphics->RenderBegin();
// IA - VS - RS - PS - OM
{
PipelineInfo info;
info.inputLayout = _inputLayout;
info.vertexShader = _vertexShader;
info.pixelShader = _pixelShader;
info.rasterizerState = _rasterizerState;
info.blendState = _blendState;
_pipeline->UpdatePipeline(info);
_pipeline->SetVertexBuffer(_vertexBuffer);
_pipeline->SetIndexBuffer(_indexBuffer);
_pipeline->SetConstantBuffer(0, SS_VertexShader, _constantBuffer);
_pipeline->SetTexture(0, SS_PixelShader, _texture1);
_pipeline->SetSamplerState(0, SS_PixelShader, _samplerState);
_pipeline->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}
_graphics->RenderEnd();
}
일단 1차적으로 이렇게 정리가 되었다.
조금 더 쉽게 사용할 수 있게 되었다.
빌드하고, 실행하면 예전과 같이 잘 작동한다.
세세한 함수들에 대한 걸 기억할 필요 없이 똑같이 만들어줘서 pipeline이란 걸 묶어서 렌더링 파이프라인을 묘사할 수 있게 되었다는 특징이 생기게 된 거다.
'DirectX' 카테고리의 다른 글
24. 엔진구조_Component (0) | 2024.01.17 |
---|---|
22. 프레임워크 제작_GameObject (0) | 2024.01.05 |
20. 프레임워크 제작_Shader (0) | 2024.01.03 |
19. 프레임워크 제작_Geometry (0) | 2024.01.02 |
18. 프레임워크 제작_InputAssembler (0) | 2024.01.01 |
댓글