/*!**************************************************************************** @Function Init @Input ErrorStr In case of error, any error messages will be stored in this string @Return true if successfully completed, false otherwise. @Description Initializes any state that needs to be created by the class itself. Init WILL NOT initialize objects that need to be set by a caller, most importantly: * The vertex buffer that will contain the actual particles * The actual Spheres * The actual number of particles (SetNumberOfParticles actually allocates memory for the particles) ******************************************************************************/ bool ParticleSystemGPU::Init(CPVRTString& errorStr) { if (!CompileComputeShader(errorStr)) { return false; } if (m_ParticleConfigUbo == 0) { glGenBuffers(1, &m_ParticleConfigUbo); } if (m_SpheresUbo == 0) { glGenBuffers(1, &m_SpheresUbo); } glBindBuffer(GL_UNIFORM_BUFFER, m_SpheresUbo); glBindBuffer(GL_UNIFORM_BUFFER, m_ParticleConfigUbo); glBufferData(GL_UNIFORM_BUFFER, sizeof(ParticleConfig), &m_ParticleConfigData, GL_STREAM_DRAW); glBindBufferBase(GL_UNIFORM_BUFFER, SPHERES_UBO_BINDING_INDEX, m_SpheresUbo); glBindBufferBase(GL_UNIFORM_BUFFER, PARTICLE_CONFIG_UBO_BINDING_INDEX, m_ParticleConfigUbo); glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); return true; }
void GPUParticleSystem::InitialiseSystem(ID3D11Device* device, ID3D11DeviceContext* deviceContext) { HRESULT hr; //Compile the shaders ID3DBlob* pVertexShaderBuffer = NULL; hr = CompileShaderFromFile(L"VertexShader.hlsl", "VS", "vs_4_0", &pVertexShaderBuffer); ID3DBlob* pGeometryShaderBuffer = NULL; hr = CompileShaderFromFile(L"VertexShader.hlsl", "GS", "gs_4_0", &pGeometryShaderBuffer); ID3DBlob* pPixelShaderBuffer = NULL; hr = CompileShaderFromFile(L"VertexShader.hlsl", "PS", "ps_4_0", &pPixelShaderBuffer); // Create the shaders device->CreateVertexShader(pVertexShaderBuffer->GetBufferPointer(), pVertexShaderBuffer->GetBufferSize(), NULL, &vertexShader); device->CreateGeometryShader(pGeometryShaderBuffer->GetBufferPointer(), pGeometryShaderBuffer->GetBufferSize(), NULL, &geometryShader); device->CreatePixelShader(pPixelShaderBuffer->GetBufferPointer(), pPixelShaderBuffer->GetBufferSize(), NULL, &pixelShader); pVertexShaderBuffer->Release(); pPixelShaderBuffer->Release(); //Create buffer constant buffer for draw calls D3D11_BUFFER_DESC bd; ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof(MatricesConstantBuffer); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = 0; device->CreateBuffer(&bd, NULL, &mConstBuffer); //Create constant buffer for per frame variables ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof(PerFrameVariables); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = 0; device->CreateBuffer(&bd, NULL, &perFrameVariablesBuffer); //Create constant buffer for emitter variables ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_DYNAMIC; bd.ByteWidth = sizeof(EmitterParameters); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; device->CreateBuffer(&bd, NULL, &emitterVariablesBuffer); //Create constant buffer for variances ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_DYNAMIC; bd.ByteWidth = sizeof(EmitterParameters); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; device->CreateBuffer(&bd, NULL, &variancesCB); //Compile and create compute shaders ID3DBlob *csInitBlob = nullptr; ID3DBlob *csEmitBlob = nullptr; ID3DBlob *csUpdateBlob = nullptr; ID3DBlob *errorBlob; hr = CompileComputeShader(L"InitialiseDeadList.hlsl", "main", device, &csInitBlob); hr = CompileComputeShader(L"EmitParticles.hlsl", "main", device, &csEmitBlob); //hr = CompileComputeShader(L"UpdateParticles.hlsl", "main", device, &csUpdateBlob); //Assembles shader code for UpdateParticles shaderFactory->ShaderAssembly(); //Compiles the code that has been put together in the shader factory hr = D3DCompile(shaderFactory->updateShaderCode.c_str(), shaderFactory->updateShaderCode.length(), NULL, NULL, NULL, "main", "cs_5_0", D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG, NULL, &csUpdateBlob, &errorBlob); if (FAILED(hr)) { std::string error = std::string((char*)errorBlob->GetBufferPointer()); errorBlob->Release(); return; } //Creates the compute shaders hr = device->CreateComputeShader(csInitBlob->GetBufferPointer(), csInitBlob->GetBufferSize(), nullptr, &initialiseDeadListCS); hr = device->CreateComputeShader(csEmitBlob->GetBufferPointer(), csEmitBlob->GetBufferSize(), nullptr, &emitParticlesCS); hr = device->CreateComputeShader(csUpdateBlob->GetBufferPointer(), csUpdateBlob->GetBufferSize(), nullptr, &updateParticlesCS); // The dead particle index list. Created as an append buffer D3D11_BUFFER_DESC desc; desc.ByteWidth = sizeof(UINT) * g_maxParticles; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; desc.CPUAccessFlags = 0; desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; desc.StructureByteStride = sizeof(UINT); device->CreateBuffer(&desc, nullptr, &particleDeadListBuffer); // Create constant buffers to copy the dead and alive list counters into ZeroMemory(&desc, sizeof(desc)); desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; desc.CPUAccessFlags = 0; desc.ByteWidth = 4 * sizeof(UINT); device->CreateBuffer(&desc, nullptr, &particleDeadListConstantBuffer); D3D11_UNORDERED_ACCESS_VIEW_DESC uav; ZeroMemory(&uav, sizeof(uav)); uav.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; uav.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_APPEND; uav.Buffer.FirstElement = 0; uav.Format = DXGI_FORMAT_UNKNOWN; uav.Buffer.NumElements = g_maxParticles; device->CreateUnorderedAccessView(particleDeadListBuffer, &uav, &particleDeadListUAV); //Initialise list of particles that are able to be emitted InitialiseDeadList(deviceContext); //Create the particle buffer/UAV/SRV D3D11_BUFFER_DESC buffDesc; ZeroMemory(&buffDesc, sizeof(buffDesc)); buffDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE; buffDesc.ByteWidth = sizeof(Particle)* g_maxParticles; buffDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; buffDesc.StructureByteStride = sizeof(Particle); buffDesc.Usage = D3D11_USAGE_DEFAULT; Particle* particleList = new Particle[g_maxParticles]; //Initial particle values that are never used and are just for initialisation for (int i = 0; i < g_maxParticles; ++i) { particleList[i].position = DirectX::XMFLOAT3(9999.0f, 0.0f, 9999.0f); particleList[i].velocity = DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f); particleList[i].life = 0.0f; particleList[i].age = 0.0f; particleList[i].alive = false; particleList[i].startSize = 0.0f; particleList[i].endSize = 0.0f; particleList[i].startColour = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); particleList[i].endColour = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); particleList[i].currentColour = DirectX::XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f); particleList[i].currentSize = 0.0f; } D3D11_SUBRESOURCE_DATA data; ZeroMemory(&data, sizeof(data)); data.pSysMem = particleList; device->CreateBuffer(&buffDesc, &data, &particles); delete[] particleList; D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; ZeroMemory(&srvDesc, sizeof(srvDesc)); srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; srvDesc.Buffer.FirstElement = 0; srvDesc.Format = DXGI_FORMAT_UNKNOWN; srvDesc.Buffer.NumElements = g_maxParticles; device->CreateShaderResourceView(particles, &srvDesc, &particlesSRV); D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; ZeroMemory(&uavDesc, sizeof(uavDesc)); uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; uavDesc.Buffer.Flags = 0; uavDesc.Buffer.FirstElement = 0; uavDesc.Format = DXGI_FORMAT_UNKNOWN; uavDesc.Buffer.NumElements = g_maxParticles; device->CreateUnorderedAccessView(particles, &uavDesc, &particlesUAV); //Buffer for the particle count ZeroMemory(&desc, sizeof(desc)); desc.Usage = D3D11_USAGE_STAGING; desc.BindFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.ByteWidth = sizeof(UINT); device->CreateBuffer(&desc, nullptr, &debugCounterBuffer); //Loads in smoke particle texture to use with the particles using DirectXTK texture loader hr = DirectX::CreateWICTextureFromFile(device, deviceContext, L"smoke.jpg", nullptr, &texture); }
int main() { // Create Device const D3D_FEATURE_LEVEL lvl[] = { D3D_FEATURE_LEVEL_11_1 }; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif /* ================================== */ printf("Creating device..."); ID3D11Device* device = nullptr; HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, lvl, _countof(lvl), D3D11_SDK_VERSION, &device, nullptr, nullptr); if (FAILED(hr)) { printf("Failed creating Direct3D 11 device %08X\n", hr); return returnDBG(-1); } /* ================================== */ printf("Compile Compute Shader..."); ID3DBlob *csBlob = nullptr; hr = CompileComputeShader(L"ComputeShader.hlsl", "main", device, &csBlob); if (FAILED(hr)) { device->Release(); printf("Failed compiling shader %08X\n", hr); return returnDBG(-1); } /* ================================== */ printf("Create Compute Shader..."); ID3D11ComputeShader* computeShader = nullptr; hr = device->CreateComputeShader(csBlob->GetBufferPointer(), csBlob->GetBufferSize(), nullptr, &computeShader); /* ================================== */ printf("Creating buffers and filling them with initial data..."); for (int i = 0; i < NUM_ELEMENTS; ++i) { g_vBuf0[i].i = i; g_vBuf0[i].f = (float)i; g_vBuf1[i].i = i; g_vBuf1[i].f = (float)i; } CreateRawBuffer(g_pDevice, NUM_ELEMENTS * sizeof(BufType), &g_vBuf0[0], &g_pBuf0); CreateRawBuffer(g_pDevice, NUM_ELEMENTS * sizeof(BufType), &g_vBuf1[0], &g_pBuf1); CreateRawBuffer(g_pDevice, NUM_ELEMENTS * sizeof(BufType), nullptr, &g_pBufResult); /* ================================== */ printf("Running Compute Shader..."); ID3D11ShaderResourceView* aRViews[2] = { g_pBuf0SRV, g_pBuf1SRV }; RunComputeShader(g_pContext, g_pCS, 2, aRViews, nullptr, nullptr, 0, g_pBufResultUAV, NUM_ELEMENTS, 1, 1); printf("done\n"); csBlob->Release(); if (FAILED(hr)) { device->Release(); } printf("Success\n"); // Clean up computeShader->Release(); device->Release(); return returnDBG(0); }