fixed: auto_ptr -> unique_ptr
[opensg.git] / Examples / Advanced / computeshader4.cpp
blobc24f5d462c78384f9feb88e15267b4f8b189ac31
1 // OpenSG Tutorial Example: ComputeShader4
2 //
3 // This example renders just the cylinder / torus animation that
4 // is known from many others of the simple examples. What is new
5 // is that the material database is filled by a compute shader.
6 //
7 // The point here is that the shader storage buffer object for
8 // the material database is modified by the compute shader and
9 // then read by the fragment shader that runs after the compute
10 // shader.
13 #include <sstream>
14 #include <boost/random/mersenne_twister.hpp>
15 #include <boost/random/uniform_int_distribution.hpp>
17 #ifdef OSG_BUILD_ACTIVE
18 // Headers
19 #include <OSGGLUT.h>
20 #include <OSGConfig.h>
21 #include <OSGSimpleGeometry.h>
22 #include <OSGGLUTWindow.h>
23 #include <OSGSimpleSceneManager.h>
24 #include <OSGBaseFunctions.h>
25 #include <OSGTransform.h>
26 #include <OSGGroup.h>
28 // new headers:
29 #include <OSGGLEXT.h>
30 #include <OSGShaderProgramChunk.h>
31 #include <OSGShaderProgram.h>
32 #include <OSGShaderVariableOSG.h>
33 #include <OSGChunkMaterial.h>
34 #include <OSGMaterialGroup.h>
35 #include <OSGMaterialChunkOverrideGroup.h>
36 #include <OSGShaderStorageBufferObjChunk.h>
37 #include <OSGPolygonChunk.h>
38 #include <OSGDepthChunk.h>
39 #include <OSGShaderProgramVariableChunk.h>
40 #include <OSGAlgorithmComputeElement.h>
41 #include <OSGComputeShaderAlgorithm.h>
42 #include <OSGComputeShaderChunk.h>
43 #include <OSGShaderProgram.h>
44 #include <OSGShaderProgramVariables.h>
46 #else
47 // Headers
48 #include <OpenSG/OSGGLUT.h>
49 #include <OpenSG/OSGConfig.h>
50 #include <OpenSG/OSGSimpleGeometry.h>
51 #include <OpenSG/OSGGLUTWindow.h>
52 #include <OpenSG/OSGSimpleSceneManager.h>
53 #include <OpenSG/OSGBaseFunctions.h>
54 #include <OpenSG/OSGTransform.h>
55 #include <OpenSG/OSGGroup.h>
57 // new headers:
58 #include <OpenSG/OSGGLEXT.h>
59 #include <OpenSG/OSGShaderProgramChunk.h>
60 #include <OpenSG/OSGShaderProgram.h>
61 #include <OpenSG/OSGShaderVariableOSG.h>
62 #include <OpenSG/OSGChunkMaterial.h>
63 #include <OpenSG/OSGMaterialGroup.h>
64 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
65 #include <OpenSG/OSGShaderStorageBufferObjChunk.h>
66 #include <OpenSG/OSGPolygonChunk.h>
67 #include <OpenSG/OSGDepthChunk.h>
68 #include <OpenSG/OSGShaderProgramVariableChunk.h>
69 #include <OpenSG/OSGAlgorithmComputeElement.h>
70 #include <OpenSG/OSGComputeShaderAlgorithm.h>
71 #include <OpenSG/OSGComputeShaderChunk.h>
72 #include <OpenSG/OSGShaderProgram.h>
73 #include <OpenSG/OSGShaderProgramVariables.h>
74 #endif
76 const OSG::Vec3i work_group_count(32,32,1);
77 const OSG::Vec3i work_group_size(16,16,1);
79 const OSG::UInt32 num_materials = (work_group_size.z()-1) * work_group_size.y() * work_group_size.x()
80 + (work_group_size.y()-1) * work_group_size.x()
81 + (work_group_size.x()-1)
82 + 1;
84 // The SimpleSceneManager to manage simple applications
86 OSG::SimpleSceneManagerRefPtr mgr;
89 // simple light data structure
91 struct Light
93 enum Type
95 directional_light = 0,
96 point_light,
97 spot_light,
98 no_light
101 Light()
102 : position(0.f, 0.f, 0.f)
103 , spot_direction(0.f, 1.f, 0.f)
104 , Ia(1.f, 1.f, 1.f)
105 , Id(1.f, 1.f, 1.f)
106 , Is(1.f, 1.f, 1.f)
107 , attenuation(1.f, 0.f, 0.f)
108 , spot_cos_cutoff(cosf(45.f))
109 , spot_exponent(1.f)
110 , type(no_light)
113 static Light create_light(Type e)
115 Light l;
116 l.type = e;
118 switch (e) {
119 case directional_light: l.spot_direction = OSG::Vec3f(1.f, 0.f, 0.f);
120 break;
121 case point_light: l.position = OSG::Pnt3f(0.f, 0.2f, 0.f);
122 break;
123 case spot_light: l.position = OSG::Pnt3f(0.f, 0.2f, 0.f); l.spot_direction = OSG::Pnt3f(0.f, 0.f, 0.f) - l.position;
124 break;
125 default:
126 break;
128 return l;
131 OSG::Pnt3f position; // in object space
132 OSG::Vec3f spot_direction; // in object space, also used for dir of directional lights (see shader code)
133 OSG::Color3f Ia; // ambient max. Intensity
134 OSG::Color3f Id; // diffuse max. Intensity
135 OSG::Color3f Is; // specular max. Intensity
137 OSG::Vec3f attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0
138 OSG::Real32 spot_cos_cutoff; // cosine cut of angle
139 OSG::Real32 spot_exponent; // [0-128]
140 OSG::Int32 type; // directional_light, point_light, spot_light, no_light
143 typedef std::vector<Light> VecLightsT; // multiple lights
145 const std::size_t num_lights = 1; // simple example with just one light
147 VecLightsT initialize_lights() // helper to create lights
149 VecLightsT lights;
151 lights.push_back(Light::create_light(Light::point_light));
153 assert(lights.size() == num_lights);
155 return lights;
158 VecLightsT lights = initialize_lights(); // the lights
162 // Simple material data structure
164 struct Material
166 Material()
167 : ambient (0.f, 0.f, 0.f)
168 , diffuse (1.f, 1.f, 1.f)
169 , specular(0.f, 0.f, 0.f)
170 , emissive(0.f, 0.f, 0.f)
171 , opacity(1.f)
172 , shininess(100.f)
175 OSG::Color3f ambient;
176 OSG::Color3f diffuse;
177 OSG::Color3f specular;
178 OSG::Color3f emissive;
180 OSG::Real32 opacity;
181 OSG::Real32 shininess;
184 typedef std::vector<Material> VecMaterialsT; // multiple materials
186 VecMaterialsT initialize_materials(std::size_t num) // helper to create materials
188 VecMaterialsT materials;
189 materials.resize(num);
191 return materials;
194 VecMaterialsT materials = initialize_materials(num_materials); // the material database
198 // Simple geometry state data structure
200 struct GeomState
202 GeomState()
203 : material_index(0)
206 OSG::UInt32 material_index;
210 // transform point from world space to eye space
212 OSG::Pnt3f transform_to_eye_space(const OSG::Pnt3f& p)
214 if (!mgr || !mgr->getWindow() || mgr->getWindow()->getMFPort()->size() == 0)
215 return p;
217 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
219 OSG::Pnt3f p_es;
221 OSG::Matrix view;
222 OSG::Int16 width = pPort->calcPixelWidth();
223 OSG::Int16 height = pPort->calcPixelHeight();
225 pPort->getCamera()->getViewing(view, width, height);
227 view.multFull( p, p_es);
229 return p_es;
233 // transform vector from world space to eye space
235 OSG::Vec3f transform_to_eye_space(const OSG::Vec3f& v)
237 if (!mgr || !mgr->getWindow() || mgr->getWindow()->getMFPort()->size() == 0)
238 return v;
240 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
242 OSG::Vec3f v_es;
244 OSG::Matrix view;
245 OSG::Int16 width = pPort->calcPixelWidth();
246 OSG::Int16 height = pPort->calcPixelHeight();
248 pPort->getCamera()->getViewing(view, width, height);
250 view.multFull( v, v_es);
252 return v_es;
256 // The light state
258 void update_light_state(OSG::ShaderStorageBufferObjChunk* ssbo, const VecLightsT& vLights)
260 if (ssbo) {
261 for (std::size_t i = 0; i < vLights.size(); ++i) {
262 std::stringstream stream;
263 stream << "Lights.light[" << i << "]." << std::flush;
264 std::string name;
266 OSG::Pnt3f position_es = transform_to_eye_space(vLights[i].position);
267 OSG::Vec3f spot_direction_es = transform_to_eye_space(vLights[i].spot_direction);
269 name = stream.str() + "position"; ssbo->setVec3 (name, position_es);
270 name = stream.str() + "spot_direction"; ssbo->setVec3 (name, spot_direction_es);
271 name = stream.str() + "Ia"; ssbo->setVec3 (name, vLights[i].Ia);
272 name = stream.str() + "Id"; ssbo->setVec3 (name, vLights[i].Id);
273 name = stream.str() + "Is"; ssbo->setVec3 (name, vLights[i].Is);
274 name = stream.str() + "attenuation"; ssbo->setVec3 (name, vLights[i].attenuation);
275 name = stream.str() + "spot_cos_cutoff"; ssbo->setFloat(name, vLights[i].spot_cos_cutoff);
276 name = stream.str() + "spot_exponent"; ssbo->setFloat(name, vLights[i].spot_exponent);
277 name = stream.str() + "type"; ssbo->setInt (name, vLights[i].type);
282 OSG::ShaderStorageBufferObjChunkTransitPtr create_light_state(const VecLightsT& vLights)
284 OSG::ShaderStorageBufferObjChunkRefPtr ssbo = OSG::ShaderStorageBufferObjChunk::create();
286 ssbo->setBlockName("Lights");
287 ssbo->setUsage(GL_STREAM_DRAW);
289 for (std::size_t i = 0; i < vLights.size(); ++i) {
290 std::stringstream stream;
291 stream << "Lights.light[" << i << "]." << std::flush;
292 std::string name;
294 name = stream.str() + "position"; ssbo->addVec3 (name);
295 name = stream.str() + "spot_direction"; ssbo->addVec3 (name);
296 name = stream.str() + "Ia"; ssbo->addVec3 (name);
297 name = stream.str() + "Id"; ssbo->addVec3 (name);
298 name = stream.str() + "Is"; ssbo->addVec3 (name);
299 name = stream.str() + "attenuation"; ssbo->addVec3 (name);
300 name = stream.str() + "spot_cos_cutoff"; ssbo->addFloat(name);
301 name = stream.str() + "spot_exponent"; ssbo->addFloat(name);
302 name = stream.str() + "type"; ssbo->addInt (name);
305 update_light_state(ssbo, vLights);
307 return OSG::ShaderStorageBufferObjChunkTransitPtr(ssbo);
311 // The material state
313 void update_material_database_state(OSG::ShaderStorageBufferObjChunk* ssbo, const VecMaterialsT& vMaterials)
315 if (ssbo) {
316 for (std::size_t i = 0; i < vMaterials.size(); ++i) {
317 std::stringstream stream;
318 stream << "Materials.material[" << i << "]." << std::flush;
319 std::string name;
321 name = stream.str() + "ambient"; ssbo->setVec3 (name, vMaterials[i].ambient);
322 name = stream.str() + "diffuse"; ssbo->setVec3 (name, vMaterials[i].diffuse);
323 name = stream.str() + "specular"; ssbo->setVec3 (name, vMaterials[i].specular);
324 name = stream.str() + "emissive"; ssbo->setVec3 (name, vMaterials[i].emissive);
325 name = stream.str() + "opacity"; ssbo->setFloat(name, vMaterials[i].opacity);
326 name = stream.str() + "shininess"; ssbo->setFloat(name, vMaterials[i].shininess);
331 OSG::ShaderStorageBufferObjChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
333 OSG::ShaderStorageBufferObjChunkRefPtr ssbo = OSG::ShaderStorageBufferObjChunk::create();
335 ssbo->setBlockName("Materials");
336 ssbo->setUsage(GL_STATIC_DRAW);
338 for (std::size_t i = 0; i < vMaterials.size(); ++i) {
339 std::stringstream stream;
340 stream << "Materials.material[" << i << "]." << std::flush;
341 std::string name;
343 name = stream.str() + "ambient"; ssbo->addVec3 (name);
344 name = stream.str() + "diffuse"; ssbo->addVec3 (name);
345 name = stream.str() + "specular"; ssbo->addVec3 (name);
346 name = stream.str() + "emissive"; ssbo->addVec3 (name);
347 name = stream.str() + "opacity"; ssbo->addFloat(name);
348 name = stream.str() + "shininess"; ssbo->addFloat(name);
351 update_material_database_state(ssbo, vMaterials);
353 return OSG::ShaderStorageBufferObjChunkTransitPtr(ssbo);
357 // The geometry material state
359 void update_geometry_material_state(OSG::ShaderStorageBufferObjChunk* ssbo, const GeomState& geom_state)
361 if (ssbo)
363 ssbo->setInt("GeomState.material_index", geom_state.material_index);
367 OSG::ShaderStorageBufferObjChunkTransitPtr create_geometry_material_state(const GeomState& geom_state)
369 OSG::ShaderStorageBufferObjChunkRefPtr ssbo = OSG::ShaderStorageBufferObjChunk::create();
371 ssbo->setBlockName("GeomState");
372 ssbo->setUsage(GL_DYNAMIC_DRAW);
374 ssbo->addInt("GeomState.material_index");
376 update_geometry_material_state(ssbo, geom_state);
378 return OSG::ShaderStorageBufferObjChunkTransitPtr(ssbo);
382 // compute, vertex and fragment shader program.
384 std::string get_cp_program();
385 std::string get_vp_program();
386 std::string get_fp_program();
388 const OSG::UInt32 data_binding_point = 1;
389 const OSG::UInt32 light_binding_point = 2;
390 const OSG::UInt32 geom_binding_point = 3;
393 // random number generator
395 boost::random::mt19937 generator;
396 boost::random::uniform_int_distribution<> dist(0, num_materials-1);
399 // a separate transformation for every object
401 OSG::TransformRefPtr cyltrans, tortrans;
404 // Shader storage buffer objects corresponding to transient shader blocks
406 OSG::ShaderStorageBufferObjChunkRefPtr ssbo_material_database = NULL;
407 OSG::ShaderStorageBufferObjChunkRefPtr ssbo_light_state = NULL;
408 OSG::ShaderStorageBufferObjChunkRefPtr ssbo_geom_state_1 = NULL;
409 OSG::ShaderStorageBufferObjChunkRefPtr ssbo_geom_state_2 = NULL;
412 // The computation core that is responsible for generating matrial database content
414 OSG::AlgorithmComputeElementTransitPtr createComputation()
416 OSG::ChunkMaterialRefPtr data_state = OSG::ChunkMaterial::create();
417 data_state->addChunk(ssbo_material_database, data_binding_point);
419 OSG::ShaderProgramRefPtr compShader = OSG::ShaderProgram::create();
420 compShader->setShaderType(GL_COMPUTE_SHADER);
421 compShader->setProgram(get_cp_program());
422 compShader->addShaderStorageBlock("Materials", data_binding_point); // block binding point
424 OSG::ComputeShaderChunkRefPtr compShaderChunk = OSG::ComputeShaderChunk::create();
425 compShaderChunk->addComputeShader(compShader);
426 compShaderChunk->setVariables(compShader->getVariables());
428 OSG::ComputeShaderAlgorithmRefPtr compShaderAlgo = OSG::ComputeShaderAlgorithm::create();
429 compShaderAlgo->setUseMemoryBarrier(true);
430 compShaderAlgo->setMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
431 compShaderAlgo->setComputeShader(compShaderChunk);
432 compShaderAlgo->setDispatchConfig(work_group_count);
433 compShaderAlgo->setChunkMaterial(data_state);
435 OSG::AlgorithmComputeElementRefPtr algoCompElement = OSG::AlgorithmComputeElement::create();
436 algoCompElement->setAlgorithm(compShaderAlgo);
438 return OSG::AlgorithmComputeElementTransitPtr(algoCompElement);
442 // The scene to be rendered
444 OSG::NodeTransitPtr createScene()
446 OSG::NodeRefPtr scene = OSG::Node::create();
448 // The cylinder and its transformation
449 OSG::NodeRefPtr cyl = OSG::Node::create();
450 OSG::GeometryRefPtr cylgeo = OSG::makeCylinderGeo( 1.4f, .3f, 24,
451 true, true, true );
453 cyl->setCore(cylgeo);
455 cyltrans = OSG::Transform::create();
457 OSG::NodeRefPtr cyltransnode = OSG::Node::create();
458 cyltransnode->setCore (cyltrans);
459 cyltransnode->addChild(cyl );
461 // add it to the scene
462 scene->addChild(cyltransnode);
464 // The torus and its transformation
465 OSG::NodeRefPtr torus = OSG::Node::create();
466 OSG::GeometryRefPtr torusgeo = OSG::makeTorusGeo( .2f, 1, 24, 36 );
468 torus->setCore(torusgeo);
470 tortrans = OSG::Transform::create();
472 OSG::NodeRefPtr tortransnode = OSG::Node::create();
473 tortransnode->setCore (tortrans);
474 tortransnode->addChild(torus );
476 // add it to the scene
477 scene->addChild(tortransnode);
480 // create the shader program
482 OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
483 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
484 OSG::ShaderProgramRefPtr fragShader = OSG::ShaderProgram::createFragmentShader();
486 vertShader->setProgram(get_vp_program());
487 fragShader->setProgram(get_fp_program());
490 // binding the unifrom block to a buffer binding point can be performed
491 // either by calling the shaders's addShaderStorageBlock method or by
492 // adding a 'shader storage block' variable to a ShaderProgramVariableChunk.
493 // In the following we use both variants for illustration.
495 fragShader->addShaderStorageBlock("Materials", data_binding_point); // block binding point
496 fragShader->addShaderStorageBlock("Lights", light_binding_point); // block binding point
499 // The following is replaced by adding ShaderProgramVariableChunk objects
500 // to the chunk material. See below...
502 // fragShader->addShaderStorageBlock("GeomState", 3); // block binding point
504 prog_chunk->addShader(vertShader);
505 prog_chunk->addShader(fragShader);
508 // create shader storage buffer object for the light state
510 ssbo_light_state = create_light_state(lights);
512 OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
513 polygon_chunk->setFrontMode(GL_FILL);
514 polygon_chunk->setBackMode(GL_FILL);
515 polygon_chunk->setCullFace(GL_NONE);
517 OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
518 depth_chunk->setEnable(true);
520 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
521 prog_state->addChunk(ssbo_material_database, data_binding_point); // buffer binding point 1
522 prog_state->addChunk(ssbo_light_state, light_binding_point); // buffer binding point 2
523 prog_state->addChunk(prog_chunk);
524 prog_state->addChunk(polygon_chunk);
525 prog_state->addChunk(depth_chunk);
527 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
528 shader_var_chunk->addShaderStorageBlock("GeomState", geom_binding_point);
530 GeomState geom1; geom1.material_index = dist(generator);
531 OSG::ChunkMaterialRefPtr geom1_state = OSG::ChunkMaterial::create();
532 ssbo_geom_state_1 = create_geometry_material_state(geom1);
533 geom1_state->addChunk(ssbo_geom_state_1, geom_binding_point); // buffer binding point 3
534 geom1_state->addChunk(shader_var_chunk); // block binding point
536 GeomState geom2; geom2.material_index = dist(generator);
537 OSG::ChunkMaterialRefPtr geom2_state = OSG::ChunkMaterial::create();
538 ssbo_geom_state_2 = create_geometry_material_state(geom2);
539 geom2_state->addChunk(ssbo_geom_state_2, geom_binding_point); // buffer binding point 3
540 geom2_state->addChunk(shader_var_chunk); // block binding point
542 cylgeo ->setMaterial(geom1_state);
543 torusgeo->setMaterial(geom2_state);
545 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
546 mgrp->setMaterial(prog_state);
547 scene->setCore(mgrp);
549 return OSG::NodeTransitPtr(scene);
553 // forward declaration so we can have the interesting stuff upfront
555 int setupGLUT(int *argc, char *argv[]);
556 void releaseGLUT();
557 void print_help();
560 // Initialize GLUT & OpenSG and set up the scene
562 int main(int argc, char **argv)
564 // OSG init
565 OSG::osgInit(argc,argv);
567 // GLUT init
568 int winid = setupGLUT(&argc, argv);
570 print_help();
572 // open a new scope, because the pointers below should go out of scope
573 // before entering glutMainLoop.
574 // Otherwise OpenSG will complain about objects being alive after shutdown.
576 // the connection between GLUT and OpenSG
577 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
578 gwin->setGlutId(winid);
579 gwin->init();
581 // create the SimpleSceneManager helper
582 mgr = OSG::SimpleSceneManager::create();
583 mgr->setWindow(gwin);
586 // create shader storage buffer object for the material database
588 ssbo_material_database = create_material_database_state(materials);
590 OSG::NodeRefPtr root = OSG::makeNodeFor(createComputation()); // OSG::Group::create());
592 root->addChild(createScene());
594 mgr->setRoot(root);
596 OSG::commitChanges();
598 // show the whole scene
599 mgr->showAll();
602 // GLUT main loop
603 glutMainLoop();
605 return 0;
609 // GLUT callback functions
613 // redraw the window
615 void display(void)
617 // light spot direction and light position must be provided in eye space
618 update_light_state(ssbo_light_state, lights);
620 // create the matrix
621 OSG::Matrix m;
622 OSG::Real32 t = glutGet(GLUT_ELAPSED_TIME );
624 // set the transforms' matrices
625 m.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t / 1000.f) * 1.5),
626 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t / 500.f));
628 cyltrans->setMatrix(m);
630 m.setTransform(OSG::Vec3f(OSG::osgSin(t / 1000.f), 0, 0),
631 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t / 1000.f));
633 tortrans->setMatrix(m);
635 OSG::commitChanges();
637 mgr->redraw();
642 // react to size changes
644 void reshape(int w, int h)
646 mgr->resize(w, h);
647 glutPostRedisplay();
651 // react to mouse button presses
653 void mouse(int button, int state, int x, int y)
655 if (state)
656 mgr->mouseButtonRelease(button, x, y);
657 else
658 mgr->mouseButtonPress(button, x, y);
660 glutPostRedisplay();
664 // react to mouse motions with pressed buttons
666 void motion(int x, int y)
668 mgr->mouseMove(x, y);
669 glutPostRedisplay();
673 // react to keys
675 void keyboard(unsigned char k, int x, int y)
677 switch(k)
679 case 27:
681 // clean up global variables
682 cyltrans = NULL;
683 tortrans = NULL;
684 mgr = NULL;
686 ssbo_material_database = NULL;
687 ssbo_light_state = NULL;
688 ssbo_geom_state_1 = NULL;
689 ssbo_geom_state_2 = NULL;
691 releaseGLUT();
693 OSG::osgExit();
694 exit(0);
696 break;
698 case 'm':
700 GeomState geom1; geom1.material_index = dist(generator);
701 GeomState geom2; geom2.material_index = dist(generator);
703 update_geometry_material_state(ssbo_geom_state_1, geom1);
704 update_geometry_material_state(ssbo_geom_state_2, geom2);
706 glutPostRedisplay();
708 break;
710 case 's':
712 mgr->setStatistics(!mgr->getStatistics());
714 break;
719 // setup the GLUT library which handles the windows for us
721 int setupGLUT(int *argc, char *argv[])
723 glutInit(argc, argv);
724 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
726 int winid = glutCreateWindow("OpenSG");
728 glutReshapeFunc(reshape);
729 glutDisplayFunc(display);
730 glutMouseFunc(mouse);
731 glutMotionFunc(motion);
732 glutKeyboardFunc(keyboard);
734 // call the redraw function whenever there's nothing else to do
735 glutIdleFunc(display);
737 return winid;
740 void releaseGLUT()
742 glutReshapeFunc(NULL);
743 glutDisplayFunc(NULL);
744 glutMouseFunc(NULL);
745 glutMotionFunc(NULL);
746 glutKeyboardFunc(NULL);
747 glutIdleFunc(NULL);
750 void print_help()
752 std::cout << "Esc : quit example" << std::endl;
753 std::cout << "m : change object colors" << std::endl;
757 // compute shader program.
759 std::string get_cp_program()
761 using namespace std;
763 stringstream ost;
765 ost << "#version 430 compatibility"
766 << endl << ""
767 << endl << "const int num_materials = " << num_materials << ";"
768 << endl << ""
769 << endl << "layout (local_size_x = " << work_group_size.x()
770 << ", local_size_y = " << work_group_size.y()
771 << ", local_size_z = " << work_group_size.z() << ") in;"
772 << endl << ""
773 << endl << "struct Material"
774 << endl << "{"
775 << endl << " vec3 ambient;"
776 << endl << " vec3 diffuse;"
777 << endl << " vec3 specular;"
778 << endl << " vec3 emissive;"
779 << endl << ""
780 << endl << " float opacity;"
781 << endl << " float shininess;"
782 << endl << "};"
783 << endl << ""
784 << endl << "layout (std430) buffer Materials"
785 << endl << "{"
786 << endl << " Material material[" << num_materials << "];"
787 << endl << "} materials;"
788 << endl << ""
789 << endl << "uint hash( uint x ) {"
790 << endl << " x += ( x << 10u );"
791 << endl << " x ^= ( x >> 6u );"
792 << endl << " x += ( x << 3u );"
793 << endl << " x ^= ( x >> 11u );"
794 << endl << " x += ( x << 15u );"
795 << endl << " return x;"
796 << endl << "}"
797 << endl << ""
798 << endl << "float random( float f ) {"
799 << endl << " const uint mantissaMask = 0x007FFFFFu;"
800 << endl << " const uint one = 0x3F800000u;"
801 << endl << ""
802 << endl << " uint h = hash( floatBitsToUint( f ) );"
803 << endl << " h &= mantissaMask;"
804 << endl << " h |= one;"
805 << endl << ""
806 << endl << " float r2 = uintBitsToFloat( h );"
807 << endl << " return r2 - 1.0;"
808 << endl << "}"
809 << endl << ""
810 << endl << "void main()"
811 << endl << "{"
812 << endl << " vec3 color;"
813 << endl << ""
814 << endl << " if (gl_LocalInvocationIndex >= " << num_materials << ")"
815 << endl << " color = vec3(1.0, 0.0, 0.0);"
816 << endl << " else"
817 << endl << " {"
818 << endl << " float value = length( vec2( ivec2(gl_LocalInvocationID.xy) - 8 ) / 8.0 );"
819 << endl << " float r = random(value);"
820 << endl << " float g = random(2*value);"
821 << endl << " float b = random(7*value);"
822 << endl << " color = vec3(r, g, b);"
823 << endl << " }"
824 << endl << ""
825 << endl << " materials.material[gl_LocalInvocationIndex].diffuse = color;"
826 << endl << "}"
827 << endl << ""
828 << endl;
830 return ost.str();
834 // vertex shader program.
836 std::string get_vp_program()
838 using namespace std;
840 stringstream ost;
842 ost << "#version 330 compatibility"
843 << endl << ""
844 << endl << "#extension GL_ARB_separate_shader_objects: enable"
845 << endl << "#extension GL_ARB_shader_storage_buffer_object: enable"
846 << endl << ""
847 << endl << "smooth out vec3 vNormalES; // eye space normal"
848 << endl << "smooth out vec3 vPositionES; // eye space position"
849 << endl << ""
850 << endl << "void main()"
851 << endl << "{"
852 << endl << " //"
853 << endl << " // multiply the object space vertex position with the modelview matrix "
854 << endl << " // to get the eye space vertex position"
855 << endl << " //"
856 << endl << " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;"
857 << endl << ""
858 << endl << " //"
859 << endl << " // multiply the object space normal with the normal matrix (transpose of the inverse "
860 << endl << " // model view matrix) to get the eye space normal"
861 << endl << " //"
862 << endl << " vNormalES = gl_NormalMatrix * gl_Normal;"
863 << endl << ""
864 << endl << " //"
865 << endl << " // multiply the combiend modelview projection matrix with the object space vertex"
866 << endl << " // position to get the clip space position"
867 << endl << " //"
868 << endl << " gl_Position = ftransform();"
869 << endl << "}"
870 << endl << ""
871 << endl;
873 return ost.str();
877 // fragment shader program for bump mapping in surface local coordinates
879 std::string get_fp_program()
881 using namespace std;
883 stringstream ost;
885 ost << "#version 330 compatibility"
886 << endl << ""
887 << endl << "#extension GL_ARB_separate_shader_objects: enable"
888 << endl << "#extension GL_ARB_shader_storage_buffer_object: enable"
889 << endl << ""
890 << endl << "smooth in vec3 vNormalES; // eye space normal"
891 << endl << "smooth in vec3 vPositionES; // eye space position"
892 << endl << ""
893 << endl << "const int num_lights = " << num_lights << ";"
894 << endl << "const int num_materials = " << num_materials << ";"
895 << endl << ""
896 << endl << "const int directional_light = 0;"
897 << endl << "const int point_light = 1;"
898 << endl << "const int spot_light = 2;"
899 << endl << "const int no_light = 3;"
900 << endl << ""
901 << endl << "struct Light"
902 << endl << "{"
903 << endl << " vec3 position; // in eye space"
904 << endl << " vec3 spot_direction; // in eye space"
905 << endl << ""
906 << endl << " vec3 Ia; // ambient max. Intensity"
907 << endl << " vec3 Id; // diffuse max. Intensity"
908 << endl << " vec3 Is; // specular max. Intensity"
909 << endl << ""
910 << endl << " vec3 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0"
911 << endl << " "
912 << endl << " float spot_cos_cutoff; // cosine cut of angle"
913 << endl << ""
914 << endl << " float spot_exponent; // [0-128]"
915 << endl << " int type; // directional_light, point_light, spot_light, no_light"
916 << endl << "};"
917 << endl << ""
918 << endl << "layout (std430) buffer Lights"
919 << endl << "{"
920 << endl << " Light light[num_lights];"
921 << endl << "} lights;"
922 << endl << ""
923 << endl << "struct Material"
924 << endl << "{"
925 << endl << " vec3 ambient;"
926 << endl << " vec3 diffuse;"
927 << endl << " vec3 specular;"
928 << endl << " vec3 emissive;"
929 << endl << ""
930 << endl << " float opacity;"
931 << endl << " float shininess;"
932 << endl << "};"
933 << endl << ""
934 << endl << "layout (std430) buffer Materials"
935 << endl << "{"
936 << endl << " Material material[num_materials];"
937 << endl << "} materials;"
938 << endl << ""
939 << endl << ""
940 << endl << "layout (std430) buffer GeomState"
941 << endl << "{"
942 << endl << " int material_index;"
943 << endl << "} geom_state;"
944 << endl << ""
945 << endl << "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!"
946 << endl << ""
947 << endl << "layout(location = 0) out vec4 vFragColor;"
948 << endl << ""
949 << endl << "//"
950 << endl << "// directional light contribution"
951 << endl << "//"
952 << endl << "vec3 directionalLight("
953 << endl << " in int i, // light identifier, i.e. current light"
954 << endl << " in int j, // material identifier"
955 << endl << " in vec3 n, // vertex normal in eye space"
956 << endl << " in vec3 v) // view direction in eye space"
957 << endl << "{"
958 << endl << " if (lights.light[i].type != directional_light)"
959 << endl << " return vec3(0.0, 0.0, 0.0);"
960 << endl << ""
961 << endl << " //"
962 << endl << " // the light direction in eye space"
963 << endl << " //"
964 << endl << " vec3 l = -lights.light[i].spot_direction; // we carry the directional light direction in the spot_direction slot"
965 << endl << ""
966 << endl << " //"
967 << endl << " // the half vector"
968 << endl << " //"
969 << endl << " vec3 h = normalize(l + v);"
970 << endl << ""
971 << endl << " float n_dot_l = max(0.0, dot(n, l));"
972 << endl << " float n_dot_h = max(0.0, dot(n, h));"
973 << endl << ""
974 << endl << " float m = materials.material[j].shininess;"
975 << endl << ""
976 << endl << " float pf; // power factor"
977 << endl << ""
978 << endl << " if (n_dot_l == 0.0)"
979 << endl << " pf = 0.0;"
980 << endl << " else"
981 << endl << " pf = pow(n_dot_h, m);"
982 << endl << ""
983 << endl << " return materials.material[j].emissive "
984 << endl << " + lights.light[i].Ia * materials.material[j].ambient "
985 << endl << " + lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI"
986 << endl << " + lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)"
987 << endl << "}"
988 << endl << ""
989 << endl << "//"
990 << endl << "// point light contribution"
991 << endl << "//"
992 << endl << "vec3 pointLight("
993 << endl << " in int i, // light identifier, i.e. current light"
994 << endl << " in int j, // material identifier"
995 << endl << " in vec3 n, // vertex normal in eye space"
996 << endl << " in vec3 v, // view direction in eye space"
997 << endl << " in vec3 p) // vertex position in eye space"
998 << endl << "{"
999 << endl << " if (lights.light[i].type != point_light)"
1000 << endl << " return vec3(0.0, 0.0, 0.0);"
1001 << endl << ""
1002 << endl << " vec3 l = vec3(lights.light[i].position) - p; // direction from surface to light position"
1003 << endl << " float d = length(l); // distance from surface to light source"
1004 << endl << " l = normalize(l); // normalized direction from surface to light position"
1005 << endl << ""
1006 << endl << " //"
1007 << endl << " // the half vector"
1008 << endl << " //"
1009 << endl << " vec3 h = normalize(l + v);"
1010 << endl << ""
1011 << endl << " float n_dot_l = max(0.0, dot(n, l));"
1012 << endl << " float n_dot_h = max(0.0, dot(n, h));"
1013 << endl << ""
1014 << endl << " float m = materials.material[j].shininess;"
1015 << endl << ""
1016 << endl << " float pf; // power factor"
1017 << endl << ""
1018 << endl << " if (n_dot_l == 0.0)"
1019 << endl << " pf = 0.0;"
1020 << endl << " else"
1021 << endl << " pf = pow(n_dot_h, m);"
1022 << endl << ""
1023 << endl << " //"
1024 << endl << " // Compute attenuation"
1025 << endl << " //"
1026 << endl << " float attenuation = 1.0 / (lights.light[i].attenuation.x + "
1027 << endl << " (lights.light[i].attenuation.y * d) + "
1028 << endl << " (lights.light[i].attenuation.z * d * d));"
1029 << endl << ""
1030 << endl << " attenuation = clamp(attenuation, 0.0, 1.0);"
1031 << endl << ""
1032 << endl << " return materials.material[j].emissive "
1033 << endl << " + attenuation * lights.light[i].Ia * materials.material[j].ambient "
1034 << endl << " + attenuation * lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI"
1035 << endl << " + attenuation * lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)"
1036 << endl << "}"
1037 << endl << ""
1038 << endl << "//"
1039 << endl << "// spot light contribution"
1040 << endl << "//"
1041 << endl << "vec3 spotLight("
1042 << endl << " in int i, // light identifier, i.e. current light"
1043 << endl << " in int j, // material identifier"
1044 << endl << " in vec3 n, // vertex normal in eye space"
1045 << endl << " in vec3 v, // view direction in eye space"
1046 << endl << " in vec3 p) // vertex position in eye space"
1047 << endl << "{"
1048 << endl << " if (lights.light[i].type != spot_light)"
1049 << endl << " return vec3(0.0, 0.0, 0.0);"
1050 << endl << ""
1051 << endl << " vec3 l = vec3(lights.light[i].position) - p; // direction from surface to light position"
1052 << endl << " float d = length(l); // distance from surface to light source"
1053 << endl << " l = normalize(l); // normalized direction from surface to light position"
1054 << endl << " "
1055 << endl << " vec3 s = lights.light[i].spot_direction; // spot direction"
1056 << endl << ""
1057 << endl << " //"
1058 << endl << " // the half vector"
1059 << endl << " //"
1060 << endl << " vec3 h = normalize(l + v);"
1061 << endl << ""
1062 << endl << " float n_dot_l = max(0.0, dot(n, l));"
1063 << endl << " float n_dot_h = max(0.0, dot(n, h));"
1064 << endl << " float l_dot_s = dot(-l, s);"
1065 << endl << ""
1066 << endl << " float m = materials.material[j].shininess;"
1067 << endl << ""
1068 << endl << " float pf; // power factor"
1069 << endl << ""
1070 << endl << " if (n_dot_l == 0.0)"
1071 << endl << " pf = 0.0;"
1072 << endl << " else"
1073 << endl << " pf = pow(n_dot_h, m);"
1074 << endl << ""
1075 << endl << " //"
1076 << endl << " // Compute attenuation"
1077 << endl << " //"
1078 << endl << " float attenuation = 1.0 / (lights.light[i].attenuation.x + "
1079 << endl << " (lights.light[i].attenuation.y * d) + "
1080 << endl << " (lights.light[i].attenuation.z * d * d));"
1081 << endl << ""
1082 << endl << " attenuation = clamp(attenuation, 0.0, 1.0);"
1083 << endl << ""
1084 << endl << " if (l_dot_s < lights.light[i].spot_cos_cutoff) "
1085 << endl << " attenuation = 0.0;"
1086 << endl << " else"
1087 << endl << " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);"
1088 << endl << ""
1089 << endl << " return materials.material[j].emissive "
1090 << endl << " + attenuation * lights.light[i].Ia * materials.material[j].ambient "
1091 << endl << " + attenuation * lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI"
1092 << endl << " + attenuation * lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)"
1093 << endl << "}"
1094 << endl << ""
1095 << endl << "void main()"
1096 << endl << "{"
1097 << endl << " //"
1098 << endl << " // normalize the eye space normal"
1099 << endl << " //"
1100 << endl << " vec3 N = normalize(vNormalES);"
1101 << endl << ""
1102 << endl << " //"
1103 << endl << " // get the view vector and normalize it"
1104 << endl << " //"
1105 << endl << " vec3 V = normalize(cCameraPositionES - vPositionES);"
1106 << endl << ""
1107 << endl << " //"
1108 << endl << " // Integrate over all lights: Any unused light does not contribute and each light"
1109 << endl << " // contribute either from the directional light, the point light or the spot light."
1110 << endl << " //"
1111 << endl << " vec3 color = vec3(0.0, 0.0, 0.0);"
1112 << endl << " for (int i = 0; i < num_lights; ++i) {"
1113 << endl << " color += directionalLight(i, geom_state.material_index, N, V) "
1114 << endl << " + pointLight(i, geom_state.material_index, N, V, vPositionES) "
1115 << endl << " + spotLight(i, geom_state.material_index, N, V, vPositionES);"
1116 << endl << " }"
1117 << endl << " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);"
1118 << endl << "}"
1119 << endl << ""
1120 << endl;
1122 return ost.str();