├── .gitignore
├── Makefile
├── README.md
├── addons.make
├── bin
├── data
│ ├── .gitkeep
│ └── shaders
│ │ ├── particles_comp.glsl
│ │ ├── render_frag.glsl
│ │ └── render_vert.glsl
└── libs
│ ├── libfmodex.so
│ └── libfmodexp64.so
├── config.make
├── particleSystemCS.cbp
├── particleSystemCS.workspace
├── particle_system_compute_shader_screenshot_1.png
├── particle_system_compute_shader_screenshot_2.png
├── particle_system_compute_shader_screenshot_3.png
└── src
├── main.cpp
├── ofApp.cpp
├── ofApp.h
├── particleManager.cpp
└── particleManager.h
/.gitignore:
--------------------------------------------------------------------------------
1 | obj/
2 | bin/particleSystemCS*
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Attempt to load a config.make file.
2 | # If none is found, project defaults in config.project.make will be used.
3 | ifneq ($(wildcard config.make),)
4 | include config.make
5 | endif
6 |
7 | # make sure the the OF_ROOT location is defined
8 | ifndef OF_ROOT
9 | OF_ROOT=../../..
10 | endif
11 |
12 | # call the project makefile!
13 | include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Particle system with a compute shader
2 | -----------------------------------
3 |
4 | This is a simple particle system made with openFrameworks that uses a compute shader. The use of a compute shader allows the simulation of a huge number of particles while keeping a good framerate.
5 |
6 | 
7 |
8 | 
9 |
10 | 
11 |
12 | Compatibility
13 | -------------
14 |
15 | This program was tested with Linux and openFrameworks v0.9.0
--------------------------------------------------------------------------------
/addons.make:
--------------------------------------------------------------------------------
1 | ofxGui
--------------------------------------------------------------------------------
/bin/data/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elaye/particleSystemCS/08cc14f9b1b4177d8eb196063ca9f87b06dc4d39/bin/data/.gitkeep
--------------------------------------------------------------------------------
/bin/data/shaders/particles_comp.glsl:
--------------------------------------------------------------------------------
1 | #version 430
2 |
3 | #define EPS 0.001
4 |
5 | uniform vec3 attractor;
6 | uniform float strength;
7 | uniform float drag;
8 |
9 | struct Particle{
10 | vec4 pos;
11 | vec4 vel;
12 | vec4 acc;
13 | };
14 |
15 | layout(std430, binding=0) buffer particles{
16 | Particle p[];
17 | };
18 |
19 | layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in;
20 |
21 | void main(){
22 | uint gid = gl_GlobalInvocationID.x;
23 |
24 | vec3 dir = p[gid].pos.xyz - attractor;
25 |
26 | float d = dot(dir, dir);
27 |
28 | p[gid].acc.xyz = -strength/(d+EPS)*dir;
29 |
30 | p[gid].vel += p[gid].acc;
31 | p[gid].vel *= drag;
32 |
33 | p[gid].pos += p[gid].vel;
34 | }
--------------------------------------------------------------------------------
/bin/data/shaders/render_frag.glsl:
--------------------------------------------------------------------------------
1 | #version 430
2 |
3 | uniform vec4 globalColor;
4 |
5 | out vec4 color;
6 |
7 | void main(){
8 | vec2 location = gl_PointCoord - vec2(0.5, 0.5);
9 | float d = dot(location, location);
10 | if(d > (0.25)) discard;
11 |
12 | color = globalColor;
13 | }
--------------------------------------------------------------------------------
/bin/data/shaders/render_vert.glsl:
--------------------------------------------------------------------------------
1 | #version 430
2 |
3 | uniform mat4 modelViewProjectionMatrix;
4 | uniform mat4 modelViewMatrix;
5 |
6 | in vec4 position;
7 |
8 | void main(){
9 | gl_Position = modelViewProjectionMatrix * position;
10 |
11 | // Point size distance attenuation
12 | float dist = - (modelViewMatrix*position).z;
13 | gl_PointSize = clamp(500.0/dist, 1.0, 20.0);
14 | }
--------------------------------------------------------------------------------
/bin/libs/libfmodex.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elaye/particleSystemCS/08cc14f9b1b4177d8eb196063ca9f87b06dc4d39/bin/libs/libfmodex.so
--------------------------------------------------------------------------------
/bin/libs/libfmodexp64.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elaye/particleSystemCS/08cc14f9b1b4177d8eb196063ca9f87b06dc4d39/bin/libs/libfmodexp64.so
--------------------------------------------------------------------------------
/config.make:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # CONFIGURE PROJECT MAKEFILE (optional)
3 | # This file is where we make project specific configurations.
4 | ################################################################################
5 |
6 | ################################################################################
7 | # OF ROOT
8 | # The location of your root openFrameworks installation
9 | # (default) OF_ROOT = ../../..
10 | ################################################################################
11 | # OF_ROOT = ../../..
12 |
13 | ################################################################################
14 | # PROJECT ROOT
15 | # The location of the project - a starting place for searching for files
16 | # (default) PROJECT_ROOT = . (this directory)
17 | #
18 | ################################################################################
19 | # PROJECT_ROOT = .
20 |
21 | ################################################################################
22 | # PROJECT SPECIFIC CHECKS
23 | # This is a project defined section to create internal makefile flags to
24 | # conditionally enable or disable the addition of various features within
25 | # this makefile. For instance, if you want to make changes based on whether
26 | # GTK is installed, one might test that here and create a variable to check.
27 | ################################################################################
28 | # None
29 |
30 | ################################################################################
31 | # PROJECT EXTERNAL SOURCE PATHS
32 | # These are fully qualified paths that are not within the PROJECT_ROOT folder.
33 | # Like source folders in the PROJECT_ROOT, these paths are subject to
34 | # exlclusion via the PROJECT_EXLCUSIONS list.
35 | #
36 | # (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
37 | #
38 | # Note: Leave a leading space when adding list items with the += operator
39 | ################################################################################
40 | # PROJECT_EXTERNAL_SOURCE_PATHS =
41 |
42 | ################################################################################
43 | # PROJECT EXCLUSIONS
44 | # These makefiles assume that all folders in your current project directory
45 | # and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
46 | # to look for source code. The any folders or files that match any of the
47 | # items in the PROJECT_EXCLUSIONS list below will be ignored.
48 | #
49 | # Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
50 | # string unless teh user adds a wildcard (%) operator to match subdirectories.
51 | # GNU make only allows one wildcard for matching. The second wildcard (%) is
52 | # treated literally.
53 | #
54 | # (default) PROJECT_EXCLUSIONS = (blank)
55 | #
56 | # Will automatically exclude the following:
57 | #
58 | # $(PROJECT_ROOT)/bin%
59 | # $(PROJECT_ROOT)/obj%
60 | # $(PROJECT_ROOT)/%.xcodeproj
61 | #
62 | # Note: Leave a leading space when adding list items with the += operator
63 | ################################################################################
64 | # PROJECT_EXCLUSIONS =
65 |
66 | ################################################################################
67 | # PROJECT LINKER FLAGS
68 | # These flags will be sent to the linker when compiling the executable.
69 | #
70 | # (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
71 | #
72 | # Note: Leave a leading space when adding list items with the += operator
73 | #
74 | # Currently, shared libraries that are needed are copied to the
75 | # $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
76 | # add a runtime path to search for those shared libraries, since they aren't
77 | # incorporated directly into the final executable application binary.
78 | ################################################################################
79 | # PROJECT_LDFLAGS=-Wl,-rpath=./libs
80 |
81 | ################################################################################
82 | # PROJECT DEFINES
83 | # Create a space-delimited list of DEFINES. The list will be converted into
84 | # CFLAGS with the "-D" flag later in the makefile.
85 | #
86 | # (default) PROJECT_DEFINES = (blank)
87 | #
88 | # Note: Leave a leading space when adding list items with the += operator
89 | ################################################################################
90 | # PROJECT_DEFINES =
91 |
92 | ################################################################################
93 | # PROJECT CFLAGS
94 | # This is a list of fully qualified CFLAGS required when compiling for this
95 | # project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
96 | # defined in your platform specific core configuration files. These flags are
97 | # presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
98 | #
99 | # (default) PROJECT_CFLAGS = (blank)
100 | #
101 | # Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
102 | # your platform specific configuration file will be applied by default and
103 | # further flags here may not be needed.
104 | #
105 | # Note: Leave a leading space when adding list items with the += operator
106 | ################################################################################
107 | # PROJECT_CFLAGS =
108 |
109 | ################################################################################
110 | # PROJECT OPTIMIZATION CFLAGS
111 | # These are lists of CFLAGS that are target-specific. While any flags could
112 | # be conditionally added, they are usually limited to optimization flags.
113 | # These flags are added BEFORE the PROJECT_CFLAGS.
114 | #
115 | # PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
116 | #
117 | # (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
118 | #
119 | # PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
120 | #
121 | # (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
122 | #
123 | # Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
124 | # PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
125 | # file will be applied by default and further optimization flags here may not
126 | # be needed.
127 | #
128 | # Note: Leave a leading space when adding list items with the += operator
129 | ################################################################################
130 | # PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
131 | # PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
132 |
133 | ################################################################################
134 | # PROJECT COMPILERS
135 | # Custom compilers can be set for CC and CXX
136 | # (default) PROJECT_CXX = (blank)
137 | # (default) PROJECT_CC = (blank)
138 | # Note: Leave a leading space when adding list items with the += operator
139 | ################################################################################
140 | # PROJECT_CXX =
141 | # PROJECT_CC =
142 |
--------------------------------------------------------------------------------
/particleSystemCS.cbp:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/particleSystemCS.workspace:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/particle_system_compute_shader_screenshot_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elaye/particleSystemCS/08cc14f9b1b4177d8eb196063ca9f87b06dc4d39/particle_system_compute_shader_screenshot_1.png
--------------------------------------------------------------------------------
/particle_system_compute_shader_screenshot_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elaye/particleSystemCS/08cc14f9b1b4177d8eb196063ca9f87b06dc4d39/particle_system_compute_shader_screenshot_2.png
--------------------------------------------------------------------------------
/particle_system_compute_shader_screenshot_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elaye/particleSystemCS/08cc14f9b1b4177d8eb196063ca9f87b06dc4d39/particle_system_compute_shader_screenshot_3.png
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "ofMain.h"
2 | #include "ofApp.h"
3 |
4 | int main( ){
5 | ofGLWindowSettings settings;
6 | settings.setGLVersion(4,3);
7 | settings.width = 1024;
8 | settings.height = 768;
9 | settings.windowMode = OF_WINDOW;
10 | ofCreateWindow(settings);
11 |
12 | ofRunApp(new ofApp());
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/ofApp.cpp:
--------------------------------------------------------------------------------
1 | #include "ofApp.h"
2 |
3 | void ofApp::setup(){
4 | ofSetVerticalSync(false);
5 | ofSetFrameRate(30);
6 |
7 | pm.setup(1024*1024);
8 |
9 | gui.setup();
10 | gui.add(pm.parameters);
11 | gui.add(fpsDisp.setup("Fps", ""));
12 |
13 | bSettings = false;
14 | bPause = false;
15 | }
16 |
17 | void ofApp::update(){
18 | fpsDisp = ofToString(ofGetFrameRate());
19 |
20 | if(!bPause){
21 | pm.update();
22 | }
23 | }
24 |
25 | void ofApp::draw(){
26 | ofBackgroundGradient(ofColor(15, 16, 37), ofColor(11, 11, 10));
27 |
28 | cam.begin();
29 | pm.draw();
30 | cam.end();
31 |
32 | if(bSettings){
33 | gui.draw();
34 | }
35 | else{
36 | ofSetColor(ofColor::white);
37 | ofDrawBitmapString("'s' settings\n'p' pause\n'f' fullscreen", 15, 15);
38 | }
39 | }
40 |
41 | void ofApp::keyPressed(int key){
42 | switch(key){
43 | case 'f':
44 | ofToggleFullscreen();
45 | break;
46 | case 's':
47 | bSettings = !bSettings;
48 | break;
49 | case 'p':
50 | bPause = !bPause;
51 | break;
52 | default:
53 | break;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/ofApp.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "ofMain.h"
4 |
5 | #include "ofxGui.h"
6 |
7 | #include "particleManager.h"
8 |
9 | class ofApp : public ofBaseApp{
10 |
11 | ofEasyCam cam;
12 |
13 | particleManager pm;
14 |
15 | ofxLabel fpsDisp;
16 |
17 | ofxPanel gui;
18 |
19 | bool bSettings, bPause;
20 |
21 | public:
22 | void setup();
23 | void update();
24 | void draw();
25 |
26 | void keyPressed(int key);
27 | };
28 |
--------------------------------------------------------------------------------
/src/particleManager.cpp:
--------------------------------------------------------------------------------
1 | #include "particleManager.h"
2 |
3 | void particleManager::setup(const int _n){
4 | n = _n;
5 |
6 | particles.resize(n);
7 | initParticles();
8 |
9 | particlesBuffer.allocate(particles, GL_DYNAMIC_DRAW);
10 |
11 | vbo.setVertexBuffer(particlesBuffer, 4, sizeof(Particle));
12 |
13 | particlesBuffer.bindBase(GL_SHADER_STORAGE_BUFFER, 0);
14 |
15 | parameters.add(bShowAttractor.set("Show attractor", true));
16 | parameters.add(strength.set("Strength", 100, 0, 1000));
17 | parameters.add(drag.set("Drag", 0.0, 0.0, 1.0));
18 | parameters.add(color.set("Color", ofFloatColor(0.81, 0.13, 0.05, 0.15), ofFloatColor(0, 0, 0, 0), ofFloatColor(1, 1, 1, 1)));
19 |
20 | attractor = ofPoint(0, 0, 0);
21 |
22 | computeShader.setupShaderFromFile(GL_COMPUTE_SHADER, "shaders/particles_comp.glsl");
23 | computeShader.linkProgram();
24 |
25 | renderShader.load("shaders/render_vert.glsl", "shaders/render_frag.glsl");
26 | }
27 |
28 | void particleManager::initParticles(){
29 | for(int i = 0; i < n; ++i){
30 | particles[i].pos.x = ofRandomWidth() - ofGetWidth()/2.0;
31 | particles[i].pos.y = ofRandomHeight() - ofGetHeight()/2.0;
32 | particles[i].pos.z = ofRandom(-200, 200);
33 | particles[i].pos.w = 1.0;
34 | particles[i].vel.x = 0.0;
35 | particles[i].vel.y = 0.0;
36 | particles[i].vel.z = 0.0;
37 | particles[i].vel.w = 0.0;
38 | particles[i].acc.x = 0.0;
39 | particles[i].acc.y = 0.0;
40 | particles[i].acc.z = 0.0;
41 | particles[i].acc.w = 0.0;
42 | }
43 | }
44 |
45 | void particleManager::update(){
46 | updateAttractor();
47 |
48 | computeShader.begin();
49 | computeShader.setUniform3f("attractor", attractor.x, attractor.y, attractor.z);
50 | computeShader.setUniform1f("strength", strength);
51 | computeShader.setUniform1f("drag", 1.0 - drag);
52 | computeShader.dispatchCompute(n/WORK_GROUP_SIZE, 1, 1);
53 | // glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
54 | computeShader.end();
55 | }
56 |
57 | void particleManager::updateAttractor(){
58 | float t = ofGetElapsedTimef();
59 | attractor.x = 500*ofSignedNoise(0.1*t);
60 | attractor.y = 500*ofSignedNoise(0.3*t);
61 | attractor.z = 500*ofSignedNoise(0.5*t);
62 | }
63 |
64 | void particleManager::draw(){
65 | ofEnableBlendMode(OF_BLENDMODE_ADD);
66 | ofSetColor(color);
67 | renderShader.begin();
68 | vbo.draw(GL_POINTS, 0, n);
69 | renderShader.end();
70 | ofDisableBlendMode();
71 |
72 | if(bShowAttractor){
73 | ofSetColor(ofColor::red);
74 | ofDrawSphere(attractor, 10);
75 | }
76 | }
--------------------------------------------------------------------------------
/src/particleManager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "ofMain.h"
4 |
5 | #define WORK_GROUP_SIZE 256
6 |
7 | struct Particle{
8 | ofVec4f pos;
9 | ofVec4f vel;
10 | ofVec4f acc;
11 | };
12 |
13 | class particleManager{
14 |
15 | int n;
16 |
17 | ofShader computeShader, renderShader;
18 |
19 | vector particles;
20 | ofBufferObject particlesBuffer;
21 |
22 | ofVbo vbo;
23 |
24 | ofPoint attractor;
25 |
26 | ofParameter bShowAttractor;
27 | ofParameter strength;
28 | ofParameter drag;
29 | ofParameter color;
30 |
31 | public:
32 | ofParameterGroup parameters;
33 | void setup(const int n);
34 | void initParticles();
35 | void update();
36 | void updateAttractor();
37 | void draw();
38 | };
--------------------------------------------------------------------------------