반응형
# 스트림 아웃풋 스테이지를 사용하는 예제.
# 3일 걸렸다... 아직도 이론적으로 제대로 이해하고 있는지 모르겠지만 일단 원하는대로 실행은 된다.
VS.hlsl
struct VS_OUTPUT { float4 p : SV_POSITION; }; VS_OUTPUT VS(float4 p : POSITION) { VS_OUTPUT output = (VS_OUTPUT)0; output.p = p; return output; }
PS.hlsl
struct VS_OUTPUT { float4 p : SV_POSITION; }; float4 PS(VS_OUTPUT p : SV_POSITION) : SV_Target { return float4(1.0f, 1.0f, 1.0f, 1.0f); }
GS.hlsl
//주석처리된 코드는 삼각형을 4개로 분할하는 코드지만 여러번 분할하면 원하는대로 되지 않아서 주석처리.
struct VS_OUTPUT { float4 p : SV_POSITION; float4 c : COLOR; }; [maxvertexcount(9)] void GS(triangle VS_OUTPUT input[3], inout TriangleStream<VS_OUTPUT> TriStream) { VS_OUTPUT output; // 페이스의 중점을 구한다. float3 centerPos = (input[0].p.xyz + input[1].p.xyz + input[2].p.xyz) / 3.0; float4 centerColor = (input[0].c + input[1].c + input[2].c) / 4.0; // 정점 당 계산된 중점을 사용하여 페이스를 추가한다. for (int i = 0; i<3; i++) { output.p = input[i].p; output.c = input[i].c; TriStream.Append(output); int iNext = (i + 1) % 3; output.p = input[iNext].p; output.c = input[iNext].c; TriStream.Append(output); output.p = float4(centerPos, 1); output.c = centerColor; TriStream.Append(output); TriStream.RestartStrip(); } TriStream.RestartStrip(); } //[maxvertexcount(9)] //void GS(triangle VS_OUTPUT input[3], inout TriangleStream<VS_OUTPUT> TriStream) //{ // VS_OUTPUT output; // // float3 a = (input[0].p + input[1].p) / 2.0; // float3 b = (input[1].p + input[2].p) / 2.0; // float3 c = (input[2].p + input[0].p) / 2.0; // // //트라이앵글 리스트는 마지막 이전 삼각형의 마지막 정점을 다음 삼각형의 첫번째 정점으로 사용한다. // // output.p = float4(c, 1); // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // output.p = input[0].p; // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // output.p = float4(a, 1); // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // output.p = input[1].p; // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // output.p = float4(b, 1); // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // output.p = input[2].p; // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // output.p = float4(c, 1); // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // output.p = float4(a, 1); // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // output.p = float4(b, 1); // output.c = float4(1, 1, 1, 1); // TriStream.Append(output); // // TriStream.RestartStrip(); //}
sample.h
#pragma once #pragma comment(lib, "TLib.lib") #include "zCore.h" #include "mathHeader_L.h" namespace Lypi { struct PC_VERTEX { float3 position; float4 color; }; class Sample : public zCore { // 버텍스 버퍼 및 레이아웃 ID3D11InputLayout* m_pVertexLayout; //정점 레이아웃 인터페이스 ID3D11Buffer* m_pVertexBuffer; //정점 버퍼 인터페이스 ID3D11Buffer* m_pIndexBuffer; //인덱스 버퍼 인터페이스 ID3D11Buffer* m_pStreamTo; //SO에서 IA로 되돌릴 버퍼 ID3D11Buffer* m_pDrawFrom; //출력용 버퍼 // 버텍스 및 픽셀 쉐이더 ID3D11VertexShader* m_pVS; //정점 쉐이더 인터페이스 ID3D11PixelShader* m_pPS; //픽셀 쉐이더 인터페이스 ID3D11GeometryShader* m_pGS; //기하 쉐이더 인터페이스 ID3D11GeometryShader* m_pSO; //Stream Output Stage용 public: HRESULT CreateVertexBuffer(); // 정점 버퍼 생성 HRESULT CreateIndexBuffer(); // 인덱스 버퍼 생성 HRESULT LoadShaderAndInputLayout(); // 정점 및 픽쉘 쉐이더 로딩 및 생성 HRESULT HandleEffects(ID3D11Buffer* pBuffer); // 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 = nullptr; m_pIndexBuffer = nullptr; m_pVertexLayout = nullptr; m_pStreamTo = nullptr; m_pDrawFrom = nullptr; m_pVS = nullptr; m_pGS = nullptr; m_pSO = nullptr; m_pPS = nullptr; } HRESULT Sample::LoadShaderAndInputLayout() { HRESULT hr = S_OK; ID3DBlob* pErrors = nullptr; DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS; #if defined( _DEBUG ) || defined( _DEBUG ) dwShaderFlags |= D3DCOMPILE_DEBUG; #endif ID3DBlob* pVSBuf = nullptr; hr = D3DX11CompileFromFile(L"../../INPUT/DATA/Shader/sample/VS.hlsl", nullptr, nullptr, "VS", "vs_5_0", dwShaderFlags, NULL, nullptr, &pVSBuf, &pErrors, nullptr); V_FRETURN(hr); V_FRETURN(g_pD3dDevice->CreateVertexShader((DWORD*)pVSBuf->GetBufferPointer(), pVSBuf->GetBufferSize(), nullptr, &m_pVS)); ID3DBlob* pGSBuf = nullptr; V_FRETURN(D3DX11CompileFromFile(L"../../INPUT/DATA/Shader/sample/GS.hlsl", nullptr, nullptr, "GS", "gs_5_0", dwShaderFlags, NULL, nullptr, &pGSBuf, &pErrors, nullptr)); V_FRETURN(g_pD3dDevice->CreateGeometryShader((DWORD*)pGSBuf->GetBufferPointer(), pGSBuf->GetBufferSize(), nullptr, &m_pGS)); ID3DBlob* pPSBuf = nullptr; V_FRETURN(D3DX11CompileFromFile(L"../../INPUT/DATA/Shader/sample/PS.hlsl", nullptr, nullptr, "PS", "ps_5_0", dwShaderFlags, NULL, nullptr, &pPSBuf, &pErrors, nullptr)); V_FRETURN(g_pD3dDevice->CreatePixelShader((DWORD*)pPSBuf->GetBufferPointer(), pPSBuf->GetBufferSize(), nullptr, &m_pPS)); //중요! 출력 슬롯의 정점 버퍼에있는 정점 요소에 대한 설명 // ...예를 들어 위치의 y 및 z 구성 요소로만 출력하려면 StartComponent가 1이고 ComponentCount가 2여야합니다. D3D11_SO_DECLARATION_ENTRY pDecl[] = { { 0, "SV_POSITION", 0, 0, 3, 0 }, { 0, "COLOR", 0, 0, 4, 0 }, }; UINT elems = ARRAYSIZE(pDecl); // == UINT elems = sizeof(pDecl) / sizeof(pDecl[0]); // == UINT elems = sizeof(pDecl) / sizeof(D3D11_SO_DECLARATION_ENTRY); UINT stride[] = { sizeof(PC_VERTEX) }; // SO에서 반환되는 정점 한개의 크기. //UINT stride = 7 * sizeof(float); // *NOT* sizeof the above array! V_FRETURN(g_pD3dDevice->CreateGeometryShaderWithStreamOutput(pGSBuf->GetBufferPointer(), pGSBuf->GetBufferSize(), pDecl, elems, stride, 1, 0, NULL, &m_pSO)); UINT m_nBufferSize = 100000; // Streamoutput Stage를 돌리면 정점이 기하급수적으로 늘어남으로 최대치로 잡는 것이 좋다. //그렇다고 너무 크게 잡으면 디바이스가 멈춤... 어느정도가 최대치인지는 잘 모르겠다. CD3D11_BUFFER_DESC bufferDesc(m_nBufferSize, D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT); //동일한 기하 쉐이더 버퍼2개 생성 V_FRETURN(g_pD3dDevice->CreateBuffer(&bufferDesc, NULL, &m_pDrawFrom)); V_FRETURN(g_pD3dDevice->CreateBuffer(&bufferDesc, NULL, &m_pStreamTo)); const D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; V_FRETURN(g_pD3dDevice->CreateInputLayout(layout, 2, pVSBuf->GetBufferPointer(), pVSBuf->GetBufferSize(), &m_pVertexLayout)); SAFE_RELEASE(pVSBuf); SAFE_RELEASE(pGSBuf); SAFE_RELEASE(pPSBuf); SAFE_RELEASE(pErrors); RSChange(); //스트림 출력( 스트림 출력 스테이지 ) //처음에 VertexBuffer로 한번은 꼭 돌려야한다. HandleEffects(m_pVertexBuffer); //for (int iCnt = 0; iCnt < 1; iCnt++) //기하 쉐이더를 몇번 돌릴지 결정. //{ // HandleEffects(m_pDrawFrom); //} return hr; } HRESULT Sample::HandleEffects(ID3D11Buffer* pBuffer) { HRESULT hr = S_OK; g_pD3dContext->IASetInputLayout(m_pVertexLayout); g_pD3dContext->VSSetShader(m_pVS, NULL, 0); g_pD3dContext->GSSetShader(m_pSO, NULL, 0); //SO로 세팅되면 PS로 넘어가지 않음 UINT stride = sizeof(PC_VERTEX); UINT Offsets[] = { 0 }; ID3D11Buffer* pVB[] = { pBuffer }; g_pD3dContext->SOSetTargets(1, &m_pStreamTo, Offsets); //삼각형당 쪼개진 데이터가 저장되서 나옴. g_pD3dContext->IASetVertexBuffers(0, 1, pVB, &stride, Offsets); g_pD3dContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0); g_pD3dContext->RSSetState(m_pRS); g_pD3dContext->IASetPrimitiveTopology((D3D11_PRIMITIVE_TOPOLOGY)m_uPrimType); if (pBuffer == m_pVertexBuffer) { (g_pD3dContext->DrawIndexed(3, 0, 0)); } else { (g_pD3dContext->DrawAuto()); } //더블버퍼링과 같은 개념 ID3D11Buffer* pTemp = m_pStreamTo; m_pStreamTo = m_pDrawFrom; m_pDrawFrom = pTemp; //여기에 있어야 함. 중요함. pVB[0] = NULL; g_pD3dContext->SOSetTargets(0, pVB, Offsets); return hr; } HRESULT Sample::CreateVertexBuffer() { HRESULT hr = S_OK; //시계 방향으로 지정할 것. PC_VERTEX vertices[] = { { float3 (-0.0f, +0.7f, 0.5f), float4(1.f,1.f,1.f,1.f)}, { float3 (+0.5f, -0.2f, 0.5f), float4(1.f,1.f,1.f,1.f)}, { float3 (-0.5f, -0.2f, 0.5f), float4(1.f,1.f,1.f,1.f)}, }; UINT numVertices = sizeof(vertices) / sizeof(vertices[0]); //// CD3D11_BUFFER_DESC : 버퍼 크기와 버퍼 용도만 결정하면 나머지는 기본값으로 생성해주는 구조체. CD3D11_BUFFER_DESC cbc(sizeof(PC_VERTEX) * numVertices, D3D11_BIND_VERTEX_BUFFER); D3D11_SUBRESOURCE_DATA InitData; InitData.pSysMem = vertices; V_FRETURN(g_pD3dDevice->CreateBuffer(&cbc, &InitData, &m_pVertexBuffer)); return hr; } HRESULT Sample::CreateIndexBuffer() { HRESULT hr = S_OK; DWORD indices[] = { 0,1,2, //0,2,3, }; UINT iNumIndex = sizeof(indices) / sizeof(indices[0]); // Create an Index Buffer CD3D11_BUFFER_DESC cib(iNumIndex * sizeof(DWORD), 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; } bool Sample::Init() { if (FAILED(CreateVertexBuffer())) { MessageBox(0, _T("CreateTrangle 실패"), _T("Fatal error"), MB_OK); return false; } if (FAILED(CreateIndexBuffer())) { MessageBox(0, _T("CreateIndexBuffer 실패"), _T("Fatal error"), MB_OK); return false; } if (FAILED(LoadShaderAndInputLayout())) { MessageBox(0, _T("LoadShaderAndInputLayout 실패"), _T("Fatal error"), MB_OK); return false; } g_pD3dContext->IASetPrimitiveTopology((D3D11_PRIMITIVE_TOPOLOGY)m_uPrimType); return true; } bool Sample::Frame() { if (I_Input.IsKeyDownOnce(DIK_F1)) { (m_uPrimType + 1 > 5) ? (m_uPrimType = 1) : (m_uPrimType += 1); } if (I_Input.IsKeyDownOnce(DIK_F2)) { (m_uCullMode + 1 > 3) ? (m_uCullMode = 1) : (m_uCullMode += 1); RSChange(); } if (I_Input.IsKeyDownOnce(DIK_F3)) { (m_uFillMode + 1 > 3) ? (m_uFillMode = 2) : (m_uFillMode += 1); RSChange(); } //D키를 누르면 분할한다. if (I_Input.IsKeyDownOnce(DIK_D)) { HandleEffects(m_pDrawFrom); } return true; } bool Sample::Render() { // Shaders g_pD3dContext->VSSetShader(m_pVS, NULL, 0); g_pD3dContext->PSSetShader(m_pPS, NULL, 0); // Set the input layout g_pD3dContext->IASetInputLayout(m_pVertexLayout); UINT stride[] = { sizeof(PC_VERTEX) }; UINT offset[] = { 0 }; // Set vertex buffer g_pD3dContext->IASetVertexBuffers(0, 1, &m_pDrawFrom, stride, offset); g_pD3dContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0); g_pD3dContext->RSSetState(m_pRS); g_pD3dContext->IASetPrimitiveTopology((D3D_PRIMITIVE_TOPOLOGY)m_uPrimType); //쪼개진 이후이므로 DrawAuto로 출력해야 제대로 분할된게 출력된다. /*g_pD3dContext->DrawIndexed(3, 0, 0);*/ g_pD3dContext->DrawAuto(); return true; } bool Sample::Release() { SAFE_RELEASE(m_pVertexBuffer); // 정점 버퍼 릴리즈 SAFE_RELEASE(m_pVertexLayout); // 정점 레이아웃 릴리즈 SAFE_RELEASE(m_pVS); // 정점 쉐이더 릴리즈 SAFE_RELEASE(m_pGS); // 기하 쉐이더 릴리즈 SAFE_RELEASE(m_pSO); // SO 릴리즈 SAFE_RELEASE(m_pPS); // 픽쉘 쉐이더 릴리즈 SAFE_RELEASE(m_pStreamTo); SAFE_RELEASE(m_pDrawFrom); SAFE_RELEASE(m_pRS); return true; } Sample::~Sample(void) { } }
반응형