Skip to content

Commit bb8777a

Browse files
committed
Created initial implementation.
1 parent d4fae94 commit bb8777a

File tree

6 files changed

+356
-104
lines changed

6 files changed

+356
-104
lines changed

src/main.cpp

Lines changed: 209 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
#include <random>
1313

1414
#undef min
15+
#undef max
1516
#define CAMERA_FAR_PLANE 1000.0f
16-
#define MAX_PARTICLES 1000000
17+
#define MAX_PARTICLES 100
1718
#define GRADIENT_SAMPLES 32
19+
#define LOCAL_SIZE 32
1820

1921
struct GlobalUniforms
2022
{
@@ -50,6 +52,7 @@ class GPUParticleSystem : public dw::Application
5052

5153
// Create camera.
5254
create_camera();
55+
particle_initialize();
5356

5457
glEnable(GL_MULTISAMPLE);
5558

@@ -71,12 +74,13 @@ class GPUParticleSystem : public dw::Application
7174
// Update camera.
7275
update_camera();
7376

74-
update_uniforms();
75-
7677
glBindFramebuffer(GL_FRAMEBUFFER, 0);
7778
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
7879
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
7980

81+
particle_kickoff();
82+
particle_emission();
83+
particle_simulation();
8084
render_particle();
8185

8286
m_debug_draw.grid(m_main_camera->m_view_projection, 1.0f, 10.0f);
@@ -185,14 +189,101 @@ class GPUParticleSystem : public dw::Application
185189

186190
void render_particle()
187191
{
192+
glEnable(GL_DEPTH_TEST);
193+
188194
m_particle_program->use();
189195

190196
m_particle_program->set_uniform("u_Rotation", glm::radians(m_rotation));
191-
m_particle_program->set_uniform("u_Position", m_position);
192197
m_particle_program->set_uniform("u_View", m_main_camera->m_view);
193198
m_particle_program->set_uniform("u_Proj", m_main_camera->m_projection);
194199

195-
glDrawArrays(GL_TRIANGLES, 0, 6);
200+
m_particle_data_ssbo->bind_base(0);
201+
m_alive_indices_post_sim_ssbo->bind_base(1);
202+
203+
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_indirect_args_ssbo->handle());
204+
205+
glDrawArraysIndirect(GL_TRIANGLES, 0);
206+
}
207+
208+
// -----------------------------------------------------------------------------------------------------------------------------------
209+
210+
void particle_initialize()
211+
{
212+
m_particle_initialize_program->use();
213+
214+
m_dead_indices_ssbo->bind_base(0);
215+
m_alive_indices_pre_sim_ssbo->bind_base(1);
216+
m_counters_ssbo->bind_base(2);
217+
218+
m_particle_initialize_program->set_uniform("u_MaxParticles", MAX_PARTICLES);
219+
220+
glDispatchCompute(MAX_PARTICLES / LOCAL_SIZE, 1, 1);
221+
222+
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
223+
}
224+
225+
// -----------------------------------------------------------------------------------------------------------------------------------
226+
227+
void particle_kickoff()
228+
{
229+
m_particle_update_kickoff_program->use();
230+
231+
int32_t rate = glm::max(1, int32_t(float(m_emission_rate) * float(m_delta_seconds)));
232+
m_particle_update_kickoff_program->set_uniform("u_ParticlesPerFrame", rate);
233+
234+
m_particle_data_ssbo->bind_base(0);
235+
m_dispatch_emission_indirect_args_ssbo->bind_base(1);
236+
m_dispatch_simulation_indirect_args_ssbo->bind_base(2);
237+
m_draw_indirect_args_ssbo->bind_base(3);
238+
m_counters_ssbo->bind_base(4);
239+
240+
glDispatchCompute(1, 1, 1);
241+
242+
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
243+
}
244+
245+
// -----------------------------------------------------------------------------------------------------------------------------------
246+
247+
void particle_emission()
248+
{
249+
m_particle_emission_program->use();
250+
251+
m_particle_emission_program->set_uniform("u_EmitterPosition", m_position);
252+
m_particle_emission_program->set_uniform("u_EmitterVelocity", m_max_velocity);
253+
m_particle_emission_program->set_uniform("u_EmitterLifetime", m_max_lifetime);
254+
255+
m_particle_data_ssbo->bind_base(0);
256+
m_dead_indices_ssbo->bind_base(1);
257+
m_alive_indices_pre_sim_ssbo->bind_base(2);
258+
m_counters_ssbo->bind_base(3);
259+
260+
glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_emission_indirect_args_ssbo->handle());
261+
262+
glDispatchComputeIndirect(0);
263+
264+
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
265+
}
266+
267+
// -----------------------------------------------------------------------------------------------------------------------------------
268+
269+
void particle_simulation()
270+
{
271+
m_particle_simulation_program->use();
272+
273+
m_particle_simulation_program->set_uniform("u_DeltaTime", float(m_delta_seconds));
274+
275+
m_particle_data_ssbo->bind_base(0);
276+
m_dead_indices_ssbo->bind_base(1);
277+
m_alive_indices_pre_sim_ssbo->bind_base(2);
278+
m_alive_indices_post_sim_ssbo->bind_base(3);
279+
m_draw_indirect_args_ssbo->bind_base(4);
280+
m_counters_ssbo->bind_base(5);
281+
282+
glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_simulation_indirect_args_ssbo->handle());
283+
284+
glDispatchComputeIndirect(0);
285+
286+
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
196287
}
197288

198289
// -----------------------------------------------------------------------------------------------------------------------------------
@@ -201,8 +292,12 @@ class GPUParticleSystem : public dw::Application
201292
{
202293
{
203294
// Create general shaders
204-
m_particle_vs = std::unique_ptr<dw::gl::Shader>(dw::gl::Shader::create_from_file(GL_VERTEX_SHADER, "shader/particle_vs.glsl"));
205-
m_particle_fs = std::unique_ptr<dw::gl::Shader>(dw::gl::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/particle_fs.glsl"));
295+
m_particle_vs = std::unique_ptr<dw::gl::Shader>(dw::gl::Shader::create_from_file(GL_VERTEX_SHADER, "shader/particle_vs.glsl"));
296+
m_particle_fs = std::unique_ptr<dw::gl::Shader>(dw::gl::Shader::create_from_file(GL_FRAGMENT_SHADER, "shader/particle_fs.glsl"));
297+
m_particle_initialize_cs = std::unique_ptr<dw::gl::Shader>(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/particle_initialize_cs.glsl"));
298+
m_particle_update_kickoff_cs = std::unique_ptr<dw::gl::Shader>(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/particle_update_kickoff_cs.glsl"));
299+
m_particle_emission_cs = std::unique_ptr<dw::gl::Shader>(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/particle_emission_cs.glsl"));
300+
m_particle_simulation_cs = std::unique_ptr<dw::gl::Shader>(dw::gl::Shader::create_from_file(GL_COMPUTE_SHADER, "shader/particle_simulation_cs.glsl"));
206301

207302
{
208303
if (!m_particle_vs || !m_particle_fs)
@@ -221,6 +316,78 @@ class GPUParticleSystem : public dw::Application
221316
return false;
222317
}
223318
}
319+
320+
{
321+
if (!m_particle_initialize_cs)
322+
{
323+
DW_LOG_FATAL("Failed to create Shaders");
324+
return false;
325+
}
326+
327+
// Create general shader program
328+
dw::gl::Shader* shaders[] = { m_particle_initialize_cs.get() };
329+
m_particle_initialize_program = std::make_unique<dw::gl::Program>(1, shaders);
330+
331+
if (!m_particle_initialize_program)
332+
{
333+
DW_LOG_FATAL("Failed to create Shader Program");
334+
return false;
335+
}
336+
}
337+
338+
{
339+
if (!m_particle_update_kickoff_cs)
340+
{
341+
DW_LOG_FATAL("Failed to create Shaders");
342+
return false;
343+
}
344+
345+
// Create general shader program
346+
dw::gl::Shader* shaders[] = { m_particle_update_kickoff_cs.get() };
347+
m_particle_update_kickoff_program = std::make_unique<dw::gl::Program>(1, shaders);
348+
349+
if (!m_particle_update_kickoff_program)
350+
{
351+
DW_LOG_FATAL("Failed to create Shader Program");
352+
return false;
353+
}
354+
}
355+
356+
{
357+
if (!m_particle_emission_cs)
358+
{
359+
DW_LOG_FATAL("Failed to create Shaders");
360+
return false;
361+
}
362+
363+
// Create general shader program
364+
dw::gl::Shader* shaders[] = { m_particle_emission_cs.get() };
365+
m_particle_emission_program = std::make_unique<dw::gl::Program>(1, shaders);
366+
367+
if (!m_particle_emission_program)
368+
{
369+
DW_LOG_FATAL("Failed to create Shader Program");
370+
return false;
371+
}
372+
}
373+
374+
{
375+
if (!m_particle_simulation_cs)
376+
{
377+
DW_LOG_FATAL("Failed to create Shaders");
378+
return false;
379+
}
380+
381+
// Create general shader program
382+
dw::gl::Shader* shaders[] = { m_particle_simulation_cs.get() };
383+
m_particle_simulation_program = std::make_unique<dw::gl::Program>(1, shaders);
384+
385+
if (!m_particle_simulation_program)
386+
{
387+
DW_LOG_FATAL("Failed to create Shader Program");
388+
return false;
389+
}
390+
}
224391
}
225392

226393
return true;
@@ -230,8 +397,22 @@ class GPUParticleSystem : public dw::Application
230397

231398
bool create_buffers()
232399
{
233-
// Create uniform buffer for global data
234-
m_global_ubo = std::make_unique<dw::gl::UniformBuffer>(GL_DYNAMIC_DRAW, sizeof(GlobalUniforms));
400+
struct Particle
401+
{
402+
glm::vec4 lifetime;
403+
glm::vec4 velocity;
404+
glm::vec4 position;
405+
glm::vec4 color;
406+
};
407+
408+
m_draw_indirect_args_ssbo = std::make_unique<dw::gl::ShaderStorageBuffer>(GL_STATIC_DRAW, sizeof(int32_t) * 4, nullptr);
409+
m_dispatch_emission_indirect_args_ssbo = std::make_unique<dw::gl::ShaderStorageBuffer>(GL_STATIC_DRAW, sizeof(int32_t) * 3, nullptr);
410+
m_dispatch_simulation_indirect_args_ssbo = std::make_unique<dw::gl::ShaderStorageBuffer>(GL_STATIC_DRAW, sizeof(int32_t) * 3, nullptr);
411+
m_particle_data_ssbo = std::make_unique<dw::gl::ShaderStorageBuffer>(GL_STATIC_DRAW, sizeof(Particle) * MAX_PARTICLES, nullptr);
412+
m_alive_indices_pre_sim_ssbo = std::make_unique<dw::gl::ShaderStorageBuffer>(GL_STATIC_DRAW, sizeof(int32_t) * MAX_PARTICLES, nullptr);
413+
m_alive_indices_post_sim_ssbo = std::make_unique<dw::gl::ShaderStorageBuffer>(GL_STATIC_DRAW, sizeof(int32_t) * MAX_PARTICLES, nullptr);
414+
m_dead_indices_ssbo = std::make_unique<dw::gl::ShaderStorageBuffer>(GL_STATIC_DRAW, sizeof(int32_t) * MAX_PARTICLES, nullptr);
415+
m_counters_ssbo = std::make_unique<dw::gl::ShaderStorageBuffer>(GL_STATIC_DRAW, sizeof(int32_t) * 5, nullptr);
235416

236417
return true;
237418
}
@@ -247,15 +428,6 @@ class GPUParticleSystem : public dw::Application
247428

248429
// -----------------------------------------------------------------------------------------------------------------------------------
249430

250-
void update_uniforms()
251-
{
252-
void* ptr = m_global_ubo->map(GL_WRITE_ONLY);
253-
memcpy(ptr, &m_global_uniforms, sizeof(GlobalUniforms));
254-
m_global_ubo->unmap();
255-
}
256-
257-
// -----------------------------------------------------------------------------------------------------------------------------------
258-
259431
void update_transforms(dw::Camera* camera)
260432
{
261433
// Update camera matrices.
@@ -298,22 +470,32 @@ class GPUParticleSystem : public dw::Application
298470
// -----------------------------------------------------------------------------------------------------------------------------------
299471

300472
private:
301-
std::unique_ptr<dw::gl::Shader> m_particle_vs;
302-
std::unique_ptr<dw::gl::Shader> m_particle_fs;
473+
std::unique_ptr<dw::gl::Shader> m_particle_vs;
474+
std::unique_ptr<dw::gl::Shader> m_particle_fs;
475+
std::unique_ptr<dw::gl::Shader> m_particle_initialize_cs;
476+
std::unique_ptr<dw::gl::Shader> m_particle_update_kickoff_cs;
477+
std::unique_ptr<dw::gl::Shader> m_particle_emission_cs;
478+
std::unique_ptr<dw::gl::Shader> m_particle_simulation_cs;
479+
303480
std::unique_ptr<dw::gl::Program> m_particle_program;
481+
std::unique_ptr<dw::gl::Program> m_particle_initialize_program;
482+
std::unique_ptr<dw::gl::Program> m_particle_update_kickoff_program;
483+
std::unique_ptr<dw::gl::Program> m_particle_emission_program;
484+
std::unique_ptr<dw::gl::Program> m_particle_simulation_program;
304485

305486
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_draw_indirect_args_ssbo;
306-
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_dispatch_indirect_args_ssbo;
487+
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_dispatch_emission_indirect_args_ssbo;
488+
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_dispatch_simulation_indirect_args_ssbo;
307489
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_particle_data_ssbo;
308490
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_alive_indices_pre_sim_ssbo;
309491
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_alive_indices_post_sim_ssbo;
310492
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_dead_indices_ssbo;
493+
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_counters_ssbo;
311494

312495
std::unique_ptr<dw::gl::Texture1D> m_scale_over_time;
313496
std::unique_ptr<dw::gl::Texture1D> m_color_over_time;
314497

315-
std::unique_ptr<dw::gl::UniformBuffer> m_global_ubo;
316-
std::unique_ptr<dw::Camera> m_main_camera;
498+
std::unique_ptr<dw::Camera> m_main_camera;
317499

318500
GlobalUniforms m_global_uniforms;
319501

@@ -332,11 +514,11 @@ class GPUParticleSystem : public dw::Application
332514

333515
// Particle settings
334516
uint32_t m_max_active_particles = 0; // Max Lifetime * Emission Rate
335-
uint32_t m_emission_rate = 0; // Particles per second
517+
uint32_t m_emission_rate = 100; // Particles per second
336518
float m_min_lifetime = 0.0f; // Seconds
337-
float m_max_lifetime = 0.0f; // Seconds
338-
float m_min_velocity = 0.0f;
339-
float m_max_velocity = 0.0f;
519+
float m_max_lifetime = 3.0f; // Seconds
520+
glm::vec3 m_min_velocity = glm::vec3(0.0f);
521+
glm::vec3 m_max_velocity = glm::vec3(0.0f, 1.0f, 0.0f);
340522
bool m_affected_by_gravity = false;
341523
PropertyChangeType m_color_mode = PROPERTY_CONSTANT;
342524
PropertyChangeType m_scale_mode = PROPERTY_CONSTANT;

0 commit comments

Comments
 (0)