12
12
#include < random>
13
13
14
14
#undef min
15
+ #undef max
15
16
#define CAMERA_FAR_PLANE 1000 .0f
16
- #define MAX_PARTICLES 1000000
17
+ #define MAX_PARTICLES 100
17
18
#define GRADIENT_SAMPLES 32
19
+ #define LOCAL_SIZE 32
18
20
19
21
struct GlobalUniforms
20
22
{
@@ -50,6 +52,7 @@ class GPUParticleSystem : public dw::Application
50
52
51
53
// Create camera.
52
54
create_camera ();
55
+ particle_initialize ();
53
56
54
57
glEnable (GL_MULTISAMPLE);
55
58
@@ -71,12 +74,13 @@ class GPUParticleSystem : public dw::Application
71
74
// Update camera.
72
75
update_camera ();
73
76
74
- update_uniforms ();
75
-
76
77
glBindFramebuffer (GL_FRAMEBUFFER, 0 );
77
78
glClearColor (0 .0f , 0 .0f , 0 .0f , 0 .0f );
78
79
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
79
80
81
+ particle_kickoff ();
82
+ particle_emission ();
83
+ particle_simulation ();
80
84
render_particle ();
81
85
82
86
m_debug_draw.grid (m_main_camera->m_view_projection , 1 .0f , 10 .0f );
@@ -185,14 +189,101 @@ class GPUParticleSystem : public dw::Application
185
189
186
190
void render_particle ()
187
191
{
192
+ glEnable (GL_DEPTH_TEST);
193
+
188
194
m_particle_program->use ();
189
195
190
196
m_particle_program->set_uniform (" u_Rotation" , glm::radians (m_rotation));
191
- m_particle_program->set_uniform (" u_Position" , m_position);
192
197
m_particle_program->set_uniform (" u_View" , m_main_camera->m_view );
193
198
m_particle_program->set_uniform (" u_Proj" , m_main_camera->m_projection );
194
199
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);
196
287
}
197
288
198
289
// -----------------------------------------------------------------------------------------------------------------------------------
@@ -201,8 +292,12 @@ class GPUParticleSystem : public dw::Application
201
292
{
202
293
{
203
294
// 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" ));
206
301
207
302
{
208
303
if (!m_particle_vs || !m_particle_fs)
@@ -221,6 +316,78 @@ class GPUParticleSystem : public dw::Application
221
316
return false ;
222
317
}
223
318
}
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
+ }
224
391
}
225
392
226
393
return true ;
@@ -230,8 +397,22 @@ class GPUParticleSystem : public dw::Application
230
397
231
398
bool create_buffers ()
232
399
{
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 );
235
416
236
417
return true ;
237
418
}
@@ -247,15 +428,6 @@ class GPUParticleSystem : public dw::Application
247
428
248
429
// -----------------------------------------------------------------------------------------------------------------------------------
249
430
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
-
259
431
void update_transforms (dw::Camera* camera)
260
432
{
261
433
// Update camera matrices.
@@ -298,22 +470,32 @@ class GPUParticleSystem : public dw::Application
298
470
// -----------------------------------------------------------------------------------------------------------------------------------
299
471
300
472
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
+
303
480
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;
304
485
305
486
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;
307
489
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_particle_data_ssbo;
308
490
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_alive_indices_pre_sim_ssbo;
309
491
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_alive_indices_post_sim_ssbo;
310
492
std::unique_ptr<dw::gl::ShaderStorageBuffer> m_dead_indices_ssbo;
493
+ std::unique_ptr<dw::gl::ShaderStorageBuffer> m_counters_ssbo;
311
494
312
495
std::unique_ptr<dw::gl::Texture1D> m_scale_over_time;
313
496
std::unique_ptr<dw::gl::Texture1D> m_color_over_time;
314
497
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;
317
499
318
500
GlobalUniforms m_global_uniforms;
319
501
@@ -332,11 +514,11 @@ class GPUParticleSystem : public dw::Application
332
514
333
515
// Particle settings
334
516
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
336
518
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 ) ;
340
522
bool m_affected_by_gravity = false ;
341
523
PropertyChangeType m_color_mode = PROPERTY_CONSTANT;
342
524
PropertyChangeType m_scale_mode = PROPERTY_CONSTANT;
0 commit comments