Adjust examples for MultiLight changes
[opensg.git] / Examples / Simple / uniformbufferobject_std140_1.cpp
blob6e4a7aa1994fc38a3c06e83601022d4a81154e08
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 UniformBufferObjStd140Chunk which allows the
7 // host application to directly provide a buffer to the chunk according
8 // to the std140 specification.
9 //
10 // This example differs from the uniformbufferobject_std140.cpp example
11 // that it uses the SimpleSHLChunk instead of the ShaderProgramChunk in
12 // combination with the ShaderProgram class.
17 // * - Attention
18 // =============
19 // The fragment shader of this example declares two uniform block arrays:
20 // one for the lights and one for the materials. The members of these
21 // blocks are design to be vectors of size 3: postions, directions,
22 // colors etc.
23 // The ATI/AMD graphic adapters contain a driver bug at the time of
24 // writing this example which forces the use of vectors of size 4 for
25 // the uniform members. Only then, it is possible to access the members
26 // of the uniform block arrays by non constant index variable values.
27 // This driver bug does only show up for the UBO std140 block layout.
28 // NVIDIA drivers do not show this bug and they work as expected
29 // from point of view of the std140 specification.
32 #include <boost/random/mersenne_twister.hpp>
33 #include <boost/random/uniform_int_distribution.hpp>
35 #ifdef OSG_BUILD_ACTIVE
36 // Headers
37 #include <OSGGLUT.h>
38 #include <OSGConfig.h>
39 #include <OSGSimpleGeometry.h>
40 #include <OSGGLUTWindow.h>
41 #include <OSGSimpleSceneManager.h>
42 #include <OSGBaseFunctions.h>
43 #include <OSGTransform.h>
44 #include <OSGGroup.h>
46 // new headers:
47 #include <OSGGLEXT.h>
48 #include <OSGShaderVariableOSG.h>
49 #include <OSGChunkMaterial.h>
50 #include <OSGMaterialGroup.h>
51 #include <OSGMaterialChunkOverrideGroup.h>
52 #include <OSGUniformBufferObjStd140Chunk.h>
53 #include <OSGPolygonChunk.h>
54 #include <OSGDepthChunk.h>
55 #include <OSGShaderProgramVariableChunk.h>
56 #include <OSGSimpleSHLChunk.h>
58 #else
59 // Headers
60 #include <OpenSG/OSGGLUT.h>
61 #include <OpenSG/OSGConfig.h>
62 #include <OpenSG/OSGSimpleGeometry.h>
63 #include <OpenSG/OSGGLUTWindow.h>
64 #include <OpenSG/OSGSimpleSceneManager.h>
65 #include <OpenSG/OSGBaseFunctions.h>
66 #include <OpenSG/OSGTransform.h>
67 #include <OpenSG/OSGGroup.h>
69 // new headers:
70 #include <OpenSG/OSGGLEXT.h>
71 #include <OpenSG/OSGShaderVariableOSG.h>
72 #include <OpenSG/OSGChunkMaterial.h>
73 #include <OpenSG/OSGMaterialGroup.h>
74 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
75 #include <OpenSG/OSGUniformBufferObjStd140Chunk.h>
76 #include <OpenSG/OSGPolygonChunk.h>
77 #include <OpenSG/OSGDepthChunk.h>
78 #include <OpenSG/OSGShaderProgramVariableChunk.h>
79 #include <OpenSG/OSGSimpleSHLChunk.h>
80 #endif
83 // The SimpleSceneManager to manage simple applications
85 OSG::SimpleSceneManagerRefPtr mgr;
88 // simple light data structure
90 struct Light
92 enum Type
94 directional_light = 0,
95 point_light,
96 spot_light,
97 no_light
100 Light()
101 : position(0.f, 0.f, 0.f)
102 , spot_direction(0.f, 1.f, 0.f)
103 , Ia(1.f, 1.f, 1.f)
104 , Id(1.f, 1.f, 1.f)
105 , Is(1.f, 1.f, 1.f)
106 , attenuation(1.f, 0.f, 0.f)
107 , spot_cos_cutoff(cosf(45.f))
108 , spot_exponent(1.f)
109 , type(no_light)
112 static Light create_light(Type e)
114 Light l;
115 l.type = e;
117 switch (e) {
118 case directional_light: l.spot_direction = OSG::Vec3f(1.f, 0.f, 0.f);
119 break;
120 case point_light: l.position = OSG::Pnt3f(0.f, 0.2f, 0.f);
121 break;
122 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;
123 break;
124 default:
125 break;
127 return l;
130 OSG::Pnt3f position; // in object space
131 OSG::Vec3f spot_direction; // in object space, also used for dir of directional lights (see shader code)
132 OSG::Color3f Ia; // ambient max. Intensity
133 OSG::Color3f Id; // diffuse max. Intensity
134 OSG::Color3f Is; // specular max. Intensity
136 OSG::Vec3f attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0
137 OSG::Real32 spot_cos_cutoff; // cosine cut of angle
138 OSG::Real32 spot_exponent; // [0-128]
139 OSG::Int32 type; // directional_light, point_light, spot_light, no_light
142 typedef std::vector<Light> VecLightsT; // multiple lights
144 const std::size_t num_lights = 1; // simple example with just one light
146 VecLightsT initialize_lights() // helper to create lights
148 VecLightsT lights;
150 lights.push_back(Light::create_light(Light::directional_light));
152 assert(lights.size() == num_lights);
154 return lights;
157 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 number 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 // helper to calculate the correct buffer insert positions on std140
224 std::size_t align_offset(std::size_t base_alignment, std::size_t base_offset)
226 return base_alignment * ((base_alignment + base_offset - 1) / base_alignment);
230 // transform point from world space to eye space
232 OSG::Pnt3f transform_to_eye_space(const OSG::Pnt3f& p, OSG::SimpleSceneManager* pSSM)
234 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
235 return p;
237 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
239 OSG::Pnt3f p_es;
241 OSG::Matrix view;
242 OSG::Int16 width = pPort->calcPixelWidth();
243 OSG::Int16 height = pPort->calcPixelHeight();
245 pPort->getCamera()->getViewing(view, width, height);
247 view.multFull( p, p_es);
249 return p_es;
253 // transform vector from world space to eye space
255 OSG::Vec3f transform_to_eye_space(const OSG::Vec3f& v, OSG::SimpleSceneManager* pSSM)
257 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
258 return v;
260 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
262 OSG::Vec3f v_es;
264 OSG::Matrix view;
265 OSG::Int16 width = pPort->calcPixelWidth();
266 OSG::Int16 height = pPort->calcPixelHeight();
268 pPort->getCamera()->getViewing(view, width, height);
270 view.multFull( v, v_es);
272 return v_es;
276 // the light uniform buffer object
277 // see comment *) at the top of the file
279 std::size_t calc_light_buffer_size(const VecLightsT& vLights)
281 std::size_t ao = 0; // aligned offset
282 std::size_t bo = 0; // base offset
284 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Pnt4f); // OSG::Pnt3f position;
285 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Vec4f); // OSG::Vec3f spot_direction;
286 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Ia;
287 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Id;
288 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Is;
289 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Vec4f); // OSG::Vec3f attenuation;
290 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 spot_cos_cutoff;
291 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 spot_exponent;
292 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Int32); // OSG::Int32 type;
293 ao = align_offset( 16, bo); bo = ao; // padding
295 ao *= vLights.size(); bo = ao; // array
296 ao = align_offset( 16, bo); bo = ao; // padding
298 return ao;
301 std::vector<OSG::UInt8> create_light_buffer(const VecLightsT& vLights)
303 std::size_t size = calc_light_buffer_size(vLights);
305 std::vector<OSG::UInt8> buffer(size);
307 std::size_t ao = 0; // aligned offset
308 std::size_t bo = 0; // base offset
310 for (std::size_t i = 0; i < vLights.size(); ++i)
312 OSG::Pnt3f position_es = transform_to_eye_space(vLights[i].position, mgr);
313 OSG::Vec3f spot_direction_es = transform_to_eye_space(vLights[i].spot_direction, mgr);
315 ao = align_offset(16, bo);
316 memcpy(&buffer[0] + ao, &position_es[0], sizeof(OSG::Pnt3f));
317 bo = ao + sizeof(OSG::Pnt4f);
319 ao = align_offset(16, bo);
320 memcpy(&buffer[0] + ao, &spot_direction_es[0], sizeof(OSG::Vec3f));
321 bo = ao + sizeof(OSG::Vec4f);
323 ao = align_offset(16, bo);
324 memcpy(&buffer[0] + ao, &vLights[i].Ia[0], sizeof(OSG::Color3f));
325 bo = ao + sizeof(OSG::Color4f);
327 ao = align_offset(16, bo);
328 memcpy(&buffer[0] + ao, &vLights[i].Id[0], sizeof(OSG::Color3f));
329 bo = ao + sizeof(OSG::Color4f);
331 ao = align_offset(16, bo);
332 memcpy(&buffer[0] + ao, &vLights[i].Is[0], sizeof(OSG::Color3f));
333 bo = ao + sizeof(OSG::Color4f);
335 ao = align_offset(16, bo);
336 memcpy(&buffer[0] + ao, &vLights[i].attenuation[0], sizeof(OSG::Vec3f));
337 bo = ao + sizeof(OSG::Vec4f);
339 ao = align_offset( 4, bo);
340 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vLights[i].spot_cos_cutoff;
341 bo = ao + sizeof(OSG::Real32);
343 ao = align_offset( 4, bo);
344 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vLights[i].spot_exponent;
345 bo = ao + sizeof(OSG::Real32);
347 ao = align_offset( 4, bo);
348 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = vLights[i].type;
349 bo = ao + sizeof(OSG::Int32);
351 ao = align_offset( 16, bo); bo = ao; // padding
354 return buffer;
357 OSG::UniformBufferObjStd140ChunkTransitPtr create_light_state(const VecLightsT& vLights)
359 OSG::UniformBufferObjStd140ChunkRefPtr ubo = OSG::UniformBufferObjStd140Chunk::create();
361 std::vector<OSG::UInt8> buffer = create_light_buffer(vLights);
363 ubo->editMFBuffer()->setValues(buffer);
364 ubo->setUsage(GL_DYNAMIC_DRAW);
366 return OSG::UniformBufferObjStd140ChunkTransitPtr(ubo);
369 void update_light_state(OSG::UniformBufferObjStd140Chunk* ubo, const VecLightsT& vLights)
371 if (ubo) {
372 std::vector<OSG::UInt8> buffer = create_light_buffer(vLights);
373 ubo->editMFBuffer()->setValues(buffer);
378 // the material uniform buffer object
379 // see comment *) at the top of the file
381 std::size_t calc_material_database_buffer_size(const VecMaterialsT& vMaterials)
383 std::size_t ao = 0; // aligned offset
384 std::size_t bo = 0; // base offset
386 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f ambient;
387 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f diffuse;
388 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f specular;
389 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f emissive;
390 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 opacity;
391 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 shininess;
392 ao = align_offset( 16, bo); bo = ao; // padding
394 ao *= vMaterials.size(); bo = ao; // array
395 ao = align_offset( 16, bo); bo = ao; // padding
397 return ao;
400 std::vector<OSG::UInt8> create_material_database_buffer(const VecMaterialsT& vMaterials)
402 std::size_t size = calc_material_database_buffer_size(vMaterials);
404 std::vector<OSG::UInt8> buffer(size);
406 std::size_t ao = 0; // aligned offset
407 std::size_t bo = 0; // base offset
409 for (std::size_t i = 0; i < vMaterials.size(); ++i)
411 ao = align_offset(16, bo);
412 memcpy(&buffer[0] + ao, &vMaterials[i].ambient[0], sizeof(OSG::Color3f));
413 bo = ao + sizeof(OSG::Color4f);
415 ao = align_offset(16, bo);
416 memcpy(&buffer[0] + ao, &vMaterials[i].diffuse[0], sizeof(OSG::Color3f));
417 bo = ao + sizeof(OSG::Color4f);
419 ao = align_offset(16, bo);
420 memcpy(&buffer[0] + ao, &vMaterials[i].specular[0], sizeof(OSG::Color3f));
421 bo = ao + sizeof(OSG::Color4f);
423 ao = align_offset(16, bo);
424 memcpy(&buffer[0] + ao, &vMaterials[i].emissive[0], sizeof(OSG::Color3f));
425 bo = ao + sizeof(OSG::Color4f);
427 ao = align_offset( 4, bo);
428 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vMaterials[i].opacity;
429 bo = ao + sizeof(OSG::Real32);
431 ao = align_offset( 4, bo);
432 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vMaterials[i].shininess;
433 bo = ao + sizeof(OSG::Real32);
435 ao = align_offset( 16, bo); bo = ao; // padding
438 return buffer;
441 OSG::UniformBufferObjStd140ChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
443 OSG::UniformBufferObjStd140ChunkRefPtr ubo = OSG::UniformBufferObjStd140Chunk::create();
445 std::vector<OSG::UInt8> buffer = create_material_database_buffer(vMaterials);
447 ubo->editMFBuffer()->setValues(buffer);
448 ubo->setUsage(GL_STATIC_DRAW);
450 return OSG::UniformBufferObjStd140ChunkTransitPtr(ubo);
453 void update_material_database_state(OSG::UniformBufferObjStd140Chunk* ubo, const VecMaterialsT& vMaterials)
455 if (ubo) {
456 std::vector<OSG::UInt8> buffer = create_material_database_buffer(vMaterials);
457 ubo->editMFBuffer()->setValues(buffer);
462 // the geomertry uniform buffer object
464 std::size_t calc_geometry_material_buffer_size()
466 std::size_t ao = 0; // aligned offset
467 std::size_t bo = 0; // base offset
469 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::UInt32); // OSG::UInt32 material_index;
470 ao = align_offset( 16, bo); bo = ao; // padding
472 return ao;
475 std::vector<OSG::UInt8> create_geometry_material_buffer(const GeomState& geom_state)
477 std::size_t size = calc_geometry_material_buffer_size();
479 std::vector<OSG::UInt8> buffer(size);
481 std::size_t ao = 0; // aligned offset
482 std::size_t bo = 0; // base offset
484 ao = align_offset( 4, bo);
485 *(reinterpret_cast<OSG::UInt32*>(&buffer[0] + ao)) = geom_state.material_index;
486 bo = ao + sizeof(OSG::UInt32);
488 return buffer;
491 OSG::UniformBufferObjStd140ChunkTransitPtr create_geometry_material_state(const GeomState& geom_state)
493 OSG::UniformBufferObjStd140ChunkRefPtr ubo = OSG::UniformBufferObjStd140Chunk::create();
495 std::vector<OSG::UInt8> buffer = create_geometry_material_buffer(geom_state);
497 ubo->editMFBuffer()->setValues(buffer);
498 ubo->setUsage(GL_DYNAMIC_DRAW);
500 return OSG::UniformBufferObjStd140ChunkTransitPtr(ubo);
503 void update_geometry_material_state(OSG::UniformBufferObjStd140Chunk* ubo, const GeomState& geom_state)
505 if (ubo) {
506 std::vector<OSG::UInt8> buffer = create_geometry_material_buffer(geom_state);
507 ubo->editMFBuffer()->setValues(buffer);
512 // vertex shader program.
514 std::string get_vp_program();
517 // fragment shader program for bump mapping in surface local coordinates
519 std::string get_fp_program();
522 // random number generator
524 boost::random::mt19937 generator;
525 boost::random::uniform_int_distribution<> dist(0, num_materials-1);
528 // a separate transformation for every object
530 OSG::TransformRefPtr cyltrans, tortrans;
533 // Uniform buffer objects corresponding to transient shader blocks
535 OSG::UniformBufferObjStd140ChunkRefPtr ubo_light_state = NULL;
536 OSG::UniformBufferObjStd140ChunkRefPtr ubo_geom_state_1 = NULL;
537 OSG::UniformBufferObjStd140ChunkRefPtr ubo_geom_state_2 = NULL;
540 // forward declaration so we can have the interesting stuff upfront
542 int setupGLUT(int *argc, char *argv[]);
545 // redraw the window
547 void display(void)
549 // light spot direction and light position must be provided in eye space
550 update_light_state(ubo_light_state, lights);
552 // create the matrix
553 OSG::Matrix m;
554 OSG::Real32 t = glutGet(GLUT_ELAPSED_TIME );
556 // set the transforms' matrices
557 m.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t / 1000.f) * 1.5),
558 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t / 500.f));
560 cyltrans->setMatrix(m);
562 m.setTransform(OSG::Vec3f(OSG::osgSin(t / 1000.f), 0, 0),
563 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t / 1000.f));
565 tortrans->setMatrix(m);
567 OSG::commitChanges();
569 mgr->redraw();
573 // Initialize GLUT & OpenSG and set up the scene
575 int main(int argc, char **argv)
577 // OSG init
578 OSG::osgInit(argc,argv);
580 // GLUT init
581 int winid = setupGLUT(&argc, argv);
583 // open a new scope, because the pointers below should go out of scope
584 // before entering glutMainLoop.
585 // Otherwise OpenSG will complain about objects being alive after shutdown.
587 // the connection between GLUT and OpenSG
588 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
589 gwin->setGlutId(winid);
590 gwin->init();
592 // create the SimpleSceneManager helper
593 mgr = OSG::SimpleSceneManager::create();
594 mgr->setWindow(gwin);
596 // create a pretty simple graph: a Group with two Transforms as children,
597 // each of which carries a single Geometry.
599 // The scene
601 OSG::NodeRefPtr scene = OSG::Node::create();
603 // The cylinder and its transformation
604 OSG::NodeRefPtr cyl = OSG::Node::create();
605 OSG::GeometryRefPtr cylgeo = OSG::makeCylinderGeo( 1.4f, .3f, 24,
606 true, true, true );
608 cyl->setCore(cylgeo);
610 cyltrans = OSG::Transform::create();
612 OSG::NodeRefPtr cyltransnode = OSG::Node::create();
613 cyltransnode->setCore (cyltrans);
614 cyltransnode->addChild(cyl );
616 // add it to the scene
617 scene->addChild(cyltransnode);
619 // The torus and its transformation
620 OSG::NodeRefPtr torus = OSG::Node::create();
621 OSG::GeometryRefPtr torusgeo = OSG::makeTorusGeo( .2f, 1, 24, 36 );
623 torus->setCore(torusgeo);
625 tortrans = OSG::Transform::create();
627 OSG::NodeRefPtr tortransnode = OSG::Node::create();
628 tortransnode->setCore (tortrans);
629 tortransnode->addChild(torus );
631 // add it to the scene
632 scene->addChild(tortransnode);
635 // create the shader program
637 OSG::SimpleSHLChunkUnrecPtr prog_chunk = OSG::SimpleSHLChunk::create();
639 prog_chunk->setVertexProgram(get_vp_program());
640 prog_chunk->setFragmentProgram(get_fp_program());
642 prog_chunk->addUniformBlock("Materials", 1); // block binding point
643 prog_chunk->addUniformBlock("Lights", 2); // block binding point
646 // create uniform buffer objects and corresponding materials
648 OSG::UniformBufferObjStd140ChunkRefPtr ubo_material_database = create_material_database_state(materials);
649 ubo_light_state = create_light_state(lights);
651 OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
652 polygon_chunk->setFrontMode(GL_FILL);
653 polygon_chunk->setBackMode(GL_FILL);
654 polygon_chunk->setCullFace(GL_NONE);
656 OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
657 depth_chunk->setEnable(true);
659 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
660 prog_state->addChunk(ubo_material_database, 1); // buffer binding point 1
661 prog_state->addChunk(ubo_light_state, 2); // buffer binding point 2
662 prog_state->addChunk(prog_chunk);
663 prog_state->addChunk(polygon_chunk);
664 prog_state->addChunk(depth_chunk);
667 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
668 shader_var_chunk->addUniformBlock("GeomState", 3);
670 GeomState geom1; geom1.material_index = dist(generator);
671 OSG::ChunkMaterialRefPtr geom1_state = OSG::ChunkMaterial::create();
672 ubo_geom_state_1 = create_geometry_material_state(geom1);
673 geom1_state->addChunk(ubo_geom_state_1, 3); // buffer binding point 3
674 geom1_state->addChunk(shader_var_chunk); // block binding point
676 GeomState geom2; geom2.material_index = dist(generator);
677 OSG::ChunkMaterialRefPtr geom2_state = OSG::ChunkMaterial::create();
678 ubo_geom_state_2 = create_geometry_material_state(geom2);
679 geom2_state->addChunk(ubo_geom_state_2, 3); // buffer binding point 3
680 geom2_state->addChunk(shader_var_chunk); // block binding point
682 cylgeo ->setMaterial(geom1_state);
683 torusgeo->setMaterial(geom2_state);
685 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
686 mgrp->setMaterial(prog_state);
687 scene->setCore(mgrp);
689 OSG::commitChanges();
691 mgr->setRoot(scene);
693 // show the whole scene
694 mgr->showAll();
697 // GLUT main loop
698 glutMainLoop();
700 return 0;
704 // GLUT callback functions
708 // react to size changes
710 void reshape(int w, int h)
712 mgr->resize(w, h);
713 glutPostRedisplay();
717 // react to mouse button presses
719 void mouse(int button, int state, int x, int y)
721 if (state)
722 mgr->mouseButtonRelease(button, x, y);
723 else
724 mgr->mouseButtonPress(button, x, y);
726 glutPostRedisplay();
730 // react to mouse motions with pressed buttons
732 void motion(int x, int y)
734 mgr->mouseMove(x, y);
735 glutPostRedisplay();
739 // react to keys
741 void keyboard(unsigned char k, int x, int y)
743 switch(k)
745 case 27:
747 // clean up global variables
748 cyltrans = NULL;
749 tortrans = NULL;
750 mgr = NULL;
752 ubo_light_state = NULL;
753 ubo_geom_state_1 = NULL;
754 ubo_geom_state_2 = NULL;
756 OSG::osgExit();
757 exit(0);
759 break;
761 case 'm':
763 GeomState geom1; geom1.material_index = dist(generator);
764 GeomState geom2; geom2.material_index = dist(generator);
766 update_geometry_material_state(ubo_geom_state_1, geom1);
767 update_geometry_material_state(ubo_geom_state_2, geom2);
769 glutPostRedisplay();
771 break;
773 case 's':
775 mgr->setStatistics(!mgr->getStatistics());
777 break;
782 // setup the GLUT library which handles the windows for us
784 int setupGLUT(int *argc, char *argv[])
786 glutInit(argc, argv);
787 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
789 int winid = glutCreateWindow("OpenSG");
791 glutReshapeFunc(reshape);
792 glutDisplayFunc(display);
793 glutMouseFunc(mouse);
794 glutMotionFunc(motion);
795 glutKeyboardFunc(keyboard);
797 // call the redraw function whenever there's nothing else to do
798 glutIdleFunc(display);
800 return winid;
804 // vertex shader program.
806 std::string get_vp_program()
808 std::string vp_program =
809 "\n"
810 "#version 330 compatibility\n"
811 "\n"
812 "#extension GL_ARB_separate_shader_objects: enable\n"
813 "#extension GL_ARB_uniform_buffer_object: enable\n"
814 "\n"
815 "smooth out vec3 vNormalES; // eye space normal\n"
816 "smooth out vec3 vPositionES; // eye space position\n"
817 "\n"
818 "void main()\n"
819 "{\n"
820 " //\n"
821 " // multiply the object space vertex position with the modelview matrix \n"
822 " // to get the eye space vertex position\n"
823 " //\n"
824 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
825 "\n"
826 " //\n"
827 " // multiply the object space normal with the normal matrix (transpose of the inverse \n"
828 " // model view matrix) to get the eye space normal\n"
829 " //\n"
830 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
831 "\n"
832 " //\n"
833 " // multiply the combiend modelview projection matrix with the object space vertex\n"
834 " // position to get the clip space position\n"
835 " //\n"
836 " gl_Position = ftransform();\n"
837 "}\n"
838 "\n"
841 return vp_program;
845 // fragment shader program for bump mapping in surface local coordinates
847 std::string get_fp_program()
849 std::string fp_program =
850 "\n"
851 "#version 330 compatibility\n"
852 "\n"
853 "#extension GL_ARB_separate_shader_objects: enable\n"
854 "#extension GL_ARB_uniform_buffer_object: enable\n"
855 "\n"
856 "smooth in vec3 vNormalES; // eye space normal\n"
857 "smooth in vec3 vPositionES; // eye space position\n"
858 "\n"
859 "const int num_lights = 1;\n"
860 "const int num_materials = 100;\n"
861 "\n"
862 "const int directional_light = 0;\n"
863 "const int point_light = 1;\n"
864 "const int spot_light = 2;\n"
865 "const int no_light = 3;\n"
866 "\n"
867 "struct Light\n"
868 "{\n"
869 " vec4 position; // in eye space\n"
870 " vec4 spot_direction; // in eye space\n"
871 "\n"
872 " vec4 Ia; // ambient max. Intensity\n"
873 " vec4 Id; // diffuse max. Intensity\n"
874 " vec4 Is; // specular max. Intensity\n"
875 "\n"
876 " vec4 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
877 " \n"
878 " float spot_cos_cutoff; // cosine cut of angle\n"
879 "\n"
880 " float spot_exponent; // [0-128]\n"
881 " int type; // directional_light, point_light, spot_light, no_light\n"
882 "};\n"
883 "\n"
884 "layout (std140) uniform Lights\n"
885 "{\n"
886 " Light light[num_lights];\n"
887 "} lights;\n"
888 "\n"
889 "struct Material\n"
890 "{\n"
891 " vec4 ambient;\n"
892 " vec4 diffuse;\n"
893 " vec4 specular;\n"
894 " vec4 emissive;\n"
895 "\n"
896 " float opacity;\n"
897 " float shininess;\n"
898 "};\n"
899 "\n"
900 "layout (std140) uniform Materials\n"
901 "{\n"
902 " Material material[num_materials];\n"
903 "} materials;\n"
904 "\n"
905 "\n"
906 "layout (std140) uniform GeomState\n"
907 "{\n"
908 " int material_index;\n"
909 "} geom_state;\n"
910 "\n"
911 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
912 "\n"
913 "layout(location = 0) out vec4 vFragColor;\n"
914 "\n"
915 "//\n"
916 "// directional light contribution\n"
917 "//\n"
918 "vec3 directionalLight(\n"
919 " in int i, // light identifier, i.e. current light\n"
920 " in int j, // material identifier\n"
921 " in vec3 n, // vertex normal in eye space\n"
922 " in vec3 v) // view direction in eye space\n"
923 "{\n"
924 " if (lights.light[i].type != directional_light)\n"
925 " return vec3(0.0, 0.0, 0.0);\n"
926 "\n"
927 " //\n"
928 " // the light direction in eye space\n"
929 " //\n"
930 " vec3 l = -lights.light[i].spot_direction.xyz; // we carry the directional light direction in the spot_direction slot\n"
931 "\n"
932 " //\n"
933 " // the half vector\n"
934 " //\n"
935 " vec3 h = normalize(l + v);\n"
936 "\n"
937 " float n_dot_l = max(0.0, dot(n, l));\n"
938 " float n_dot_h = max(0.0, dot(n, h));\n"
939 "\n"
940 " float m = materials.material[j].shininess;\n"
941 "\n"
942 " float pf; // power factor\n"
943 "\n"
944 " if (n_dot_l == 0.0)\n"
945 " pf = 0.0;\n"
946 " else\n"
947 " pf = pow(n_dot_h, m);\n"
948 "\n"
949 " return materials.material[j].emissive.rgb \n"
950 " + lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
951 " + lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
952 " + lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
953 "}\n"
954 "\n"
955 "//\n"
956 "// point light contribution\n"
957 "//\n"
958 "vec3 pointLight(\n"
959 " in int i, // light identifier, i.e. current light\n"
960 " in int j, // material identifier\n"
961 " in vec3 n, // vertex normal in eye space\n"
962 " in vec3 v, // view direction in eye space\n"
963 " in vec3 p) // vertex position in eye space\n"
964 "{\n"
965 " if (lights.light[i].type != point_light)\n"
966 " return vec3(0.0, 0.0, 0.0);\n"
967 "\n"
968 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
969 " float d = length(l); // distance from surface to light source\n"
970 " l = normalize(l); // normalized direction from surface to light position\n"
971 "\n"
972 " //\n"
973 " // the half vector\n"
974 " //\n"
975 " vec3 h = normalize(l + v);\n"
976 "\n"
977 " float n_dot_l = max(0.0, dot(n, l));\n"
978 " float n_dot_h = max(0.0, dot(n, h));\n"
979 "\n"
980 " float m = materials.material[j].shininess;\n"
981 "\n"
982 " float pf; // power factor\n"
983 "\n"
984 " if (n_dot_l == 0.0)\n"
985 " pf = 0.0;\n"
986 " else\n"
987 " pf = pow(n_dot_h, m);\n"
988 "\n"
989 " //\n"
990 " // Compute attenuation\n"
991 " //\n"
992 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
993 " (lights.light[i].attenuation.y * d) + \n"
994 " (lights.light[i].attenuation.z * d * d));\n"
995 "\n"
996 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
997 "\n"
998 " return materials.material[j].emissive.rgb \n"
999 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1000 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1001 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1002 "}\n"
1003 "\n"
1004 "//\n"
1005 "// spot light contribution\n"
1006 "//\n"
1007 "vec3 spotLight(\n"
1008 " in int i, // light identifier, i.e. current light\n"
1009 " in int j, // material identifier\n"
1010 " in vec3 n, // vertex normal in eye space\n"
1011 " in vec3 v, // view direction in eye space\n"
1012 " in vec3 p) // vertex position in eye space\n"
1013 "{\n"
1014 " if (lights.light[i].type != spot_light)\n"
1015 " return vec3(0.0, 0.0, 0.0);\n"
1016 "\n"
1017 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1018 " float d = length(l); // distance from surface to light source\n"
1019 " l = normalize(l); // normalized direction from surface to light position\n"
1020 " \n"
1021 " vec3 s = lights.light[i].spot_direction.xyz; // spot direction\n"
1022 "\n"
1023 " //\n"
1024 " // the half vector\n"
1025 " //\n"
1026 " vec3 h = normalize(l + v);\n"
1027 "\n"
1028 " float n_dot_l = max(0.0, dot(n, l));\n"
1029 " float n_dot_h = max(0.0, dot(n, h));\n"
1030 " float l_dot_s = dot(-l, s);\n"
1031 "\n"
1032 " float m = materials.material[j].shininess;\n"
1033 "\n"
1034 " float pf; // power factor\n"
1035 "\n"
1036 " if (n_dot_l == 0.0)\n"
1037 " pf = 0.0;\n"
1038 " else\n"
1039 " pf = pow(n_dot_h, m);\n"
1040 "\n"
1041 " //\n"
1042 " // Compute attenuation\n"
1043 " //\n"
1044 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1045 " (lights.light[i].attenuation.y * d) + \n"
1046 " (lights.light[i].attenuation.z * d * d));\n"
1047 "\n"
1048 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1049 "\n"
1050 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
1051 " attenuation = 0.0;\n"
1052 " else\n"
1053 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\n"
1054 "\n"
1055 " return materials.material[j].emissive.rgb \n"
1056 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1057 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1058 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1059 "}\n"
1060 "\n"
1061 "void main()\n"
1062 "{\n"
1063 " //\n"
1064 " // normalize the eye space normal\n"
1065 " //\n"
1066 " vec3 N = normalize(vNormalES);\n"
1067 "\n"
1068 " //\n"
1069 " // get the view vector and normalize it\n"
1070 " //\n"
1071 " vec3 V = normalize(cCameraPositionES - vPositionES);\n"
1072 "\n"
1073 " //\n"
1074 " // Integrate over all lights: Any unused light does not contribute and each light\n"
1075 " // contribute either from the directional light, the point light or the spot light.\n"
1076 " //\n"
1077 " vec3 color = vec3(0.0, 0.0, 0.0);\n"
1078 " for (int i = 0; i < num_lights; ++i) {\n"
1079 " color += directionalLight(i, geom_state.material_index, N, V) \n"
1080 " + pointLight(i, geom_state.material_index, N, V, vPositionES) \n"
1081 " + spotLight(i, geom_state.material_index, N, V, vPositionES);\n"
1082 " }\n"
1083 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"
1084 "}\n"
1085 "\n"
1088 return fp_program;