fixed: compile issue
[opensg.git] / Examples / Advanced / computeshader5.cpp
blobef68085b51cecebcc9e31b1102df37f192cf98ff
1 // OpenSG Tutorial Example: ComputeShader5
2 //
3 // This example shows a simple particle system that uses the compute shader
4 // to calculate the evolution of the system.
5 //
6 // What is particular interesting in this particular example is the usage
7 // of the ShaderStorageBufferObjRefChunk class. It allows the referencing
8 // of an already existing buffer object as a shader storage buffer object.
9 // Here three common properties (GeoPnt4fProperty, GeoVec4fProperty and
10 // GeoVec1fProperty) used. One for representing the particles positions,
11 // one for the particles velocities and the last one for the representing
12 // the lifetimes of the particles. The position property and the lifetime
13 // property is added to the geometry core created for rendering points to
14 // the screen. These propeties are binded as GL_ARRAY_BUFFER to the render
15 // shaders. Now, these positions, velocities and lifetimes are calculated
16 // by a compute shader before rendering. The compute shader expects for
17 // input and output either a texture or shader storage buffer objects.
18 // With the ShaderStorageBufferObjRefChunk the very same propeties buffer
19 // can now be binded as shader storage buffer objects, provided that the
20 // memory layout is compatible to the std430 layout. This, however, is the
21 // case for the Pnt4f, Vec4f and Vec1f properties.
23 // This example is based on an example created by Maurice Tollmien
24 // that can be found at
25 // https://github.com/MauriceGit/Partikel_accelleration_on_GPU
27 // His example is governed by the following license:
29 // Copyright (c) 2015, 2016 Maurice Tollmien <maurice.tollmien@gmail.com>
31 // Permission to use, copy, modify, and/or distribute this software for any
32 // purpose with or without fee is hereby granted, provided that the above
33 // copyright notice and this permission notice appear in all copies.
35 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
36 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
37 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
38 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
39 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
40 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
41 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44 #include <sstream>
45 #include <boost/foreach.hpp>
46 #include <boost/random.hpp>
48 #ifdef OSG_BUILD_ACTIVE
49 // Headers
50 #include <OSGGLUT.h>
51 #include <OSGConfig.h>
52 #include <OSGSimpleGeometry.h>
53 #include <OSGGLUTWindow.h>
54 #include <OSGSimpleSceneManager.h>
55 #include <OSGBaseFunctions.h>
56 #include <OSGTransform.h>
57 #include <OSGGroup.h>
59 // new headers:
60 #include <OSGGLEXT.h>
61 #include <OSGSolidBackground.h>
62 #include <OSGShaderProgramChunk.h>
63 #include <OSGShaderProgram.h>
64 #include <OSGShaderVariableOSG.h>
65 #include <OSGChunkMaterial.h>
66 #include <OSGMaterialGroup.h>
67 #include <OSGMaterialChunkOverrideGroup.h>
68 #include <OSGMultiPropertySSBOChunk.h>
69 #include <OSGShaderStorageBufferObjRefChunk.h>
70 #include <OSGShaderProgramVariableChunk.h>
71 #include <OSGAlgorithmComputeElement.h>
72 #include <OSGComputeShaderAlgorithm.h>
73 #include <OSGComputeShaderChunk.h>
74 #include <OSGShaderProgram.h>
75 #include <OSGShaderProgramVariables.h>
76 #include <OSGTypedGeoIntegralProperty.h>
77 #include <OSGTypedGeoVectorProperty.h>
78 #include <OSGGeoVectorBufferProperty.h>
80 #else
81 // Headers
82 #include <OpenSG/OSGGLUT.h>
83 #include <OpenSG/OSGConfig.h>
84 #include <OpenSG/OSGSimpleGeometry.h>
85 #include <OpenSG/OSGGLUTWindow.h>
86 #include <OpenSG/OSGSimpleSceneManager.h>
87 #include <OpenSG/OSGBaseFunctions.h>
88 #include <OpenSG/OSGTransform.h>
89 #include <OpenSG/OSGGroup.h>
91 // new headers:
92 #include <OpenSG/OSGGLEXT.h>
93 #include <OpenSG/OSGSolidBackground.h>
94 #include <OpenSG/OSGShaderProgramChunk.h>
95 #include <OpenSG/OSGShaderProgram.h>
96 #include <OpenSG/OSGShaderVariableOSG.h>
97 #include <OpenSG/OSGChunkMaterial.h>
98 #include <OpenSG/OSGMaterialGroup.h>
99 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
100 #include <OpenSG/OSGMultiPropertySSBOChunk.h>
101 #include <OpenSG/OSGShaderStorageBufferObjRefChunk.h>
102 #include <OpenSG/OSGShaderProgramVariableChunk.h>
103 #include <OpenSG/OSGAlgorithmComputeElement.h>
104 #include <OpenSG/OSGComputeShaderAlgorithm.h>
105 #include <OpenSG/OSGComputeShaderChunk.h>
106 #include <OpenSG/OSGShaderProgram.h>
107 #include <OpenSG/OSGShaderProgramVariables.h>
108 #include <OpenSG/OSGTypedGeoIntegralProperty.h>
109 #include <OpenSG/OSGTypedGeoVectorProperty.h>
110 #include <OpenSG/OSGGeoVectorBufferProperty.h>
111 #endif
113 const OSG::Real32 world_size = 800.0;
114 const OSG::UInt32 particle_count = 6000000;
115 const OSG::UInt32 attractor_count = 12;
116 const OSG::Real32 attractor_time = 8.0f;
117 const OSG::Real32 attractor_factor = 10.0f;
118 const OSG::Real32 delta_time = 100.0f;
120 const OSG::Vec3i work_group_count(particle_count / 128, 1,1);
122 const OSG::Real32 position_max = 4.0f;
123 const OSG::Real32 velocity_max = 0.3f;
124 const OSG::Real32 attractor_max = 40.0f;
126 boost::uniform_real<float> position_distribution ( -position_max, position_max);
127 boost::uniform_real<float> velocity_distribution ( -velocity_max, velocity_max);
128 boost::uniform_real<float> attractor_distribution(-attractor_max, attractor_max);
129 boost::uniform_01<float> lifetime_distribution;
131 typedef boost::mt19937 RNGType;
132 RNGType rng(time(0));
134 boost::variate_generator< RNGType, boost::uniform_real<float> > position_die(rng, position_distribution);
135 boost::variate_generator< RNGType, boost::uniform_real<float> > velocity_die(rng, velocity_distribution);
136 boost::variate_generator< RNGType, boost::uniform_real<float> > attractor_die(rng, attractor_distribution);
137 boost::variate_generator< RNGType, boost::uniform_01<float> > lifetime_die(rng, lifetime_distribution);
140 // The SimpleSceneManager to manage simple applications
142 OSG::SimpleSceneManagerRefPtr mgr;
145 // Simulation data
147 struct Attractor
149 Attractor() : position(0.f, 0.f, 0.f), mass(0.f) {}
150 OSG::Pnt3f position;
151 OSG::Real32 mass;
152 static OSG::UInt32 position_id;
153 static OSG::UInt32 mass_id;
155 OSG::UInt32 Attractor::position_id = 0;
156 OSG::UInt32 Attractor::mass_id = 0;
158 typedef std::vector<OSG::Pnt4f> VecPositionsT;
159 typedef std::vector<OSG::Vec4f> VecVelocitiesT;
160 typedef std::vector<OSG::Real32> VecLifetimesT;
161 typedef std::vector<Attractor> VecAttractorsT;
163 VecPositionsT initialize_positions(std::size_t num)
165 VecPositionsT positions;
166 positions.resize(num);
168 for (std::size_t i = 0; i < num; ++i)
170 OSG::Pnt4f p(position_die(), position_die(), position_die(), 1.f);
171 positions[i] = p;
174 return positions;
177 VecVelocitiesT initialize_velocities(std::size_t num)
179 VecVelocitiesT velocities;
180 velocities.resize(num);
182 for (std::size_t i = 0; i < num; ++i)
184 OSG::Vec4f v(velocity_die(), velocity_die(), velocity_die(), 0.f);
185 velocities[i] = v;
188 return velocities;
191 VecLifetimesT initialize_lifetimes(std::size_t num)
193 VecLifetimesT lifetimes;
194 lifetimes.resize(num);
196 for (std::size_t i = 0; i < num; ++i)
198 lifetimes[i] = lifetime_die();
201 return lifetimes;
204 VecAttractorsT initialize_attractors(std::size_t num)
206 VecAttractorsT attractors;
207 attractors.resize(num);
209 for (std::size_t i = 0; i < num; ++i)
211 OSG::Pnt3f p(
212 attractor_die(),
213 attractor_die(),
214 attractor_die() * attractor_factor);
215 attractors[i].position = p;
216 attractors[i].mass = 0.f;
219 return attractors;
222 void update_attractors(VecAttractorsT& attractors)
224 for (std::size_t i = 0; i < attractors.size(); ++i)
226 OSG::Pnt3f p(
227 attractor_die(),
228 attractor_die(),
229 attractor_die() * attractor_factor);
230 attractors[i].position = p;
231 attractors[i].mass = 0.f;
235 VecPositionsT positions = initialize_positions (particle_count);
236 VecVelocitiesT velocities = initialize_velocities(particle_count);
237 VecLifetimesT lifetimes = initialize_lifetimes (particle_count);
238 VecAttractorsT attractors = initialize_attractors(attractor_count);
240 OSG::GeoPnt4fPropertyTransitPtr create_position_property(const VecPositionsT& positions)
242 OSG::GeoPnt4fPropertyRefPtr properties = OSG::GeoPnt4fProperty::create();
244 properties->setUseVBO(true);
246 BOOST_FOREACH(const OSG::Pnt4f pnt, positions)
248 properties->push_back(pnt);
251 return OSG::GeoPnt4fPropertyTransitPtr(properties);
254 OSG::GeoVec4fPropertyTransitPtr create_velocity_property(const VecVelocitiesT& velocities)
256 OSG::GeoVec4fPropertyRefPtr properties = OSG::GeoVec4fProperty::create();
258 properties->setUseVBO(true);
260 BOOST_FOREACH(const OSG::Vec4f vec, velocities)
262 properties->push_back(vec);
265 return OSG::GeoVec4fPropertyTransitPtr(properties);
268 OSG::GeoVec1fPropertyTransitPtr create_lifetime_property(const VecLifetimesT& lifetimes)
270 OSG::GeoVec1fPropertyRefPtr properties = OSG::GeoVec1fProperty::create();
272 properties->setUseVBO(true);
274 BOOST_FOREACH(OSG::Real32 val, lifetimes)
276 properties->push_back(OSG::Vec1f(val));
279 return OSG::GeoVec1fPropertyTransitPtr(properties);
282 OSG::MultiPropertySSBOChunkTransitPtr create_attractor_ssbo_chunk(const VecAttractorsT& attractors)
284 OSG::MultiPropertySSBOChunkRefPtr attractorChunk = OSG::MultiPropertySSBOChunk::create();
286 OSG::UInt32 vec3_id, float_id;
288 vec3_id = attractorChunk->addMember(OSG::MultiPropertySSBOChunk:: VEC3_T);
289 float_id = attractorChunk->addMember(OSG::MultiPropertySSBOChunk::FLOAT_T);
291 attractorChunk->setUsage(GL_STATIC_DRAW);
293 Attractor::position_id = vec3_id++;
294 Attractor:: mass_id = float_id++;
296 BOOST_FOREACH(const Attractor& a, attractors)
298 OSG::UInt32 idx = attractorChunk->addProperty();
300 attractorChunk->setVec3Property (idx, Attractor::position_id, a.position.subZero());
301 attractorChunk->setFloatProperty(idx, Attractor:: mass_id, a.mass);
304 return OSG::MultiPropertySSBOChunkTransitPtr(attractorChunk);
307 void update_attractor_state(OSG::MultiPropertySSBOChunk* attractorChunk, const VecAttractorsT& attractors)
309 if (attractorChunk)
311 if (attractorChunk->getNumProperties() != attractors.size())
313 attractorChunk->clearProperties();
315 BOOST_FOREACH(const Attractor& a, attractors)
317 OSG::UInt32 idx = attractorChunk->addProperty();
319 attractorChunk->setVec3Property (idx, Attractor::position_id, a.position.subZero());
320 attractorChunk->setFloatProperty(idx, Attractor:: mass_id, a.mass);
323 else
325 for (OSG::UInt32 idx = 0; idx < attractors.size(); ++idx)
327 const Attractor& a = attractors[idx];
329 attractorChunk->setVec3Property (idx, Attractor::position_id, a.position.subZero());
330 attractorChunk->setFloatProperty(idx, Attractor:: mass_id, a.mass);
336 OSG::ShaderStorageBufferObjRefChunkTransitPtr create_ssbo_ref_chunk(OSG::UInt32 glId)
338 OSG::ShaderStorageBufferObjRefChunkRefPtr chunk = OSG::ShaderStorageBufferObjRefChunk::create();
340 chunk->setOsgGLId(glId);
342 return OSG::ShaderStorageBufferObjRefChunkTransitPtr(chunk);
346 // compute, vertex and fragment shader program.
348 std::string get_cp_program();
349 std::string get_vp_program();
350 std::string get_fp_program();
352 const OSG::UInt32 position_binding_point = 1;
353 const OSG::UInt32 velocity_binding_point = 2;
354 const OSG::UInt32 lifetime_binding_point = 3;
355 const OSG::UInt32 attractor_binding_point = 4;
358 // Proerties and shader storage buffer objects corresponding to the shader blocks
360 OSG::GeoVectorPropertyRefPtr geoprops_position = NULL;
361 OSG::GeoVectorPropertyRefPtr geoprops_velocity = NULL;
362 OSG::GeoVectorPropertyRefPtr geoprops_lifetime = NULL;
364 OSG::ShaderStorageBufferObjRefChunkRefPtr ssbo_position = NULL;
365 OSG::ShaderStorageBufferObjRefChunkRefPtr ssbo_velocity = NULL;
366 OSG::ShaderStorageBufferObjRefChunkRefPtr ssbo_lifetime = NULL;
368 OSG::MultiPropertySSBOChunkRefPtr ssbo_attractor = NULL;
370 OSG::ShaderProgramRefPtr compShader = NULL;
373 // The computation core
375 void createSimulationData()
377 geoprops_position = create_position_property(positions );
378 geoprops_velocity = create_velocity_property(velocities);
379 geoprops_lifetime = create_lifetime_property(lifetimes );
381 ssbo_position = create_ssbo_ref_chunk(geoprops_position->getGLId());
382 ssbo_velocity = create_ssbo_ref_chunk(geoprops_velocity->getGLId());
383 ssbo_lifetime = create_ssbo_ref_chunk(geoprops_lifetime->getGLId());
385 ssbo_attractor = create_attractor_ssbo_chunk(attractors);
388 OSG::AlgorithmComputeElementTransitPtr createComputation()
390 OSG::ChunkMaterialRefPtr data_state = OSG::ChunkMaterial::create();
391 data_state->addChunk(ssbo_position, position_binding_point);
392 data_state->addChunk(ssbo_velocity, velocity_binding_point);
393 data_state->addChunk(ssbo_lifetime, lifetime_binding_point);
394 data_state->addChunk(ssbo_attractor, attractor_binding_point);
396 compShader = OSG::ShaderProgram::create();
397 compShader->setShaderType(GL_COMPUTE_SHADER);
398 compShader->setProgram(get_cp_program());
399 compShader->addUniformVariable("dt", 0.f);
400 compShader->addShaderStorageBlock("Positions", position_binding_point);
401 compShader->addShaderStorageBlock("Velocities", velocity_binding_point);
402 compShader->addShaderStorageBlock("Lifetimes", lifetime_binding_point);
403 compShader->addShaderStorageBlock("Attractors", attractor_binding_point);
405 OSG::ComputeShaderChunkRefPtr compShaderChunk = OSG::ComputeShaderChunk::create();
406 compShaderChunk->addComputeShader(compShader);
407 compShaderChunk->setVariables(compShader->getVariables());
409 OSG::ComputeShaderAlgorithmRefPtr compShaderAlgo = OSG::ComputeShaderAlgorithm::create();
410 compShaderAlgo->setUseMemoryBarrier(true);
411 compShaderAlgo->setMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
412 compShaderAlgo->setComputeShader(compShaderChunk);
413 compShaderAlgo->setDispatchConfig(work_group_count);
414 compShaderAlgo->setChunkMaterial(data_state);
416 OSG::AlgorithmComputeElementRefPtr algoCompElement = OSG::AlgorithmComputeElement::create();
417 algoCompElement->setAlgorithm(compShaderAlgo);
419 return OSG::AlgorithmComputeElementTransitPtr(algoCompElement);
423 // The scene to be rendered
425 OSG::NodeTransitPtr createScene()
427 OSG::NodeRefPtr scene = OSG::Node::create();
429 OSG::GeometryRefPtr geometry = OSG::Geometry::create();
430 geometry->setDlistCache(false);
431 geometry->setUseVAO(true);
432 geometry->setUseAttribCalls(true);
434 OSG::NodeRefPtr geomNode = OSG::makeNodeFor(geometry);
436 OSG::GeoUInt8PropertyRefPtr types = OSG::GeoUInt8Property ::create();
437 OSG::GeoUInt32PropertyRefPtr lengths = OSG::GeoUInt32Property::create();
439 types ->addValue(GL_POINTS);
440 lengths->addValue(particle_count);
442 types ->setUseVBO(true);
443 lengths ->setUseVBO(true);
445 types ->setUsage(OSG::GeoProperty::UsageSystemSet);
446 lengths ->setUsage(OSG::GeoProperty::UsageSystemSet);
448 geometry->setTypes (types);
449 geometry->setLengths (lengths);
451 geometry->setProperty (geoprops_position, 0);
452 geometry->setProperty (geoprops_lifetime, 1);
454 OSG::BoxVolume& volume = geomNode->editVolume();
456 volume.setBounds(OSG::Pnt3f(-world_size,-world_size,-world_size), OSG::Pnt3f(world_size,world_size,world_size));
457 volume.setStatic(true);
459 scene->addChild(geomNode);
462 // create the shader program
464 OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
465 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
466 OSG::ShaderProgramRefPtr fragShader = OSG::ShaderProgram::createFragmentShader();
468 vertShader->setProgram(get_vp_program());
469 fragShader->setProgram(get_fp_program());
471 vertShader->addOSGVariable("OSGModelViewMatrix");
472 vertShader->addOSGVariable("OSGProjectionMatrix");
474 prog_chunk->addShader(vertShader);
475 prog_chunk->addShader(fragShader);
477 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
478 prog_state->addChunk(prog_chunk);
480 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
481 mgrp->setMaterial(prog_state);
482 scene->setCore(mgrp);
484 return OSG::NodeTransitPtr(scene);
488 // forward declaration so we can have the interesting stuff upfront
490 int setupGLUT(int *argc, char *argv[]);
491 void releaseGLUT();
492 void print_help();
495 // Initialize GLUT & OpenSG and set up the scene
497 int main(int argc, char **argv)
499 // OSG init
500 OSG::osgInit(argc,argv);
502 // GLUT init
503 int winid = setupGLUT(&argc, argv);
505 print_help();
507 // open a new scope, because the pointers below should go out of scope
508 // before entering glutMainLoop.
509 // Otherwise OpenSG will complain about objects being alive after shutdown.
511 // the connection between GLUT and OpenSG
512 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
513 gwin->setGlutId(winid);
514 gwin->init();
516 // create the SimpleSceneManager helper
517 mgr = OSG::SimpleSceneManager::create();
518 mgr->setWindow(gwin);
520 createSimulationData();
522 OSG::NodeRefPtr root = OSG::makeNodeFor(createComputation());
524 root->addChild(createScene());
526 mgr->setRoot(root);
528 OSG::SolidBackgroundRefPtr bgnd = OSG::SolidBackground::create();
529 bgnd->setColor(OSG::Color3f(1.f, 1.f, 1.f));
531 mgr->setBackground(bgnd);
533 OSG::commitChanges();
535 // show the whole scene
536 mgr->showAll();
539 // GLUT main loop
540 glutMainLoop();
542 return 0;
546 // GLUT callback functions
549 OSG::TimeStamp time_stamp = 0;
550 OSG::Real32 simulation_time = 0;
553 // redraw the window
555 void display(void)
557 if (!mgr) return;
559 if (time_stamp == 0)
560 time_stamp = OSG::getTimeStamp();
562 OSG::TimeStamp now = OSG::getTimeStamp();
563 OSG::Time elapsed = OSG::getTimeStampMsecs(now - time_stamp);
565 OSG::Real32 dt = elapsed / 1000.f;
567 simulation_time += dt;
569 if (compShader)
570 compShader->updateUniformVariable("dt", delta_time * OSG::Real32(elapsed) / 1000.f);
572 if (simulation_time >= attractor_time)
574 update_attractors(attractors);
575 update_attractor_state(ssbo_attractor, attractors);
577 simulation_time = 0.f;
580 OSG::commitChanges();
582 mgr->redraw();
584 time_stamp = now;
589 // react to size changes
591 void reshape(int w, int h)
593 mgr->resize(w, h);
594 glutPostRedisplay();
598 // react to mouse button presses
600 void mouse(int button, int state, int x, int y)
602 if (state)
603 mgr->mouseButtonRelease(button, x, y);
604 else
605 mgr->mouseButtonPress(button, x, y);
607 glutPostRedisplay();
611 // react to mouse motions with pressed buttons
613 void motion(int x, int y)
615 mgr->mouseMove(x, y);
616 glutPostRedisplay();
620 // react to keys
622 void keyboard(unsigned char k, int x, int y)
624 switch(k)
626 case 27:
628 // clean up global variables
629 mgr = NULL;
631 geoprops_position = NULL;
632 geoprops_velocity = NULL;
633 geoprops_lifetime = NULL;
635 ssbo_position = NULL;
636 ssbo_velocity = NULL;
637 ssbo_lifetime = NULL;
638 ssbo_attractor = NULL;
640 compShader = NULL;
642 releaseGLUT();
644 OSG::osgExit();
645 exit(0);
647 break;
649 case 's':
651 mgr->setStatistics(!mgr->getStatistics());
653 break;
658 // setup the GLUT library which handles the windows for us
660 int setupGLUT(int *argc, char *argv[])
662 glutInit(argc, argv);
663 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
664 glutInitWindowSize(1000, 800);
666 int winid = glutCreateWindow("OpenSG");
668 glutReshapeFunc(reshape);
669 glutDisplayFunc(display);
670 glutMouseFunc(mouse);
671 glutMotionFunc(motion);
672 glutKeyboardFunc(keyboard);
674 // call the redraw function whenever there's nothing else to do
675 glutIdleFunc(display);
677 return winid;
680 void releaseGLUT()
682 glutReshapeFunc(NULL);
683 //glutDisplayFunc(NULL);
684 glutMouseFunc(NULL);
685 glutMotionFunc(NULL);
686 glutKeyboardFunc(NULL);
687 glutIdleFunc(NULL);
690 void print_help()
692 std::cout << "Esc : quit example" << std::endl;
696 // compute shader program.
698 std::string get_cp_program()
700 using namespace std;
701 stringstream ost;
703 ost << "#version 430 compatibility"
704 << endl << ""
705 << endl << "layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in;"
706 << endl << ""
707 << endl << "layout (std430, binding = 1) buffer Positions"
708 << endl << "{"
709 << endl << " vec4 positions[];"
710 << endl << "};"
711 << endl << ""
712 << endl << "layout (std430, binding = 2) buffer Velocities"
713 << endl << "{"
714 << endl << " vec4 velocities[];"
715 << endl << "};"
716 << endl << ""
717 << endl << "layout (std430, binding = 3) buffer Lifetimes"
718 << endl << "{"
719 << endl << " float lifetimes[];"
720 << endl << "};"
721 << endl << ""
722 << endl << "struct Attractor"
723 << endl << "{"
724 << endl << " vec3 position;"
725 << endl << " float mass;"
726 << endl << "};"
727 << endl << ""
728 << endl << "layout (std430, binding = 4) buffer Attractors"
729 << endl << "{"
730 << endl << " Attractor attractors[];"
731 << endl << "};"
732 << endl << ""
733 << endl << "// Delta time"
734 << endl << "uniform float dt;"
735 << endl << ""
736 << endl << "//"
737 << endl << "// See: http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/"
738 << endl << "//"
739 << endl << "highp float rand(vec2 v)"
740 << endl << "{"
741 << endl << " highp float a = 12.9898;"
742 << endl << " highp float b = 78.233;"
743 << endl << " highp float c = 43758.5453;"
744 << endl << " highp float d = dot(v.xy, vec2(a,b));"
745 << endl << " highp float e = mod(d, 3.14);"
746 << endl << " return fract(sin(e) * c);"
747 << endl << "}"
748 << endl << ""
749 << endl << "vec3 calcForceFor(vec3 forcePoint, vec3 pos)"
750 << endl << "{"
751 << endl << " float gauss = 10000.0;"
752 << endl << " float e = 2.71828183;"
753 << endl << " float k_weak = 1.0;"
754 << endl << ""
755 << endl << " vec3 dir = forcePoint - pos.xyz;"
756 << endl << " float g = pow (e, -pow(length(dir), 2) / gauss);"
757 << endl << " vec3 f = normalize(dir) * k_weak * (1+ mod(rand(dir.xy), 10) - mod(rand(dir.yz), 10)) / 10.0 * g;"
758 << endl << ""
759 << endl << " return f;"
760 << endl << "}"
761 << endl << ""
762 << endl << "void main(void)"
763 << endl << "{"
764 << endl << " uint index = gl_GlobalInvocationID.x;"
765 << endl << ""
766 << endl << " vec3 forcePoint = vec3(0);"
767 << endl << ""
768 << endl << " for (int i = 0; i < attractors.length(); i++)"
769 << endl << " {"
770 << endl << " forcePoint += attractors[i].position;"
771 << endl << " }"
772 << endl << ""
773 << endl << " vec3 vel = velocities[index].xyz;"
774 << endl << " vec3 pos = positions[index].xyz;"
775 << endl << " float lifetime = lifetimes[index];"
776 << endl << ""
777 << endl << " float k_v = 1.5;"
778 << endl << ""
779 << endl << " vec3 f = calcForceFor(forcePoint, pos) + rand(pos.xz)/100.0;"
780 << endl << ""
781 << endl << " vec3 v = normalize(vel + (f * dt)) * k_v;"
782 << endl << ""
783 << endl << " v += (forcePoint-pos) * 0.00005;"
784 << endl << ""
785 << endl << " vec3 s = pos + v * dt;"
786 << endl << ""
787 << endl << " lifetime -= 0.0001 * dt;"
788 << endl << ""
789 << endl << " if (lifetime <= 0)"
790 << endl << " {"
791 << endl << " s = -s + rand(s.xy)*20.0 -rand(s.yz)*20.0;"
792 << endl << " lifetime = 0.99;"
793 << endl << " }"
794 << endl << ""
795 << endl << ""
796 << endl << " lifetimes[index] = lifetime;"
797 << endl << " positions[index] = vec4(s, 1.0);"
798 << endl << " velocities[index] = vec4(v, 0.0);"
799 << endl << "}"
800 << endl << ""
801 << endl;
803 return ost.str();
807 // vertex shader program.
809 std::string get_vp_program()
811 using namespace std;
812 stringstream ost;
814 ost << "#version 430 compatibility"
815 << endl << ""
816 << endl << "layout (location = 0) in vec4 vertPos;"
817 << endl << "layout (location = 1) in float lifetime;"
818 << endl << ""
819 << endl << "uniform mat4 OSGModelViewMatrix;"
820 << endl << "uniform mat4 OSGProjectionMatrix;"
821 << endl << ""
822 << endl << "out float color;"
823 << endl << ""
824 << endl << "void main()"
825 << endl << "{"
826 << endl << " color = lifetime;"
827 << endl << " gl_Position = OSGProjectionMatrix * OSGModelViewMatrix * vertPos;"
828 << endl << "}"
829 << endl << ""
830 << endl;
832 return ost.str();
836 // fragment shader program for bump mapping in surface local coordinates
838 std::string get_fp_program()
840 using namespace std;
841 stringstream ost;
843 ost << "#version 430 compatibility"
844 << endl << ""
845 << endl << "in float color;"
846 << endl << ""
847 << endl << "layout(location = 0) out vec4 vFragColor;"
848 << endl << ""
849 << endl << "void main()"
850 << endl << "{"
851 << endl << " if (color < 0.1)"
852 << endl << " {"
853 << endl << " vFragColor = mix(vec4(vec3(0.0),1.0), vec4(0.0,0.5,1.0,1.0), color*10.0);"
854 << endl << " }"
855 << endl << " else if (color > 0.9)"
856 << endl << " {"
857 << endl << " vFragColor = mix(vec4(0.6,0.05,0.0,1.0), vec4(vec3(0.0),1.0), (color-0.9)*10.0);"
858 << endl << " }"
859 << endl << " else"
860 << endl << " {"
861 << endl << " vFragColor = mix(vec4(0.0,0.5,1.0,1.0), vec4(0.6,0.05,0.0,1.0), color);"
862 << endl << " }"
863 << endl << "}"
864 << endl << ""
865 << endl;
867 return ost.str();