Purpose of the Sample:
This sample demonstrates how to use both a geometry shader and a structured buffer. In this example, a single point will be uploaded from the CPU to the GPU. The GPU will expand that single point into a quad composed of two triangles and procedurally assign colors to each new vertex.
CGame.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#ifndef __CGAME__ #define __CGAME__ #include "d3d11.h" #include "Mesh.h" class CGame { ID3D11Device* dev; ID3D11DeviceContext* devcon; IDXGISwapChain* swapchain; ID3D11RenderTargetView* renderTargetView; ID3D11Buffer* vertexBuffer; ID3D11Buffer* indexBuffer; ID3D11ShaderResourceView* particleResourceView; ID3D11VertexShader *vertexShader; ID3D11GeometryShader *geometryShader; ID3D11PixelShader* pixelShader; ID3D11InputLayout* inputLayout; ID3D11Buffer* constantBuffer; Mesh m; public: void Initialize(void * windowHandle, int width, int height); void Update(); void Render(); private: void InitializeGraphics(); void InitializePipeline(); int m_Width; int m_Height; float m_AspectRatio; }; #endif |
CGame.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
#include "CGame.h" #include <fstream> #include "DirectXMath.h" #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include "glm/glm.hpp" #include "glm/vec3.hpp" #include "glm/mat4x4.hpp" #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <minwinbase.h> using namespace std; using namespace DirectX; struct ConstantBufferData { float matrixWorld[16]; float matrixView[16]; float matrixProjection[16]; }; void LoadShader(std::string filename, unsigned char*& outShaderSrc, unsigned int& outFileLength) { outShaderSrc = 0; outFileLength = 0; std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); if (file.is_open()) { outFileLength = (int)file.tellg(); outShaderSrc = new unsigned char[outFileLength]; file.seekg(0, std::ios::beg); file.read(reinterpret_cast<char*>(outShaderSrc), outFileLength); file.close(); } } void CGame::Initialize(void * windowHandle, int width, int height) { m_Width = width; m_Height = height; m_AspectRatio = (float)width / (float)height; HRESULT hr = S_OK; hr = D3D11CreateDevice(0, D3D_DRIVER_TYPE_HARDWARE, 0, D3D11_CREATE_DEVICE_DEBUG, 0, 0, D3D11_SDK_VERSION, &dev, 0, &devcon); IDXGIDevice1* dxgiDev; hr = dev->QueryInterface(__uuidof(IDXGIDevice1), reinterpret_cast<void**>(&dxgiDev)); IDXGIAdapter* dxgiAdapter; hr = dxgiDev->GetAdapter(&dxgiAdapter); IDXGIFactory* dxgiFactory; hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory)); DXGI_SWAP_CHAIN_DESC des = { 0 }; des.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; des.BufferDesc.Width = m_Width; des.BufferDesc.Height = m_Height; des.BufferCount = 2; des.SampleDesc.Count = 1; des.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; des.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; des.Windowed = true; des.OutputWindow = reinterpret_cast<HWND>(windowHandle); hr = dxgiFactory->CreateSwapChain(dev, &des, &swapchain); ID3D11Texture2D* backBuffer; hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)); hr = dev->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView); D3D11_VIEWPORT vp = { 0 }; vp.TopLeftX = 0; vp.TopLeftY = 0; vp.Width = m_Width; vp.Height = m_Height; vp.MinDepth = 0; vp.MaxDepth = 1; devcon->RSSetViewports(1, &vp); InitializeGraphics(); InitializePipeline(); } void CGame::InitializeGraphics() { m.vertexCount = 1; m.vertices = new Vertex[m.vertexCount]; m.vertices[0].position[0] = 0; m.vertices[0].position[1] = 0; m.vertices[0].position[2] = 0; D3D11_BUFFER_DESC vertexBufferDesc = { 0 }; vertexBufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; vertexBufferDesc.ByteWidth = (unsigned int)(sizeof(m.vertices[0]) * m.vertexCount); vertexBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; vertexBufferDesc.StructureByteStride = sizeof(m.vertices[0]); vertexBufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT; vertexBufferDesc.CPUAccessFlags = 0; D3D11_SUBRESOURCE_DATA vertexBufferData = { m.vertices, 0, 0 }; HRESULT hr = dev->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &vertexBuffer); D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc; //ZeroMemory(&shaderResourceViewDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC)); shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; shaderResourceViewDesc.Format = DXGI_FORMAT_UNKNOWN; shaderResourceViewDesc.Buffer.FirstElement = 0; shaderResourceViewDesc.Buffer.NumElements = 1; hr = dev->CreateShaderResourceView(vertexBuffer, &shaderResourceViewDesc, &particleResourceView); } void CGame::InitializePipeline() { unsigned char* vsFileData = 0; unsigned char* gsFileData = 0; unsigned char* psFileData = 0; unsigned int vsFileLength = 0; unsigned int gsFileLength = 0; unsigned int psFileLength = 0; LoadShader("Assets/VertexShader.fxc", vsFileData, vsFileLength); LoadShader("Assets/GeometryShader.fxc", gsFileData, gsFileLength); LoadShader("Assets/PixelShader.fxc", psFileData, psFileLength); HRESULT hr = S_OK; hr = dev->CreateVertexShader(vsFileData, vsFileLength, nullptr, &vertexShader); hr = dev->CreateGeometryShader(gsFileData, gsFileLength, nullptr, &geometryShader); hr = dev->CreatePixelShader(psFileData, psFileLength, nullptr, &pixelShader); devcon->VSSetShader(vertexShader, 0, 0); devcon->GSSetShader(geometryShader, 0, 0); devcon->PSSetShader(pixelShader, 0, 0); D3D11_BUFFER_DESC cdes = { 0 }; cdes.Usage = D3D11_USAGE_DEFAULT; cdes.ByteWidth = 192; // 64 bytes per matrix because 4 bytes per float and there are 16 floats in a 4x4 matrix. cdes.BindFlags = D3D11_BIND_CONSTANT_BUFFER; hr = dev->CreateBuffer(&cdes, nullptr, &constantBuffer); devcon->VSSetConstantBuffers(0, 1, &constantBuffer); } void CGame::Update() { } void CGame::Render() { HRESULT hr = S_OK; devcon->OMSetRenderTargets(1, &renderTargetView, 0); const float color[4] = {0.1f, 0.1f, 0.1f, 1.0f}; devcon->ClearRenderTargetView(renderTargetView, color); devcon->IASetInputLayout(NULL); devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); devcon->VSSetShaderResources(0, 1, &particleResourceView); glm::mat4x4 matWorld = glm::mat4x4(1.0f); glm::vec3 vecCamPos(0, 0, -1.5f); glm::vec3 vecCamLookAt(0, 0, 0); glm::vec3 vecCamUp(0, 1, 0); glm::mat4x4 matView = glm::lookAtLH(vecCamPos, vecCamLookAt, vecCamUp); glm::mat4x4 matProjection = glm::perspectiveFovLH<float>(glm::radians(45.0f), m_Width, m_Height, 1, 100); ConstantBufferData constantBufferData; memcpy(&constantBufferData.matrixWorld, glm::value_ptr(matWorld), sizeof(float) * 16); memcpy(&constantBufferData.matrixView, glm::value_ptr(matView), sizeof(float) * 16); memcpy(&constantBufferData.matrixProjection, glm::value_ptr(matProjection), sizeof(float) * 16); devcon->VSSetConstantBuffers(0, 1, &constantBuffer); devcon->UpdateSubresource(constantBuffer, 0, 0, &constantBufferData, 0, 0); devcon->Draw(1, 0); hr = swapchain->Present(1, 0); } |
VertexShader.hlsl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
cbuffer ConstantBufferData { float4x4 matrixWorld; float4x4 matrixView; float4x4 matrixProjection; } StructuredBuffer<float3> particles; struct v2g { float4 position : SV_POSITION; float4 particleId : TEXCOORD0; }; v2g main( uint vertexId : SV_VertexID ) { v2g o; float4 objPos = float4(particles[vertexId].xyz, 1.0); float4 worldPos = mul(matrixWorld, objPos); float4x4 matVP = mul(matrixProjection, matrixView); o.position = mul(matVP, worldPos); o.particleId = float4(vertexId, vertexId, vertexId, vertexId); return o; } |
GeometryShader.hlsl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
struct v2g { float4 position : SV_POSITION; float4 particleId : TEXCOORD0; }; struct g2f { float4 position : SV_POSITION; float4 color : TEXCOORD0; float2 uv : TEXCOORD1; }; float2 FromClipSpace(float4 clipPos) { return clipPos.xy / clipPos.w; } float4 ToClipSpace(float2 screenPos, float originalClipPosW) { return float4( screenPos.xy * originalClipPosW, 0, originalClipPosW); } [maxvertexcount(6)] void main( point v2g input[1], inout TriangleStream<g2f> triStream ) { g2f v; float2 screenPos = FromClipSpace(input[0].position); float clipPosW = input[0].position.w; float s = 0.5; v.position = ToClipSpace(screenPos + float2(-s, -s), clipPosW); v.color = float4(1,0,0,1); v.uv = float2(0,0); triStream.Append(v); v.position = ToClipSpace(screenPos + float2(-s, s), clipPosW); v.color = float4(0,1,0,1); v.uv = float2(0,1); triStream.Append(v); v.position = ToClipSpace(screenPos + float2(s, s), clipPosW); v.color = float4(0,0,1,1); v.uv = float2(1,1); triStream.Append(v); triStream.RestartStrip(); v.position = ToClipSpace(screenPos + float2(s, -s), clipPosW); v.color = float4(0,1,0,1); v.uv = float2(1,0); triStream.Append(v); v.position = ToClipSpace(screenPos + float2(-s, -s), clipPosW); v.color = float4(1,0,0,1); v.uv = float2(0,0); triStream.Append(v); v.position = ToClipSpace(screenPos + float2(s, s), clipPosW); v.color = float4(0,0,1,1); v.uv = float2(1,1); triStream.Append(v); triStream.RestartStrip(); } |
PixelShader.hlsl
1 2 3 4 5 6 7 8 9 10 11 |
struct g2f { float4 position : SV_POSITION; float4 color : TEXCOORD0; float2 uv : TEXCOORD1; }; float4 main(g2f i) : SV_TARGET { return i.color; } |