Adjust examples for MultiLight changes
[opensg.git] / Examples / Simple / uniformbufferobject.cpp
blobee00a50abef2404079453c455a6ac2e697a29a00
1 // OpenSG Tutorial Example: UniformBufferObject
2 //
3 // This example shows how to create a shader uniform block and binding it
4 // to a uniform buffer object.
5 //
6 // The example does use the UniformBufferObjChunk which allows the host
7 // application to provide the uniform block member values directly to
8 // the chunk. The layout of the uniform block is determined by the
9 // shader code. Any of the layout values of the specification (shared,
10 // packed, std140) are allowed.
11 // It is however, important the the order and the cardinality of the
12 // members is matched exactly.
14 // Internally, the shader uniform block is queried for the offsets,
15 // array and matrix strides of the block variables.
18 #include <sstream>
19 #include <boost/random/mersenne_twister.hpp>
20 #include <boost/random/uniform_int_distribution.hpp>
22 #ifdef OSG_BUILD_ACTIVE
23 // Headers
24 #include <OSGGLUT.h>
25 #include <OSGConfig.h>
26 #include <OSGSimpleGeometry.h>
27 #include <OSGGLUTWindow.h>
28 #include <OSGSimpleSceneManager.h>
29 #include <OSGBaseFunctions.h>
30 #include <OSGTransform.h>
31 #include <OSGGroup.h>
33 // new headers:
34 #include <OSGGLEXT.h>
35 #include <OSGShaderProgramChunk.h>
36 #include <OSGShaderProgram.h>
37 #include <OSGShaderVariableOSG.h>
38 #include <OSGChunkMaterial.h>
39 #include <OSGMaterialGroup.h>
40 #include <OSGMaterialChunkOverrideGroup.h>
41 #include <OSGUniformBufferObjChunk.h>
42 #include <OSGPolygonChunk.h>
43 #include <OSGDepthChunk.h>
44 #include <OSGShaderProgramVariableChunk.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/OSGUniformBufferObjChunk.h>
66 #include <OpenSG/OSGPolygonChunk.h>
67 #include <OpenSG/OSGDepthChunk.h>
68 #include <OpenSG/OSGShaderProgramVariableChunk.h>
69 #endif
72 // USE_TEST_FP_SHADER
73 // ------------------
74 // Activate a test mode that does test the material and light at index 0,
75 // respectively, against specific values set by the application. If all
76 // values are read correctly in the shader the geometry is colored in green.
77 // Otherwise the geometry is colored red indicating failure.
79 //#define USE_TEST_FP_SHADER
82 // The SimpleSceneManager to manage simple applications
84 OSG::SimpleSceneManagerRefPtr mgr;
87 // simple light data structure
89 struct Light
91 enum Type
93 directional_light = 0,
94 point_light,
95 spot_light,
96 no_light
99 Light()
100 : position(0.f, 0.f, 0.f)
101 , spot_direction(0.f, 1.f, 0.f)
102 , Ia(1.f, 1.f, 1.f)
103 , Id(1.f, 1.f, 1.f)
104 , Is(1.f, 1.f, 1.f)
105 , attenuation(1.f, 0.f, 0.f)
106 , spot_cos_cutoff(cosf(45.f))
107 , spot_exponent(1.f)
108 , type(no_light)
111 static Light create_light(Type e)
113 Light l;
114 l.type = e;
116 switch (e) {
117 case directional_light: l.spot_direction = OSG::Vec3f(1.f, 0.f, 0.f);
118 break;
119 case point_light: l.position = OSG::Pnt3f(0.f, 0.2f, 0.f);
120 break;
121 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;
122 break;
123 default:
124 break;
126 return l;
129 OSG::Pnt3f position; // in object space
130 OSG::Vec3f spot_direction; // in object space, also used for dir of directional lights (see shader code)
131 OSG::Color3f Ia; // ambient max. Intensity
132 OSG::Color3f Id; // diffuse max. Intensity
133 OSG::Color3f Is; // specular max. Intensity
135 OSG::Vec3f attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0
136 OSG::Real32 spot_cos_cutoff; // cosine cut of angle
137 OSG::Real32 spot_exponent; // [0-128]
138 OSG::Int32 type; // directional_light, point_light, spot_light, no_light
141 typedef std::vector<Light> VecLightsT; // multiple lights
143 const std::size_t num_lights = 1; // simple example with just one light
145 VecLightsT initialize_lights() // helper to create lights
147 VecLightsT lights;
149 lights.push_back(Light::create_light(Light::directional_light));
151 assert(lights.size() == num_lights);
153 return lights;
156 VecLightsT lights = initialize_lights(); // the lights
160 // Simple material data structure
162 struct Material
164 Material()
165 : ambient (0.f, 0.f, 0.f)
166 , diffuse (0.f, 0.f, 0.f)
167 , specular(0.f, 0.f, 0.f)
168 , emissive(0.f, 0.f, 0.f)
169 , opacity(1.f)
170 , shininess(100.f)
173 OSG::Color3f ambient;
174 OSG::Color3f diffuse;
175 OSG::Color3f specular;
176 OSG::Color3f emissive;
178 OSG::Real32 opacity;
179 OSG::Real32 shininess;
182 typedef std::vector<Material> VecMaterialsT; // multiple materials
184 VecMaterialsT initialize_materials(std::size_t num) // helper to create materials
186 VecMaterialsT materials;
188 for (std::size_t i = 0; i < num; ++i)
190 Material m;
192 m.ambient = OSG::Color3f(0.1f, 0.1f, 0.1f);
193 m.diffuse.setRandom();
194 m.specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
195 m.emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
196 m.opacity = 1.f;
197 m.shininess = 80.f;
199 materials.push_back(m);
202 return materials;
205 const std::size_t num_materials = 100; // any numnber of materials
206 VecMaterialsT materials = initialize_materials(num_materials); // the material database
210 // Simple geometry state data structure
212 struct GeomState
214 GeomState()
215 : material_index(0)
218 OSG::UInt32 material_index;
222 // transform point from world space to eye space
224 OSG::Pnt3f transform_to_eye_space(const OSG::Pnt3f& p, OSG::SimpleSceneManager* pSSM)
226 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
227 return p;
229 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
231 OSG::Pnt3f p_es;
233 OSG::Matrix view;
234 OSG::Int16 width = pPort->calcPixelWidth();
235 OSG::Int16 height = pPort->calcPixelHeight();
237 pPort->getCamera()->getViewing(view, width, height);
239 view.multFull( p, p_es);
241 return p_es;
245 // transform vector from world space to eye space
247 OSG::Vec3f transform_to_eye_space(const OSG::Vec3f& v, OSG::SimpleSceneManager* pSSM)
249 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
250 return v;
252 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
254 OSG::Vec3f v_es;
256 OSG::Matrix view;
257 OSG::Int16 width = pPort->calcPixelWidth();
258 OSG::Int16 height = pPort->calcPixelHeight();
260 pPort->getCamera()->getViewing(view, width, height);
262 view.multFull( v, v_es);
264 return v_es;
268 // The light state
270 void update_light_state(OSG::UniformBufferObjChunk* ubo, const VecLightsT& vLights)
272 if (ubo) {
273 for (std::size_t i = 0; i < vLights.size(); ++i) {
274 std::stringstream stream;
275 stream << "Lights.light[" << i << "]." << std::flush;
276 std::string name;
277 #ifndef USE_TEST_FP_SHADER
278 OSG::Pnt3f position_es = transform_to_eye_space(vLights[i].position, mgr);
279 OSG::Vec3f spot_direction_es = transform_to_eye_space(vLights[i].spot_direction, mgr);
281 name = stream.str() + "position"; ubo->setVec3 (name, position_es);
282 name = stream.str() + "spot_direction"; ubo->setVec3 (name, spot_direction_es);
283 name = stream.str() + "Ia"; ubo->setVec3 (name, vLights[i].Ia);
284 name = stream.str() + "Id"; ubo->setVec3 (name, vLights[i].Id);
285 name = stream.str() + "Is"; ubo->setVec3 (name, vLights[i].Is);
286 name = stream.str() + "attenuation"; ubo->setVec3 (name, vLights[i].attenuation);
287 name = stream.str() + "spot_cos_cutoff"; ubo->setFloat(name, vLights[i].spot_cos_cutoff);
288 name = stream.str() + "spot_exponent"; ubo->setFloat(name, vLights[i].spot_exponent);
289 name = stream.str() + "type"; ubo->setInt (name, vLights[i].type);
290 #else
291 name = stream.str() + "position"; ubo->setVec3 (name, OSG::Pnt3f(1.1f, 2.2f, 3.3f));
292 name = stream.str() + "spot_direction"; ubo->setVec3 (name, OSG::Vec3f(4.4f, 5.5f, 6.6f));
293 name = stream.str() + "Ia"; ubo->setVec3 (name, OSG::Color3f(0.2f, 0.2f, 0.2f));
294 name = stream.str() + "Id"; ubo->setVec3 (name, OSG::Color3f(0.4f, 0.4f, 0.4f));
295 name = stream.str() + "Is"; ubo->setVec3 (name, OSG::Color3f(0.6f, 0.6f, 0.6f));
296 name = stream.str() + "attenuation"; ubo->setVec3 (name, OSG::Vec3f(0.8f, 0.8f, 0.8f));
297 name = stream.str() + "spot_cos_cutoff"; ubo->setFloat(name, 0.8f);
298 name = stream.str() + "spot_exponent"; ubo->setFloat(name, 12.3f);
299 name = stream.str() + "type"; ubo->setInt (name, Light::point_light);
300 #endif
305 OSG::UniformBufferObjChunkTransitPtr create_light_state(const VecLightsT& vLights)
307 OSG::UniformBufferObjChunkRefPtr ubo = OSG::UniformBufferObjChunk::create();
309 ubo->setBlockName("Lights");
310 ubo->setUsage(GL_STREAM_DRAW);
312 for (std::size_t i = 0; i < vLights.size(); ++i) {
313 std::stringstream stream;
314 stream << "Lights.light[" << i << "]." << std::flush;
315 std::string name;
317 name = stream.str() + "position"; ubo->addVec3 (name);
318 name = stream.str() + "spot_direction"; ubo->addVec3 (name);
319 name = stream.str() + "Ia"; ubo->addVec3 (name);
320 name = stream.str() + "Id"; ubo->addVec3 (name);
321 name = stream.str() + "Is"; ubo->addVec3 (name);
322 name = stream.str() + "attenuation"; ubo->addVec3 (name);
323 name = stream.str() + "spot_cos_cutoff"; ubo->addFloat(name);
324 name = stream.str() + "spot_exponent"; ubo->addFloat(name);
325 name = stream.str() + "type"; ubo->addInt (name);
328 update_light_state(ubo, vLights);
330 return OSG::UniformBufferObjChunkTransitPtr(ubo);
334 // The material state
336 void update_material_database_state(OSG::UniformBufferObjChunk* ubo, const VecMaterialsT& vMaterials)
338 if (ubo) {
339 for (std::size_t i = 0; i < vMaterials.size(); ++i) {
340 std::stringstream stream;
341 stream << "Materials.material[" << i << "]." << std::flush;
342 std::string name;
343 #ifndef USE_TEST_FP_SHADER
344 name = stream.str() + "ambient"; ubo->setVec3 (name, vMaterials[i].ambient);
345 name = stream.str() + "diffuse"; ubo->setVec3 (name, vMaterials[i].diffuse);
346 name = stream.str() + "specular"; ubo->setVec3 (name, vMaterials[i].specular);
347 name = stream.str() + "emissive"; ubo->setVec3 (name, vMaterials[i].emissive);
348 name = stream.str() + "opacity"; ubo->setFloat(name, vMaterials[i].opacity);
349 name = stream.str() + "shininess"; ubo->setFloat(name, vMaterials[i].shininess);
350 #else
351 name = stream.str() + "ambient"; ubo->setVec3 (name, OSG::Color3f(0.1f,0.2f,0.3f));
352 name = stream.str() + "diffuse"; ubo->setVec3 (name, OSG::Color3f(0.2f,0.4f,0.6f));
353 name = stream.str() + "specular"; ubo->setVec3 (name, OSG::Color3f(0.4f,0.6f,0.8f));
354 name = stream.str() + "emissive"; ubo->setVec3 (name, OSG::Color3f(0.6f,0.8f,1.0f));
355 name = stream.str() + "opacity"; ubo->setFloat(name, 0.7f);
356 name = stream.str() + "shininess"; ubo->setFloat(name, 25.4f);
357 #endif
362 OSG::UniformBufferObjChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
364 OSG::UniformBufferObjChunkRefPtr ubo = OSG::UniformBufferObjChunk::create();
366 ubo->setBlockName("Materials");
367 ubo->setUsage(GL_STATIC_DRAW);
369 for (std::size_t i = 0; i < vMaterials.size(); ++i) {
370 std::stringstream stream;
371 stream << "Materials.material[" << i << "]." << std::flush;
372 std::string name;
374 name = stream.str() + "ambient"; ubo->addVec3 (name);
375 name = stream.str() + "diffuse"; ubo->addVec3 (name);
376 name = stream.str() + "specular"; ubo->addVec3 (name);
377 name = stream.str() + "emissive"; ubo->addVec3 (name);
378 name = stream.str() + "opacity"; ubo->addFloat(name);
379 name = stream.str() + "shininess"; ubo->addFloat(name);
382 update_material_database_state(ubo, vMaterials);
384 return OSG::UniformBufferObjChunkTransitPtr(ubo);
388 // The geometry material state
390 void update_geometry_material_state(OSG::UniformBufferObjChunk* ubo, const GeomState& geom_state)
392 if (ubo) {
393 #ifndef USE_TEST_FP_SHADER
394 ubo->setInt("GeomState.material_index", geom_state.material_index);
395 #else
396 ubo->setInt("GeomState.material_index", 7);
397 #endif
401 OSG::UniformBufferObjChunkTransitPtr create_geometry_material_state(const GeomState& geom_state)
403 OSG::UniformBufferObjChunkRefPtr ubo = OSG::UniformBufferObjChunk::create();
405 ubo->setBlockName("GeomState");
406 ubo->setUsage(GL_DYNAMIC_DRAW);
408 ubo->addInt("GeomState.material_index");
410 update_geometry_material_state(ubo, geom_state);
412 return OSG::UniformBufferObjChunkTransitPtr(ubo);
416 // vertex shader program.
418 std::string get_vp_program();
421 // fragment shader program for bump mapping in surface local coordinates
423 std::string get_fp_program();
426 // random number generator
428 boost::random::mt19937 generator;
429 boost::random::uniform_int_distribution<> dist(0, num_materials-1);
432 // a separate transformation for every object
434 OSG::TransformRefPtr cyltrans, tortrans;
437 // Uniform buffer objects corresponding to transient shader blocks
439 OSG::UniformBufferObjChunkRefPtr ubo_light_state = NULL;
440 OSG::UniformBufferObjChunkRefPtr ubo_geom_state_1 = NULL;
441 OSG::UniformBufferObjChunkRefPtr ubo_geom_state_2 = NULL;
444 // forward declaration so we can have the interesting stuff upfront
446 int setupGLUT(int *argc, char *argv[]);
449 // redraw the window
451 void display(void)
453 // light spot direction and light position must be provided in eye space
454 update_light_state(ubo_light_state, lights);
456 // create the matrix
457 OSG::Matrix m;
458 OSG::Real32 t = glutGet(GLUT_ELAPSED_TIME );
460 // set the transforms' matrices
461 m.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t / 1000.f) * 1.5),
462 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t / 500.f));
464 cyltrans->setMatrix(m);
466 m.setTransform(OSG::Vec3f(OSG::osgSin(t / 1000.f), 0, 0),
467 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t / 1000.f));
469 tortrans->setMatrix(m);
471 OSG::commitChanges();
473 mgr->redraw();
477 // Initialize GLUT & OpenSG and set up the scene
479 int main(int argc, char **argv)
481 // OSG init
482 OSG::osgInit(argc,argv);
484 // GLUT init
485 int winid = setupGLUT(&argc, argv);
487 // open a new scope, because the pointers below should go out of scope
488 // before entering glutMainLoop.
489 // Otherwise OpenSG will complain about objects being alive after shutdown.
491 // the connection between GLUT and OpenSG
492 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
493 gwin->setGlutId(winid);
494 gwin->init();
496 // create the SimpleSceneManager helper
497 mgr = OSG::SimpleSceneManager::create();
498 mgr->setWindow(gwin);
500 // create a pretty simple graph: a Group with two Transforms as children,
501 // each of which carries a single Geometry.
503 // The scene
505 OSG::NodeRefPtr scene = OSG::Node::create();
507 // The cylinder and its transformation
508 OSG::NodeRefPtr cyl = OSG::Node::create();
509 OSG::GeometryRefPtr cylgeo = OSG::makeCylinderGeo( 1.4f, .3f, 24,
510 true, true, true );
512 cyl->setCore(cylgeo);
514 cyltrans = OSG::Transform::create();
516 OSG::NodeRefPtr cyltransnode = OSG::Node::create();
517 cyltransnode->setCore (cyltrans);
518 cyltransnode->addChild(cyl );
520 // add it to the scene
521 scene->addChild(cyltransnode);
523 // The torus and its transformation
524 OSG::NodeRefPtr torus = OSG::Node::create();
525 OSG::GeometryRefPtr torusgeo = OSG::makeTorusGeo( .2f, 1, 24, 36 );
527 torus->setCore(torusgeo);
529 tortrans = OSG::Transform::create();
531 OSG::NodeRefPtr tortransnode = OSG::Node::create();
532 tortransnode->setCore (tortrans);
533 tortransnode->addChild(torus );
535 // add it to the scene
536 scene->addChild(tortransnode);
539 // create the shader program
541 OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
542 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
543 OSG::ShaderProgramRefPtr fragShader = OSG::ShaderProgram::createFragmentShader();
545 vertShader->setProgram(get_vp_program());
546 fragShader->setProgram(get_fp_program());
549 // binding the unifrom block to a buffer binding point can be performed
550 // either by calling the shaders's addUniformBlock method or by
551 // adding a 'uniform block' variable to a ShaderProgramVariableChunk.
552 // In the following we use both variants for illustration.
554 fragShader->addUniformBlock("Materials", 1); // block binding point
555 fragShader->addUniformBlock("Lights", 2); // block binding point
558 // The following is replaced by adding ShaderProgramVariableChunk objects
559 // to the chunk material. See below...
561 // fragShader->addUniformBlock("GeomState", 3); // block binding point
563 prog_chunk->addShader(vertShader);
564 prog_chunk->addShader(fragShader);
567 // create uniform buffer objects and corresponding materials
569 OSG::UniformBufferObjChunkRefPtr ubo_material_database = create_material_database_state(materials);
570 ubo_light_state = create_light_state(lights);
572 OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
573 polygon_chunk->setFrontMode(GL_FILL);
574 polygon_chunk->setBackMode(GL_FILL);
575 polygon_chunk->setCullFace(GL_NONE);
577 OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
578 depth_chunk->setEnable(true);
580 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
581 prog_state->addChunk(ubo_material_database, 1); // buffer binding point 1
582 prog_state->addChunk(ubo_light_state, 2); // buffer binding point 2
583 prog_state->addChunk(prog_chunk);
584 prog_state->addChunk(polygon_chunk);
585 prog_state->addChunk(depth_chunk);
587 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
588 shader_var_chunk->addUniformBlock("GeomState", 3);
590 GeomState geom1; geom1.material_index = dist(generator);
591 OSG::ChunkMaterialRefPtr geom1_state = OSG::ChunkMaterial::create();
592 ubo_geom_state_1 = create_geometry_material_state(geom1);
593 geom1_state->addChunk(ubo_geom_state_1, 3); // buffer binding point 3
594 geom1_state->addChunk(shader_var_chunk); // block binding point
596 GeomState geom2; geom2.material_index = dist(generator);
597 OSG::ChunkMaterialRefPtr geom2_state = OSG::ChunkMaterial::create();
598 ubo_geom_state_2 = create_geometry_material_state(geom2);
599 geom2_state->addChunk(ubo_geom_state_2, 3); // buffer binding point 3
600 geom2_state->addChunk(shader_var_chunk); // block binding point
602 cylgeo ->setMaterial(geom1_state);
603 torusgeo->setMaterial(geom2_state);
605 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
606 mgrp->setMaterial(prog_state);
607 scene->setCore(mgrp);
609 OSG::commitChanges();
611 mgr->setRoot(scene);
613 // show the whole scene
614 mgr->showAll();
617 // GLUT main loop
618 glutMainLoop();
620 return 0;
624 // GLUT callback functions
628 // react to size changes
630 void reshape(int w, int h)
632 mgr->resize(w, h);
633 glutPostRedisplay();
637 // react to mouse button presses
639 void mouse(int button, int state, int x, int y)
641 if (state)
642 mgr->mouseButtonRelease(button, x, y);
643 else
644 mgr->mouseButtonPress(button, x, y);
646 glutPostRedisplay();
650 // react to mouse motions with pressed buttons
652 void motion(int x, int y)
654 mgr->mouseMove(x, y);
655 glutPostRedisplay();
659 // react to keys
661 void keyboard(unsigned char k, int x, int y)
663 switch(k)
665 case 27:
667 // clean up global variables
668 cyltrans = NULL;
669 tortrans = NULL;
670 mgr = NULL;
672 ubo_light_state = NULL;
673 ubo_geom_state_1 = NULL;
674 ubo_geom_state_2 = NULL;
676 OSG::osgExit();
677 exit(0);
679 break;
681 case 'm':
683 GeomState geom1; geom1.material_index = dist(generator);
684 GeomState geom2; geom2.material_index = dist(generator);
686 update_geometry_material_state(ubo_geom_state_1, geom1);
687 update_geometry_material_state(ubo_geom_state_2, geom2);
689 glutPostRedisplay();
691 break;
693 case 's':
695 mgr->setStatistics(!mgr->getStatistics());
697 break;
702 // setup the GLUT library which handles the windows for us
704 int setupGLUT(int *argc, char *argv[])
706 glutInit(argc, argv);
707 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
709 int winid = glutCreateWindow("OpenSG");
711 glutReshapeFunc(reshape);
712 glutDisplayFunc(display);
713 glutMouseFunc(mouse);
714 glutMotionFunc(motion);
715 glutKeyboardFunc(keyboard);
717 // call the redraw function whenever there's nothing else to do
718 glutIdleFunc(display);
720 return winid;
724 // vertex shader program.
726 std::string get_vp_program()
728 std::string vp_program =
729 "\n"
730 "#version 330 compatibility\n"
731 "\n"
732 "#extension GL_ARB_separate_shader_objects: enable\n"
733 "#extension GL_ARB_uniform_buffer_object: enable\n"
734 "\n"
735 "smooth out vec3 vNormalES; // eye space normal\n"
736 "smooth out vec3 vPositionES; // eye space position\n"
737 "\n"
738 "void main()\n"
739 "{\n"
740 " //\n"
741 " // multiply the object space vertex position with the modelview matrix \n"
742 " // to get the eye space vertex position\n"
743 " //\n"
744 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
745 "\n"
746 " //\n"
747 " // multiply the object space normal with the normal matrix (transpose of the inverse \n"
748 " // model view matrix) to get the eye space normal\n"
749 " //\n"
750 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
751 "\n"
752 " //\n"
753 " // multiply the combiend modelview projection matrix with the object space vertex\n"
754 " // position to get the clip space position\n"
755 " //\n"
756 " gl_Position = ftransform();\n"
757 "}\n"
758 "\n"
760 return vp_program;
764 // fragment shader program for bump mapping in surface local coordinates
766 std::string get_fp_program()
768 #ifndef USE_TEST_FP_SHADER
769 std::string fp_program =
770 "\n"
771 "#version 330 compatibility\n"
772 "\n"
773 "#extension GL_ARB_separate_shader_objects: enable\n"
774 "#extension GL_ARB_uniform_buffer_object: enable\n"
775 "\n"
776 "smooth in vec3 vNormalES; // eye space normal\n"
777 "smooth in vec3 vPositionES; // eye space position\n"
778 "\n"
779 "const int num_lights = 1;\n"
780 "const int num_materials = 100;\n"
781 "\n"
782 "const int directional_light = 0;\n"
783 "const int point_light = 1;\n"
784 "const int spot_light = 2;\n"
785 "const int no_light = 3;\n"
786 "\n"
787 "struct Light\n"
788 "{\n"
789 " vec3 position; // in eye space\n"
790 " vec3 spot_direction; // in eye space\n"
791 "\n"
792 " vec3 Ia; // ambient max. Intensity\n"
793 " vec3 Id; // diffuse max. Intensity\n"
794 " vec3 Is; // specular max. Intensity\n"
795 "\n"
796 " vec3 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
797 " \n"
798 " float spot_cos_cutoff; // cosine cut of angle\n"
799 "\n"
800 " float spot_exponent; // [0-128]\n"
801 " int type; // directional_light, point_light, spot_light, no_light\n"
802 "};\n"
803 "\n"
804 "layout (shared) uniform Lights\n"
805 "{\n"
806 " Light light[num_lights];\n"
807 "} lights;\n"
808 "\n"
809 "struct Material\n"
810 "{\n"
811 " vec3 ambient;\n"
812 " vec3 diffuse;\n"
813 " vec3 specular;\n"
814 " vec3 emissive;\n"
815 "\n"
816 " float opacity;\n"
817 " float shininess;\n"
818 "};\n"
819 "\n"
820 "layout (shared) uniform Materials\n"
821 "{\n"
822 " Material material[num_materials];\n"
823 "} materials;\n"
824 "\n"
825 "\n"
826 "layout (shared) uniform GeomState\n"
827 "{\n"
828 " int material_index;\n"
829 "} geom_state;\n"
830 "\n"
831 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
832 "\n"
833 "layout(location = 0) out vec4 vFragColor;\n"
834 "\n"
835 "//\n"
836 "// directional light contribution\n"
837 "//\n"
838 "vec3 directionalLight(\n"
839 " in int i, // light identifier, i.e. current light\n"
840 " in int j, // material identifier\n"
841 " in vec3 n, // vertex normal in eye space\n"
842 " in vec3 v) // view direction in eye space\n"
843 "{\n"
844 " if (lights.light[i].type != directional_light)\n"
845 " return vec3(0.0, 0.0, 0.0);\n"
846 "\n"
847 " //\n"
848 " // the light direction in eye space\n"
849 " //\n"
850 " vec3 l = -lights.light[i].spot_direction; // we carry the directional light direction in the spot_direction slot\n"
851 "\n"
852 " //\n"
853 " // the half vector\n"
854 " //\n"
855 " vec3 h = normalize(l + v);\n"
856 "\n"
857 " float n_dot_l = max(0.0, dot(n, l));\n"
858 " float n_dot_h = max(0.0, dot(n, h));\n"
859 "\n"
860 " float m = materials.material[j].shininess;\n"
861 "\n"
862 " float pf; // power factor\n"
863 "\n"
864 " if (n_dot_l == 0.0)\n"
865 " pf = 0.0;\n"
866 " else\n"
867 " pf = pow(n_dot_h, m);\n"
868 "\n"
869 " return materials.material[j].emissive \n"
870 " + lights.light[i].Ia * materials.material[j].ambient \n"
871 " + lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI\n"
872 " + lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
873 "}\n"
874 "\n"
875 "//\n"
876 "// point light contribution\n"
877 "//\n"
878 "vec3 pointLight(\n"
879 " in int i, // light identifier, i.e. current light\n"
880 " in int j, // material identifier\n"
881 " in vec3 n, // vertex normal in eye space\n"
882 " in vec3 v, // view direction in eye space\n"
883 " in vec3 p) // vertex position in eye space\n"
884 "{\n"
885 " if (lights.light[i].type != point_light)\n"
886 " return vec3(0.0, 0.0, 0.0);\n"
887 "\n"
888 " vec3 l = vec3(lights.light[i].position) - p; // direction from surface to light position\n"
889 " float d = length(l); // distance from surface to light source\n"
890 " l = normalize(l); // normalized direction from surface to light position\n"
891 "\n"
892 " //\n"
893 " // the half vector\n"
894 " //\n"
895 " vec3 h = normalize(l + v);\n"
896 "\n"
897 " float n_dot_l = max(0.0, dot(n, l));\n"
898 " float n_dot_h = max(0.0, dot(n, h));\n"
899 "\n"
900 " float m = materials.material[j].shininess;\n"
901 "\n"
902 " float pf; // power factor\n"
903 "\n"
904 " if (n_dot_l == 0.0)\n"
905 " pf = 0.0;\n"
906 " else\n"
907 " pf = pow(n_dot_h, m);\n"
908 "\n"
909 " //\n"
910 " // Compute attenuation\n"
911 " //\n"
912 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
913 " (lights.light[i].attenuation.y * d) + \n"
914 " (lights.light[i].attenuation.z * d * d));\n"
915 "\n"
916 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
917 "\n"
918 " return materials.material[j].emissive \n"
919 " + attenuation * lights.light[i].Ia * materials.material[j].ambient \n"
920 " + attenuation * lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI\n"
921 " + attenuation * lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
922 "}\n"
923 "\n"
924 "//\n"
925 "// spot light contribution\n"
926 "//\n"
927 "vec3 spotLight(\n"
928 " in int i, // light identifier, i.e. current light\n"
929 " in int j, // material identifier\n"
930 " in vec3 n, // vertex normal in eye space\n"
931 " in vec3 v, // view direction in eye space\n"
932 " in vec3 p) // vertex position in eye space\n"
933 "{\n"
934 " if (lights.light[i].type != spot_light)\n"
935 " return vec3(0.0, 0.0, 0.0);\n"
936 "\n"
937 " vec3 l = vec3(lights.light[i].position) - p; // direction from surface to light position\n"
938 " float d = length(l); // distance from surface to light source\n"
939 " l = normalize(l); // normalized direction from surface to light position\n"
940 " \n"
941 " vec3 s = lights.light[i].spot_direction; // spot direction\n"
942 "\n"
943 " //\n"
944 " // the half vector\n"
945 " //\n"
946 " vec3 h = normalize(l + v);\n"
947 "\n"
948 " float n_dot_l = max(0.0, dot(n, l));\n"
949 " float n_dot_h = max(0.0, dot(n, h));\n"
950 " float l_dot_s = dot(-l, s);\n"
951 "\n"
952 " float m = materials.material[j].shininess;\n"
953 "\n"
954 " float pf; // power factor\n"
955 "\n"
956 " if (n_dot_l == 0.0)\n"
957 " pf = 0.0;\n"
958 " else\n"
959 " pf = pow(n_dot_h, m);\n"
960 "\n"
961 " //\n"
962 " // Compute attenuation\n"
963 " //\n"
964 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
965 " (lights.light[i].attenuation.y * d) + \n"
966 " (lights.light[i].attenuation.z * d * d));\n"
967 "\n"
968 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
969 "\n"
970 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
971 " attenuation = 0.0;\n"
972 " else\n"
973 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\n"
974 "\n"
975 " return materials.material[j].emissive \n"
976 " + attenuation * lights.light[i].Ia * materials.material[j].ambient \n"
977 " + attenuation * lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI\n"
978 " + attenuation * lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
979 "}\n"
980 "\n"
981 "void main()\n"
982 "{\n"
983 " //\n"
984 " // normalize the eye space normal\n"
985 " //\n"
986 " vec3 N = normalize(vNormalES);\n"
987 "\n"
988 " //\n"
989 " // get the view vector and normalize it\n"
990 " //\n"
991 " vec3 V = normalize(cCameraPositionES - vPositionES);\n"
992 "\n"
993 " //\n"
994 " // Integrate over all lights: Any unused light does not contribute and each light\n"
995 " // contribute either from the directional light, the point light or the spot light.\n"
996 " //\n"
997 " vec3 color = vec3(0.0, 0.0, 0.0);\n"
998 " for (int i = 0; i < num_lights; ++i) {\n"
999 " color += directionalLight(i, geom_state.material_index, N, V) \n"
1000 " + pointLight(i, geom_state.material_index, N, V, vPositionES) \n"
1001 " + spotLight(i, geom_state.material_index, N, V, vPositionES);\n"
1002 " }\n"
1003 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"
1004 "}\n"
1005 "\n"
1007 #else
1008 std::string fp_program =
1009 "\n"
1010 "#version 330 compatibility\n"
1011 "\n"
1012 "#extension GL_ARB_separate_shader_objects: enable\n"
1013 "#extension GL_ARB_uniform_buffer_object: enable\n"
1014 "\n"
1015 "smooth in vec3 vNormalES; // eye space normal\n"
1016 "smooth in vec3 vPositionES; // eye space position\n"
1017 "\n"
1018 "const int num_lights = 1;\n"
1019 "const int num_materials = 100;\n"
1020 "\n"
1021 "const int directional_light = 0;\n"
1022 "const int point_light = 1;\n"
1023 "const int spot_light = 2;\n"
1024 "const int no_light = 3;\n"
1025 "\n"
1026 "struct Light\n"
1027 "{\n"
1028 " vec3 position; // in eye space\n"
1029 " vec3 spot_direction; // in eye space\n"
1030 "\n"
1031 " vec3 Ia; // ambient max. Intensity\n"
1032 " vec3 Id; // diffuse max. Intensity\n"
1033 " vec3 Is; // specular max. Intensity\n"
1034 "\n"
1035 " vec3 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
1036 "\n"
1037 " float spot_cos_cutoff; // cosine cut of angle\n"
1038 " float spot_exponent; // [0-128]\n"
1039 " int type; // directional_light, point_light, spot_light, no_light\n"
1040 "};\n"
1041 "\n"
1042 "layout (shared) uniform Lights\n"
1043 "{\n"
1044 " Light light[num_lights];\n"
1045 "} lights;\n"
1046 "\n"
1047 "struct Material\n"
1048 "{\n"
1049 " vec3 ambient;\n"
1050 " vec3 diffuse;\n"
1051 " vec3 specular;\n"
1052 " vec3 emissive;\n"
1053 "\n"
1054 " float opacity;\n"
1055 " float shininess;\n"
1056 "};\n"
1057 "\n"
1058 "layout (shared) uniform Materials\n"
1059 "{\n"
1060 " Material material[num_materials];\n"
1061 "} materials;\n"
1062 "\n"
1063 "\n"
1064 "layout (shared) uniform GeomState\n"
1065 "{\n"
1066 " int material_index;\n"
1067 "} geom_state;\n"
1068 "\n"
1069 "layout(location = 0) out vec4 vFragColor;\n"
1070 "\n"
1071 "\n"
1072 "void main()\n"
1073 "{\n"
1074 "\n"
1075 " int type = lights.light[0].type;\n"
1076 " vec3 position = lights.light[0].position;\n"
1077 " vec3 spot_direction = lights.light[0].spot_direction;\n"
1078 " vec3 Ia = lights.light[0].Ia;\n"
1079 " vec3 Id = lights.light[0].Id;\n"
1080 " vec3 Is = lights.light[0].Is;\n"
1081 " vec3 attenuation = lights.light[0].attenuation;\n"
1082 " float spot_cos_cutoff = lights.light[0].spot_cos_cutoff;\n"
1083 " float spot_exponent = lights.light[0].spot_exponent;\n"
1084 "\n"
1085 " vec3 ambient = materials.material[0].ambient;\n"
1086 " vec3 diffuse = materials.material[0].diffuse;\n"
1087 " vec3 specular = materials.material[0].specular;\n"
1088 " vec3 emissive = materials.material[0].emissive;\n"
1089 " float opacity = materials.material[0].opacity;\n"
1090 " float shininess = materials.material[0].shininess;\n"
1091 "\n"
1092 " int material_index = geom_state.material_index;\n"
1093 "\n"
1094 " vec4 error = vec4(1.0, 0.0, 0.0, 1.0);\n"
1095 " vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1096 "\n"
1097 " if (type != point_light)\n"
1098 " color = error;\n"
1099 "\n"
1100 " if (position != vec3(1.1, 2.2, 3.3))\n"
1101 " color = error;\n"
1102 "\n"
1103 " if (spot_direction != vec3(4.4, 5.5, 6.6))\n"
1104 " color = error;\n"
1105 "\n"
1106 " if (Ia != vec3(0.2, 0.2, 0.2))\n"
1107 " color = error;\n"
1108 "\n"
1109 " if (Id != vec3(0.4, 0.4, 0.4))\n"
1110 " color = error;\n"
1111 "\n"
1112 " if (Is != vec3(0.6, 0.6, 0.6))\n"
1113 " color = error;\n"
1114 "\n"
1115 " if (attenuation != vec3(0.8, 0.8, 0.8))\n"
1116 " color = error;\n"
1117 "\n"
1118 " if (spot_cos_cutoff != 0.8)\n"
1119 " color = error;\n"
1120 "\n"
1121 " if (spot_exponent != 12.3)\n"
1122 " color = error;\n"
1123 "\n"
1124 " if (ambient != vec3(0.1, 0.2, 0.3))\n"
1125 " color = error;\n"
1126 "\n"
1127 " if (diffuse != vec3(0.2, 0.4, 0.6))\n"
1128 " color = error;\n"
1129 "\n"
1130 " if (specular != vec3(0.4, 0.6, 0.8))\n"
1131 " color = error;\n"
1132 "\n"
1133 " if (emissive != vec3(0.6, 0.8, 1.0))\n"
1134 " color = error;\n"
1135 "\n"
1136 " if (opacity != 0.7)\n"
1137 " color = error;\n"
1138 "\n"
1139 " if (shininess != 25.4)\n"
1140 " color = error;\n"
1141 "\n"
1142 " if (material_index != 7)\n"
1143 " color = error;\n"
1144 "\n"
1145 "\n"
1146 " vFragColor = color;\n"
1147 "}\n"
1148 "\n"
1150 #endif
1151 return fp_program;