[DX] Framework - Pipeline

vector·2025년 11월 10일

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);
}

주요 필드 해설

필드의미
FillModeD3D11_FILL_SOLID(면), D3D11_FILL_WIREFRAME(와이어)
CullModeD3D11_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;	// U축 경계처리
	desc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;	// V축 경계처리
	desc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;	// W축 경계처리
	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 등)
BorderColorAddress 모드가 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;

	//desc.RenderTarget[0].BlendEnable = true; // 블렌딩 비활성화
	//desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; // SrcFactor
	//desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; // DstFactor
	//desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; // 합산
	//desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
	//desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
	//desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
	//desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; // RGBA 모두 쓰기

	_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());

		// 필요시 PS에도 설정가능
		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);

	// VS
	if (info.vertexShader)
		_deviceContext->VSSetShader(info.vertexShader->GetComPtr().Get(), nullptr, 0);
	// 상수버퍼는 사용할지 안할지 확실하지 않아서 포함x
	//_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer->GetComPtr().GetAddressOf());


	// RS
	if (info.rasterizerState)
		_deviceContext->RSSetState(info.rasterizerState->GetComPtr().Get());

	// PS
	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());
}

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);
}
profile
게임 클라이언트 프로그래머 준비중 (공부 및 기록용)

0개의 댓글