1 // OpenSG Tutorial Example: ComputeShader5
3 // This example shows a simple particle system that uses the compute shader
4 // to calculate the evolution of the system.
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.
45 #include <boost/foreach.hpp>
46 #include <boost/random.hpp>
48 #ifdef OSG_BUILD_ACTIVE
51 #include <OSGConfig.h>
52 #include <OSGSimpleGeometry.h>
53 #include <OSGGLUTWindow.h>
54 #include <OSGSimpleSceneManager.h>
55 #include <OSGBaseFunctions.h>
56 #include <OSGTransform.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>
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>
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>
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
;
149 Attractor() : position(0.f
, 0.f
, 0.f
), mass(0.f
) {}
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
);
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
);
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();
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
)
214 attractor_die() * attractor_factor
);
215 attractors
[i
].position
= p
;
216 attractors
[i
].mass
= 0.f
;
222 void update_attractors(VecAttractorsT
& attractors
)
224 for (std::size_t i
= 0; i
< attractors
.size(); ++i
)
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
)
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
);
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
[]);
495 // Initialize GLUT & OpenSG and set up the scene
497 int main(int argc
, char **argv
)
500 OSG::osgInit(argc
,argv
);
503 int winid
= setupGLUT(&argc
, argv
);
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
);
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());
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
546 // GLUT callback functions
549 OSG::TimeStamp time_stamp
= 0;
550 OSG::Real32 simulation_time
= 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
;
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();
589 // react to size changes
591 void reshape(int w
, int h
)
598 // react to mouse button presses
600 void mouse(int button
, int state
, int x
, int y
)
603 mgr
->mouseButtonRelease(button
, x
, y
);
605 mgr
->mouseButtonPress(button
, x
, y
);
611 // react to mouse motions with pressed buttons
613 void motion(int x
, int y
)
615 mgr
->mouseMove(x
, y
);
622 void keyboard(unsigned char k
, int x
, int y
)
628 // clean up global variables
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
;
651 mgr
->setStatistics(!mgr
->getStatistics());
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
);
682 glutReshapeFunc(NULL
);
683 //glutDisplayFunc(NULL);
685 glutMotionFunc(NULL
);
686 glutKeyboardFunc(NULL
);
692 std::cout
<< "Esc : quit example" << std::endl
;
696 // compute shader program.
698 std::string
get_cp_program()
703 ost
<< "#version 430 compatibility"
705 << endl
<< "layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in;"
707 << endl
<< "layout (std430, binding = 1) buffer Positions"
709 << endl
<< " vec4 positions[];"
712 << endl
<< "layout (std430, binding = 2) buffer Velocities"
714 << endl
<< " vec4 velocities[];"
717 << endl
<< "layout (std430, binding = 3) buffer Lifetimes"
719 << endl
<< " float lifetimes[];"
722 << endl
<< "struct Attractor"
724 << endl
<< " vec3 position;"
725 << endl
<< " float mass;"
728 << endl
<< "layout (std430, binding = 4) buffer Attractors"
730 << endl
<< " Attractor attractors[];"
733 << endl
<< "// Delta time"
734 << endl
<< "uniform float dt;"
737 << endl
<< "// See: http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/"
739 << endl
<< "highp float rand(vec2 v)"
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);"
749 << endl
<< "vec3 calcForceFor(vec3 forcePoint, vec3 pos)"
751 << endl
<< " float gauss = 10000.0;"
752 << endl
<< " float e = 2.71828183;"
753 << endl
<< " float k_weak = 1.0;"
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;"
759 << endl
<< " return f;"
762 << endl
<< "void main(void)"
764 << endl
<< " uint index = gl_GlobalInvocationID.x;"
766 << endl
<< " vec3 forcePoint = vec3(0);"
768 << endl
<< " for (int i = 0; i < attractors.length(); i++)"
770 << endl
<< " forcePoint += attractors[i].position;"
773 << endl
<< " vec3 vel = velocities[index].xyz;"
774 << endl
<< " vec3 pos = positions[index].xyz;"
775 << endl
<< " float lifetime = lifetimes[index];"
777 << endl
<< " float k_v = 1.5;"
779 << endl
<< " vec3 f = calcForceFor(forcePoint, pos) + rand(pos.xz)/100.0;"
781 << endl
<< " vec3 v = normalize(vel + (f * dt)) * k_v;"
783 << endl
<< " v += (forcePoint-pos) * 0.00005;"
785 << endl
<< " vec3 s = pos + v * dt;"
787 << endl
<< " lifetime -= 0.0001 * dt;"
789 << endl
<< " if (lifetime <= 0)"
791 << endl
<< " s = -s + rand(s.xy)*20.0 -rand(s.yz)*20.0;"
792 << endl
<< " lifetime = 0.99;"
796 << endl
<< " lifetimes[index] = lifetime;"
797 << endl
<< " positions[index] = vec4(s, 1.0);"
798 << endl
<< " velocities[index] = vec4(v, 0.0);"
807 // vertex shader program.
809 std::string
get_vp_program()
814 ost
<< "#version 430 compatibility"
816 << endl
<< "layout (location = 0) in vec4 vertPos;"
817 << endl
<< "layout (location = 1) in float lifetime;"
819 << endl
<< "uniform mat4 OSGModelViewMatrix;"
820 << endl
<< "uniform mat4 OSGProjectionMatrix;"
822 << endl
<< "out float color;"
824 << endl
<< "void main()"
826 << endl
<< " color = lifetime;"
827 << endl
<< " gl_Position = OSGProjectionMatrix * OSGModelViewMatrix * vertPos;"
836 // fragment shader program for bump mapping in surface local coordinates
838 std::string
get_fp_program()
843 ost
<< "#version 430 compatibility"
845 << endl
<< "in float color;"
847 << endl
<< "layout(location = 0) out vec4 vFragColor;"
849 << endl
<< "void main()"
851 << endl
<< " if (color < 0.1)"
853 << endl
<< " vFragColor = mix(vec4(vec3(0.0),1.0), vec4(0.0,0.5,1.0,1.0), color*10.0);"
855 << endl
<< " else if (color > 0.9)"
857 << endl
<< " vFragColor = mix(vec4(0.6,0.05,0.0,1.0), vec4(vec3(0.0),1.0), (color-0.9)*10.0);"
861 << endl
<< " vFragColor = mix(vec4(0.0,0.5,1.0,1.0), vec4(0.6,0.05,0.0,1.0), color);"