버퍼
버퍼란 Shader 프로그래밍에서 GPU 자원(ID3D11Buffer : ID3D11Resource)를 뜻한다.
버텍스 버퍼, 인덱스 버퍼, 상수 버퍼 등 이에 해당된다.
셰이더와 프로그램이 연동되는 변수라고 생각하면 편하다.
상수 버퍼
상수버퍼는 말 그대로 상수를 데이터를 보내주는 버퍼로,
앞서 얘기한 월드 변환 행렬, 뷰 변환 행렬, 투영 변환 행렬을 셰이더로 넘겨주어
각 정점에 곱할 수 있게 해 준다.
1. 상수버퍼에 넣어줄 구조체
struct CB_DATA
{
KMatrix matWorld;
KMatrix matView;
KMatrix matProj;
KMatrix matNormal;
KVector4 vLightDir;
KVector4 vValue; // 시간 값 xyzw
};
상수 버퍼 구조체를 이용해서 넘기면 편하게 받을 수 있다.
채워진 구조체 자체를 보낼 수 있기 때문이다.
2. 상수 버퍼 생성
HRESULT KObject::CreateConstantBuffer()
{
HRESULT hr = S_OK;
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC));
bd.ByteWidth = sizeof(CB_DATA);
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
D3D11_SUBRESOURCE_DATA data;
ZeroMemory(&data, sizeof(D3D11_SUBRESOURCE_DATA));
data.pSysMem = &m_cbData;
hr = g_pd3dDevice->CreateBuffer(&bd, &data, &m_pConstantBuffer);
if (FAILED(hr)) return hr;
return hr;
}
Direct 디바이스로 버퍼를 만드는 함수 CreateBuffer()로
m_pConstantBuffer주소에 버퍼를 만든다.
필요한 D3D11_BUFFER_DESC, D3D11_SUBRESOURCE_DATA 구조 포인터를 기입한다.
3. 상수버퍼의 갱신 및 셰이더 상수 버퍼 설정
자체적으로 구현된 렌더 파이프라인에 넣어주면 된다.
리소스, 상수버퍼와 셰이더의 변수와 연동한다.
pContext->UpdateSubresource(
m_pConstantBuffer.Get(), 0, NULL, &m_cbData, 0, 0);
pContext->VSSetConstantBuffers(0, 1, m_pConstantBuffer.GetAddressOf());
pContext->PSSetConstantBuffers(0, 1, m_pConstantBuffer.GetAddressOf());
0, 1 숫자는 0번째 슬롯에 1개를 보내겠다는 의미로
Buffers <- s가 붙었다는 것은 여러 개를 보낼 수 있다는 뜻이다.
자세한 함수 설명은 msdn을 참조..
4. 셰이더
//HLSL->c언와 유사하다.
//정점쉐이더는 반드시 float4:SV_POSITION(레지스터)로 반환한다.
//정점버퍼의 정점1개마다 호출된다.
//POSITION(시멘틱:의미구조)
cbuffer CBuf
{
matrix g_matWorld : packoffset(c0);
matrix g_matView : packoffset(c4);
matrix g_matProj : packoffset(c8);
float4 vLightDir : packoffset(c12);
float4 vValue : packoffset(c13);
};
struct VS_OUTPUT
{
float4 p : SV_POSITION;
float3 n : NORMAL;
float4 c : COLOR0;
float2 t : TEXCOORD0;
};
VS_OUTPUT VS(float3 p: POSITION, float3 n : NORMAL, float4 c : COLOR, float2 t : TEXTURE)
{
VS_OUTPUT pOut = (VS_OUTPUT)0;
float4 vLocal = float4(p,1.0f);
float4 vWorld = mul(vLocal, g_matWorld);
float4 vView = mul(vWorld, g_matView);
float4 vProj = mul(vView, g_matProj);
pOut.p = vProj;
pOut.n = n;
pOut.c = c;
pOut.t = t;
return pOut;
}
상단에 있는 것이 상수버퍼 구조체이다.
셰이더에서 상수버퍼는 레지스터 단위로 할당이 되어야 한다.
float4가 기준이다. 행렬인 경우 (Matrix)는 float4 4개가 있는 것과 같으므로
4개씩 늘어나고 float4는 1개씩 자리를 이동하는 모습이다.
결과 - 공간 변환 (박스 출력)
결과 - 상수버퍼로 시간을 전달, cos 값으로 정점 이동