1 // OpenSG Tutorial Example: ComputeShader4
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.
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
14 #include <boost/random/mersenne_twister.hpp>
15 #include <boost/random/uniform_int_distribution.hpp>
17 #ifdef OSG_BUILD_ACTIVE
20 #include <OSGConfig.h>
21 #include <OSGSimpleGeometry.h>
22 #include <OSGGLUTWindow.h>
23 #include <OSGSimpleSceneManager.h>
24 #include <OSGBaseFunctions.h>
25 #include <OSGTransform.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>
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>
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>
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)
84 // The SimpleSceneManager to manage simple applications
86 OSG::SimpleSceneManagerRefPtr mgr
;
89 // simple light data structure
95 directional_light
= 0,
102 : position(0.f
, 0.f
, 0.f
)
103 , spot_direction(0.f
, 1.f
, 0.f
)
107 , attenuation(1.f
, 0.f
, 0.f
)
108 , spot_cos_cutoff(cosf(45.f
))
113 static Light
create_light(Type e
)
119 case directional_light
: l
.spot_direction
= OSG::Vec3f(1.f
, 0.f
, 0.f
);
121 case point_light
: l
.position
= OSG::Pnt3f(0.f
, 0.2f
, 0.f
);
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
;
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
151 lights
.push_back(Light::create_light(Light::point_light
));
153 assert(lights
.size() == num_lights
);
158 VecLightsT lights
= initialize_lights(); // the lights
162 // Simple material data structure
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
)
175 OSG::Color3f ambient
;
176 OSG::Color3f diffuse
;
177 OSG::Color3f specular
;
178 OSG::Color3f emissive
;
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
);
194 VecMaterialsT materials
= initialize_materials(num_materials
); // the material database
198 // Simple geometry state data structure
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)
217 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
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
);
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)
240 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
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
);
258 void update_light_state(OSG::ShaderStorageBufferObjChunk
* ssbo
, const VecLightsT
& vLights
)
261 for (std::size_t i
= 0; i
< vLights
.size(); ++i
) {
262 std::stringstream stream
;
263 stream
<< "Lights.light[" << i
<< "]." << std::flush
;
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
;
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
)
316 for (std::size_t i
= 0; i
< vMaterials
.size(); ++i
) {
317 std::stringstream stream
;
318 stream
<< "Materials.material[" << i
<< "]." << std::flush
;
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
;
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
)
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,
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
[]);
560 // Initialize GLUT & OpenSG and set up the scene
562 int main(int argc
, char **argv
)
565 OSG::osgInit(argc
,argv
);
568 int winid
= setupGLUT(&argc
, argv
);
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
);
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());
596 OSG::commitChanges();
598 // show the whole scene
609 // GLUT callback functions
617 // light spot direction and light position must be provided in eye space
618 update_light_state(ssbo_light_state
, lights
);
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();
642 // react to size changes
644 void reshape(int w
, int h
)
651 // react to mouse button presses
653 void mouse(int button
, int state
, int x
, int y
)
656 mgr
->mouseButtonRelease(button
, x
, y
);
658 mgr
->mouseButtonPress(button
, x
, y
);
664 // react to mouse motions with pressed buttons
666 void motion(int x
, int y
)
668 mgr
->mouseMove(x
, y
);
675 void keyboard(unsigned char k
, int x
, int y
)
681 // clean up global variables
686 ssbo_material_database
= NULL
;
687 ssbo_light_state
= NULL
;
688 ssbo_geom_state_1
= NULL
;
689 ssbo_geom_state_2
= NULL
;
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
);
712 mgr
->setStatistics(!mgr
->getStatistics());
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
);
742 glutReshapeFunc(NULL
);
743 glutDisplayFunc(NULL
);
745 glutMotionFunc(NULL
);
746 glutKeyboardFunc(NULL
);
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()
765 ost
<< "#version 430 compatibility"
767 << endl
<< "const int num_materials = " << num_materials
<< ";"
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;"
773 << endl
<< "struct Material"
775 << endl
<< " vec3 ambient;"
776 << endl
<< " vec3 diffuse;"
777 << endl
<< " vec3 specular;"
778 << endl
<< " vec3 emissive;"
780 << endl
<< " float opacity;"
781 << endl
<< " float shininess;"
784 << endl
<< "layout (std430) buffer Materials"
786 << endl
<< " Material material[" << num_materials
<< "];"
787 << endl
<< "} materials;"
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;"
798 << endl
<< "float random( float f ) {"
799 << endl
<< " const uint mantissaMask = 0x007FFFFFu;"
800 << endl
<< " const uint one = 0x3F800000u;"
802 << endl
<< " uint h = hash( floatBitsToUint( f ) );"
803 << endl
<< " h &= mantissaMask;"
804 << endl
<< " h |= one;"
806 << endl
<< " float r2 = uintBitsToFloat( h );"
807 << endl
<< " return r2 - 1.0;"
810 << endl
<< "void main()"
812 << endl
<< " vec3 color;"
814 << endl
<< " if (gl_LocalInvocationIndex >= " << num_materials
<< ")"
815 << endl
<< " color = vec3(1.0, 0.0, 0.0);"
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);"
825 << endl
<< " materials.material[gl_LocalInvocationIndex].diffuse = color;"
834 // vertex shader program.
836 std::string
get_vp_program()
842 ost
<< "#version 330 compatibility"
844 << endl
<< "#extension GL_ARB_separate_shader_objects: enable"
845 << endl
<< "#extension GL_ARB_shader_storage_buffer_object: enable"
847 << endl
<< "smooth out vec3 vNormalES; // eye space normal"
848 << endl
<< "smooth out vec3 vPositionES; // eye space position"
850 << endl
<< "void main()"
853 << endl
<< " // multiply the object space vertex position with the modelview matrix "
854 << endl
<< " // to get the eye space vertex position"
856 << endl
<< " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;"
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"
862 << endl
<< " vNormalES = gl_NormalMatrix * gl_Normal;"
865 << endl
<< " // multiply the combiend modelview projection matrix with the object space vertex"
866 << endl
<< " // position to get the clip space position"
868 << endl
<< " gl_Position = ftransform();"
877 // fragment shader program for bump mapping in surface local coordinates
879 std::string
get_fp_program()
885 ost
<< "#version 330 compatibility"
887 << endl
<< "#extension GL_ARB_separate_shader_objects: enable"
888 << endl
<< "#extension GL_ARB_shader_storage_buffer_object: enable"
890 << endl
<< "smooth in vec3 vNormalES; // eye space normal"
891 << endl
<< "smooth in vec3 vPositionES; // eye space position"
893 << endl
<< "const int num_lights = " << num_lights
<< ";"
894 << endl
<< "const int num_materials = " << num_materials
<< ";"
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;"
901 << endl
<< "struct Light"
903 << endl
<< " vec3 position; // in eye space"
904 << endl
<< " vec3 spot_direction; // in eye space"
906 << endl
<< " vec3 Ia; // ambient max. Intensity"
907 << endl
<< " vec3 Id; // diffuse max. Intensity"
908 << endl
<< " vec3 Is; // specular max. Intensity"
910 << endl
<< " vec3 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0"
912 << endl
<< " float spot_cos_cutoff; // cosine cut of angle"
914 << endl
<< " float spot_exponent; // [0-128]"
915 << endl
<< " int type; // directional_light, point_light, spot_light, no_light"
918 << endl
<< "layout (std430) buffer Lights"
920 << endl
<< " Light light[num_lights];"
921 << endl
<< "} lights;"
923 << endl
<< "struct Material"
925 << endl
<< " vec3 ambient;"
926 << endl
<< " vec3 diffuse;"
927 << endl
<< " vec3 specular;"
928 << endl
<< " vec3 emissive;"
930 << endl
<< " float opacity;"
931 << endl
<< " float shininess;"
934 << endl
<< "layout (std430) buffer Materials"
936 << endl
<< " Material material[num_materials];"
937 << endl
<< "} materials;"
940 << endl
<< "layout (std430) buffer GeomState"
942 << endl
<< " int material_index;"
943 << endl
<< "} geom_state;"
945 << endl
<< "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!"
947 << endl
<< "layout(location = 0) out vec4 vFragColor;"
950 << endl
<< "// directional light contribution"
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"
958 << endl
<< " if (lights.light[i].type != directional_light)"
959 << endl
<< " return vec3(0.0, 0.0, 0.0);"
962 << endl
<< " // the light direction in eye space"
964 << endl
<< " vec3 l = -lights.light[i].spot_direction; // we carry the directional light direction in the spot_direction slot"
967 << endl
<< " // the half vector"
969 << endl
<< " vec3 h = normalize(l + v);"
971 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
972 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
974 << endl
<< " float m = materials.material[j].shininess;"
976 << endl
<< " float pf; // power factor"
978 << endl
<< " if (n_dot_l == 0.0)"
979 << endl
<< " pf = 0.0;"
981 << endl
<< " pf = pow(n_dot_h, m);"
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)"
990 << endl
<< "// point light contribution"
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"
999 << endl
<< " if (lights.light[i].type != point_light)"
1000 << endl
<< " return vec3(0.0, 0.0, 0.0);"
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"
1007 << endl
<< " // the half vector"
1009 << endl
<< " vec3 h = normalize(l + v);"
1011 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
1012 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
1014 << endl
<< " float m = materials.material[j].shininess;"
1016 << endl
<< " float pf; // power factor"
1018 << endl
<< " if (n_dot_l == 0.0)"
1019 << endl
<< " pf = 0.0;"
1021 << endl
<< " pf = pow(n_dot_h, m);"
1024 << endl
<< " // Compute attenuation"
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));"
1030 << endl
<< " attenuation = clamp(attenuation, 0.0, 1.0);"
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)"
1039 << endl
<< "// spot light contribution"
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"
1048 << endl
<< " if (lights.light[i].type != spot_light)"
1049 << endl
<< " return vec3(0.0, 0.0, 0.0);"
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"
1055 << endl
<< " vec3 s = lights.light[i].spot_direction; // spot direction"
1058 << endl
<< " // the half vector"
1060 << endl
<< " vec3 h = normalize(l + v);"
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);"
1066 << endl
<< " float m = materials.material[j].shininess;"
1068 << endl
<< " float pf; // power factor"
1070 << endl
<< " if (n_dot_l == 0.0)"
1071 << endl
<< " pf = 0.0;"
1073 << endl
<< " pf = pow(n_dot_h, m);"
1076 << endl
<< " // Compute attenuation"
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));"
1082 << endl
<< " attenuation = clamp(attenuation, 0.0, 1.0);"
1084 << endl
<< " if (l_dot_s < lights.light[i].spot_cos_cutoff) "
1085 << endl
<< " attenuation = 0.0;"
1087 << endl
<< " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);"
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)"
1095 << endl
<< "void main()"
1098 << endl
<< " // normalize the eye space normal"
1100 << endl
<< " vec3 N = normalize(vNormalES);"
1103 << endl
<< " // get the view vector and normalize it"
1105 << endl
<< " vec3 V = normalize(cCameraPositionES - vPositionES);"
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."
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);"
1117 << endl
<< " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);"