반응형
Constant Buffer
# 상수 버퍼 활용 예제는 조금 바뀐게 많으므로 업데이트한 파일의 전체 소스를 첨부함.
# mathHeader_L.h은 그냥 만든게 아까워서 쓰는 것일뿐이니 D3D수학 라이브러리의 내용을 쓰는 것이 좋다.
VS.hlsl
//상수 버퍼
cbuffer cb0
{
float4 Color : packoffset(c0);
float fTime : packoffset(c1.x);
};
//정점 쉐이더 반환값 구조체
struct VS_OUTPUT
{
float4 Position : SV_Position; // vertex position
float4 ColorChange : COLOR0; // vertex diffuse color
};
//정점 쉐이더
VS_OUTPUT VS(float3 p : POSITION)
{
VS_OUTPUT Output;
float3 vPos = p * fTime; // 0 <= fTime <= 1.0f
Output.Position = float4(vPos, 1.0f);
Output.ColorChange = Color;
return Output;
}
PS.hlsl
//정점 쉐이더 반환값 구조체
struct VS_OUTPUT
{
float4 Position : SV_Position; // vertex position
float4 ColorChange : COLOR0; // vertex diffuse color
};
//픽셀 쉐이더
float4 PS(VS_OUTPUT input) : SV_Target
{
return input.ColorChange;
}
sample.h
#pragma once
#pragma comment(lib, "TLib.lib")
#include "zCore.h"
#include "mathHeader_L.h"
namespace Lypi
{
struct Point3
{
float x;
float y;
float z;
};
struct VSCB
{
float4 vColor; // c0
// c1 - 쉐이더에는 실수4개 단위로 전달된다.
float fTime;
float fC5_Y;
float fC5_Z;
float fC5_W;
};
class Sample : public zCore
{
// 버텍스 버퍼 및 레이아웃
ID3D11Buffer* m_pVertexBuffer; //정점 버퍼 인터페이스
ID3D11Buffer* m_pIndexBuffer; //인덱스 버퍼 인터페이스
ID3D11Buffer* m_pConstantBuffer; //상수 버퍼 인터페이스
ID3D11InputLayout* m_pVertexLayout; //정점 레이아웃 인터페이스
// 버텍스 및 픽셀 쉐이더
ID3D11VertexShader* m_pVS; //정점 쉐이더 인터페이스
ID3D11PixelShader* m_pPS; //픽셀 쉐이더 인터페이스
UINT m_PrimType;;
public:
HRESULT CreateVertexBuffer(); // 정점 버퍼 생성
HRESULT CreateIndexBuffer(); // 인덱스 버퍼 생성
HRESULT CreateConstantBuffer(); // 상수 버퍼 생성
HRESULT LoadShaderAndInputLayout(); // 정점 및 픽쉘 쉐이더 로딩 및 생성
public:
bool Init();
bool Frame();
bool Render();
bool Release();
public:
Sample(LPCTSTR LWndName);
virtual ~Sample();
};
}
sample.cpp
#include "sample.h"
namespace Lypi
{
Sample::Sample(LPCTSTR LWndName) : zCore(LWndName)
{
m_pVertexBuffer = NULL;
m_pIndexBuffer = NULL;
m_pConstantBuffer = NULL;
m_pVertexLayout = NULL;
m_pVS = NULL;
m_pPS = NULL;
m_PrimType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
}
HRESULT Sample::CreateVertexBuffer()
{
HRESULT hr = S_OK;
//시계 방향으로 지정할 것.
Point3 vertices[] =
{
{ -0.5f, +0.5f, 0.5f },
{ +0.5f, +0.5f, 0.5f },
{ +0.5f, -0.5f, 0.5f },
{ -0.5f, -0.5f, 0.5f },
};
UINT numVertices = sizeof(vertices) / sizeof(vertices[0]);
// CD3D11_BUFFER_DESC : 버퍼 크기와 버퍼 용도만 결정하면 나머지는 기본값으로 생성해주는 구조체.
CD3D11_BUFFER_DESC cbc(sizeof(Point3) * numVertices, D3D11_BIND_VERTEX_BUFFER);
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(D3D11_SUBRESOURCE_DATA));
InitData.pSysMem = vertices;
V_FRETURN(g_pD3dDevice->CreateBuffer(&cbc, &InitData, &m_pVertexBuffer));
return hr;
}
HRESULT Sample::CreateIndexBuffer()
{
HRESULT hr = S_OK;
WORD indices[] =
{
0,1,2,
0,2,3,
};
UINT iNumIndex = sizeof(indices) / sizeof(indices[0]);
CD3D11_BUFFER_DESC cib(iNumIndex * sizeof(WORD), D3D11_BIND_INDEX_BUFFER);
D3D11_SUBRESOURCE_DATA ibInitData;
ZeroMemory(&ibInitData, sizeof(D3D11_SUBRESOURCE_DATA));
ibInitData.pSysMem = indices;
V_FRETURN(g_pD3dDevice->CreateBuffer(&cib, &ibInitData, &m_pIndexBuffer));
return hr;
}
HRESULT Sample::CreateConstantBuffer()
{
HRESULT hr;
//구조체의 값을 생성자에서 줄 수 있다.
CD3D11_BUFFER_DESC cbDesc(sizeof(VSCB), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE);
V_FRETURN(g_pD3dDevice->CreateBuffer(&cbDesc, NULL, &m_pConstantBuffer));
return hr;
}
HRESULT Sample::LoadShaderAndInputLayout()
{
HRESULT hr = S_OK;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( _DEBUG ) || defined( _DEBUG )
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif
ID3DBlob* pVSBuf = NULL;
V_FRETURN(D3DX11CompileFromFile(L"../../INPUT/DATA/Shader/sample/VS.hlsl", NULL, NULL, "VS", "vs_5_0", dwShaderFlags, NULL, NULL, &pVSBuf, NULL, NULL));
V_FRETURN(g_pD3dDevice->CreateVertexShader((DWORD*)pVSBuf->GetBufferPointer(), pVSBuf->GetBufferSize(), NULL, &m_pVS));
SIZE_T vsSize = pVSBuf->GetBufferSize();
ID3DBlob* pPSBuf = NULL;
V_FRETURN(D3DX11CompileFromFile(L"../../INPUT/DATA/Shader/sample/PS.hlsl", NULL, NULL, "PS", "ps_5_0", dwShaderFlags, NULL, NULL, &pPSBuf, NULL, NULL));
V_FRETURN(g_pD3dDevice->CreatePixelShader((DWORD*)pPSBuf->GetBufferPointer(), pPSBuf->GetBufferSize(), NULL, &m_pPS));
SIZE_T psSize = pPSBuf->GetBufferSize();
const D3D11_INPUT_ELEMENT_DESC layout[] =
{
//정점쉐이더안의 POSITION시멘틱의 의미를 지정.
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
V_FRETURN(g_pD3dDevice->CreateInputLayout(layout, 1, pVSBuf->GetBufferPointer(), vsSize, &m_pVertexLayout));
SAFE_RELEASE(pVSBuf);
SAFE_RELEASE(pPSBuf);
return hr;
}
bool Sample::Init()
{
if (FAILED(CreateVertexBuffer()))
{
MessageBox(0, _T("CreateVertexBuffer 실패"), _T("Fatal error"), MB_OK);
return false;
}
if (FAILED(CreateIndexBuffer()))
{
MessageBox(0, _T("CreateIndexBuffer 실패"), _T("Fatal error"), MB_OK);
return false;
}
if (FAILED(CreateConstantBuffer()))
{
MessageBox(0, _T("CreateConstantBuffer 실패"), _T("Fatal error"), MB_OK);
return false;
}
if (FAILED(LoadShaderAndInputLayout()))
{
MessageBox(0, _T("LoadShaderAndInputLayout 실패"), _T("Fatal error"), MB_OK);
return false;
}
return true;
}
bool Sample::Frame()
{
float fTime = m_GameTimer.getGameTime();
float fBoundedTime = cosf(fTime)*0.5f + 0.5f;
// 상수버퍼를 갱신한다.
D3D11_MAPPED_SUBRESOURCE MappedResource;
g_pD3dContext->Map(m_pConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
VSCB* pConstData = (VSCB*)MappedResource.pData;
pConstData->vColor = float4(cosf(fTime), sinf(fTime), 1.0f - cosf(fTime), 1.0f);
pConstData->fTime = fBoundedTime;
g_pD3dContext->Unmap(m_pConstantBuffer, 0);
if (I_Input.IsKeyDownOnce(DIK_T)) {
(m_PrimType+1 > 5) ? (m_PrimType = 1) : (m_PrimType += 1);
}
return true;
}
bool Sample::Render()
{
m_Font.SetAlignment(DWRITE_TEXT_ALIGNMENT_CENTER, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
m_Font.SetTextColor(ColorF(1.0f, 1.0f, 1.0f, 1.0f));
m_Font.SetlayoutRt(0, 0, (FLOAT)g_rtClient.right, (FLOAT)g_rtClient.bottom);
TCHAR TopologyBuffer[256];
ZeroMemory(TopologyBuffer, sizeof(TCHAR) * 256);
switch (m_PrimType) {
case 1: { _tcscpy_s(TopologyBuffer, L"POINTLIST"); } break;
case 2: { _tcscpy_s(TopologyBuffer, L"LINELIST"); } break;
case 3: { _tcscpy_s(TopologyBuffer, L"LINESTRIP"); } break;
case 4: { _tcscpy_s(TopologyBuffer, L"TRIANGLELIST"); } break;
case 5: { _tcscpy_s(TopologyBuffer, L"TRIANGLESTRIP"); } break;
}
TCHAR pBuffer[256];
ZeroMemory(pBuffer, sizeof(TCHAR) * 256);
_stprintf_s(pBuffer, L"%s", TopologyBuffer);
m_Font.DrawText(pBuffer);
// Set the input layout
g_pD3dContext->IASetInputLayout(m_pVertexLayout);
// Shaders
g_pD3dContext->VSSetShader(m_pVS, NULL, 0);
g_pD3dContext->PSSetShader(m_pPS, NULL, 0);
// // Set vertex buffer
UINT stride = sizeof(Point3);
UINT offset = 0;
//IASetVertexBuffers : 1개 정점의 메모리 크기
g_pD3dContext->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &stride, &offset);
g_pD3dContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0); //WORD는 R16, DWORD는 R32
g_pD3dContext->VSSetConstantBuffers(0, 1, &m_pConstantBuffer);
g_pD3dContext->IASetPrimitiveTopology((D3D_PRIMITIVE_TOPOLOGY)m_PrimType);
g_pD3dContext->DrawIndexed(6, 0, 0); //정점 버퍼와 인덱스 버퍼를 모두 사용해서 뿌리는 거
return true;
}
bool Sample::Release()
{
SAFE_RELEASE(m_pVertexBuffer); // 정점 버퍼 릴리즈
SAFE_RELEASE(m_pIndexBuffer); // 인덱스 버퍼 릴리즈
SAFE_RELEASE(m_pConstantBuffer); // 상수 버퍼 릴리즈
SAFE_RELEASE(m_pVertexLayout); // 정점 레이아웃 릴리즈
SAFE_RELEASE(m_pVS); // 정점 쉐이더 릴리즈
SAFE_RELEASE(m_pPS); // 픽쉘 쉐이더 릴리즈
return true;
}
Sample::~Sample() { }
}
반응형