1. RasterizerState
- 정점(Vertex)을 받아서 화면 픽셀 단위(Fragment)로 변환하는 단계
#pragma once
class RasterizerState
{
public:
RasterizerState(ComPtr<ID3D11Device> device);
~RasterizerState();
ComPtr<ID3D11RasterizerState> GetComPtr() const { 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;
desc.DepthClipEnable = false;
desc.ScissorEnable = false;
desc.MultisampleEnable = false;
desc.AntialiasedLineEnable = false;
HRESULT hr = _device->CreateRasterizerState(&desc, _rasterizerState.GetAddressOf());
CHECK(hr);
}
주요 필드 해설
| 필드 | 의미 |
|---|
| FillMode | D3D11_FILL_SOLID(면), D3D11_FILL_WIREFRAME(와이어) |
| CullMode | D3D11_CULL_BACK, D3D11_CULL_FRONT, D3D11_CULL_NONE |
| FrontCounterClockwise | 삼각형의 앞면 기준 (시계/반시계) |
| DepthClipEnable | 깊이 버퍼 밖의 픽셀을 잘라낼지 여부 |
| MultisampleEnable | 멀티샘플링 안티앨리어싱 활성화 여부 |
게임 사용 예시
- 3D 모델 렌더링 : 뒷면 제거(
CullBack)으로 성능 향상
- 디버그용 와이어 프레임 :
FillMode = D3D11_FILL_WIREFRAME
- 양면 렌더링(예 나뭇잎 텍스처) :
CullMode = D3D_CULL_NONE
2. SamplerState
- 쉐이더에서 텍스처를 불러올 때 픽셀 좌표가 정수 단위가 아닐 때 보간하는 방식
#pragma once
class SamplerState
{
public:
SamplerState(ComPtr<ID3D11Device> device);
~SamplerState();
ComPtr<ID3D11SamplerState> GetComPtr() const { 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;
_device->CreateSamplerState(&desc, _samplerState.GetAddressOf());
}
주요 필드 해설
| 필드 | 의미 |
|---|
| AddressU/V/W | 텍스처 경계 처리 방식 (Wrap, Clamp, Border 등) |
| Filter | 텍스처 보간 방법 (Point, Linear, Anisotropic 등) |
| BorderColor | Address 모드가 Border일 때 적용되는 색 |
| MaxAnisotropy | 이방성 필터링의 품질 설정 |
| ComparisonFunc | 그림자 맵 샘플링 등에서 깊이 비교 시 사용 |
게임 사용 예시
- 픽셀 보간 : 저해상도 텍스처일 때 Linear로 부드럽게 보간
- 픽셀 아트 : Filter = D3D11_FILTER_MIN_MAG_MIP_POINT
- 경계색 효과 : BorderColor로 텍스처 바깥 색칠 (예 UI glow)
3. BlendState
- 출력 단계(OM)에서 이미 그려진 픽셀(배경)과 새로 그릴 픽셀(전경)의 색을 어떻게 섞을지 정의
#pragma once
class BlendState
{
public:
BlendState(ComPtr<ID3D11Device> device);
~BlendState();
const float* GetBlendFactor() const { return &_blendFactor; }
uint32 GetSampleMask() const { return _sampleMask; }
ComPtr<ID3D11BlendState> GetComPtr() const { 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.1f);
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(desc));
desc.AlphaToCoverageEnable = false;
desc.IndependentBlendEnable = false;
desc.RenderTarget[0] = blendDesc;
_device->CreateBlendState(&desc, _blendState.GetAddressOf());
}
주요 개념
- SrcBlend : 현재 픽셀(앞면)의 색 가중치
- DestBlend : 기존 픽실(배경)의 색 가중치
- BlendOp : 두 색을 더하거나 빼는 공식
게임 사용 예시
- 투명 유리창
- 빛 번짐(Additive)
- 파티클 엔진 불꽃
4. Pipeline
- 지금까지 만든 모든 상태 객체와 쉐이더, 버퍼를 하나의 렌더링 컨텍스트(DeviceContext)에 세팅하는 통합 제어 클래스
#pragma once
struct PipelineInfo
{
shared_ptr<InputLayout> inputLayout;
shared_ptr<VertexShader> vertexShader;
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);
void SetVertexBuffer(shared_ptr<VertexBuffer> buffer);
void SetIndexBuffer(shared_ptr<IndexBuffer> buffer);
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());
}
void SetTexture(uint32 slot, uint32 scope, shared_ptr<Texture> texture);
void SetSamplerState(uint32 slot, uint32 scope, shared_ptr<SamplerState> samplerState);
void Draw(uint32 vertexCount, uint32 startVertexLocation);
void DrawIndexed(uint32 indexCount, uint32 startIndexLocation, int baseVertexLocation);
private:
ComPtr<ID3D11DeviceContext> _deviceContext;
};
#include "pch.h"
#include "Pipeline.h"
Pipeline::Pipeline(ComPtr<ID3D11DeviceContext> deviceContext)
: _deviceContext(deviceContext)
{
}
Pipeline::~Pipeline()
{
}
void Pipeline::UpdatePipeline(PipelineInfo info)
{
_deviceContext->IASetInputLayout(info.inputLayout->GetComPtr().Get());
_deviceContext->IASetPrimitiveTopology(info.topology);
if (info.vertexShader)
_deviceContext->VSSetShader(info.vertexShader->GetComPtr().Get(), nullptr, 0);
if (info.rasterizerState)
_deviceContext->RSSetState(info.rasterizerState->GetComPtr().Get());
if (info.pixelShader)
_deviceContext->PSSetShader(info.pixelShader->GetComPtr().Get(), nullptr, 0);
if (info.blendState)
_deviceContext->OMSetBlendState(info.blendState->GetComPtr().Get(), info.blendState->GetBlendFactor(), info.blendState->GetSampleMask());
}
void Pipeline::SetVertexBuffer(shared_ptr<VertexBuffer> buffer)
{
uint32 stride = buffer->GetStride();
uint32 offset = buffer->GetOffset();
_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);
}
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(slot, 1, samplerState->GetComPtr().GetAddressOf());
if (scope & SS_PixelShader)
_deviceContext->PSSetSamplers(slot, 1, samplerState->GetComPtr().GetAddressOf());
}
void Pipeline::Draw(uint32 vertexCount, uint32 startVertexLocation)
{
_deviceContext->Draw(vertexCount, startVertexLocation);
}
void Pipeline::DrawIndexed(uint32 indexCount, uint32 startIndexLocation, int baseVertexLocation)
{
_deviceContext->DrawIndexed(indexCount, startIndexLocation, baseVertexLocation);
}