Adjust examples for MultiLight changes
[opensg.git] / Examples / Simple / uniformbufferobject_std140.cpp
blob9e31dcd8c1723c5e374da0e55a0e014b3ddd1f0d
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 //
12 // * - Attention
13 // =============
14 // The fragment shader of this example declares two uniform block arrays:
15 // one for the lights and one for the materials. The members of these
16 // blocks are design to be vectors of size 3: postions, directions,
17 // colors etc.
18 // The ATI/AMD graphic adapters contain a driver bug at the time of
19 // writing this example which forces the use of vectors of size 4 for
20 // the uniform members. Only then, it is possible to access the members
21 // of the uniform block arrays by non constant index variable values.
22 // This driver bug does only show up for the UBO std140 block layout.
23 // NVIDIA drivers do not show this bug and they work as expected
24 // from point of view of the std140 specification.
27 #include <boost/random/mersenne_twister.hpp>
28 #include <boost/random/uniform_int_distribution.hpp>
30 #ifdef OSG_BUILD_ACTIVE
31 // Headers
32 #include <OSGGLUT.h>
33 #include <OSGConfig.h>
34 #include <OSGSimpleGeometry.h>
35 #include <OSGGLUTWindow.h>
36 #include <OSGSimpleSceneManager.h>
37 #include <OSGBaseFunctions.h>
38 #include <OSGTransform.h>
39 #include <OSGGroup.h>
41 // new headers:
42 #include <OSGGLEXT.h>
43 #include <OSGShaderProgramChunk.h>
44 #include <OSGShaderProgram.h>
45 #include <OSGShaderVariableOSG.h>
46 #include <OSGChunkMaterial.h>
47 #include <OSGMaterialGroup.h>
48 #include <OSGMaterialChunkOverrideGroup.h>
49 #include <OSGUniformBufferObjStd140Chunk.h>
50 #include <OSGPolygonChunk.h>
51 #include <OSGDepthChunk.h>
52 #include <OSGShaderProgramVariableChunk.h>
54 #else
55 // Headers
56 #include <OpenSG/OSGGLUT.h>
57 #include <OpenSG/OSGConfig.h>
58 #include <OpenSG/OSGSimpleGeometry.h>
59 #include <OpenSG/OSGGLUTWindow.h>
60 #include <OpenSG/OSGSimpleSceneManager.h>
61 #include <OpenSG/OSGBaseFunctions.h>
62 #include <OpenSG/OSGTransform.h>
63 #include <OpenSG/OSGGroup.h>
65 // new headers:
66 #include <OpenSG/OSGGLEXT.h>
67 #include <OpenSG/OSGShaderProgramChunk.h>
68 #include <OpenSG/OSGShaderProgram.h>
69 #include <OpenSG/OSGShaderVariableOSG.h>
70 #include <OpenSG/OSGChunkMaterial.h>
71 #include <OpenSG/OSGMaterialGroup.h>
72 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
73 #include <OpenSG/OSGUniformBufferObjStd140Chunk.h>
74 #include <OpenSG/OSGPolygonChunk.h>
75 #include <OpenSG/OSGDepthChunk.h>
76 #include <OpenSG/OSGShaderProgramVariableChunk.h>
77 #endif
80 // The SimpleSceneManager to manage simple applications
82 OSG::SimpleSceneManagerRefPtr mgr;
85 // simple light data structure
87 struct Light
89 enum Type
91 directional_light = 0,
92 point_light,
93 spot_light,
94 no_light
97 Light()
98 : position(0.f, 0.f, 0.f)
99 , spot_direction(0.f, 1.f, 0.f)
100 , Ia(1.f, 1.f, 1.f)
101 , Id(1.f, 1.f, 1.f)
102 , Is(1.f, 1.f, 1.f)
103 , attenuation(1.f, 0.f, 0.f)
104 , spot_cos_cutoff(cosf(45.f))
105 , spot_exponent(1.f)
106 , type(no_light)
109 static Light create_light(Type e)
111 Light l;
112 l.type = e;
114 switch (e) {
115 case directional_light: l.spot_direction = OSG::Vec3f(1.f, 0.f, 0.f);
116 break;
117 case point_light: l.position = OSG::Pnt3f(0.f, 0.2f, 0.f);
118 break;
119 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;
120 break;
121 default:
122 break;
124 return l;
127 OSG::Pnt3f position; // in object space
128 OSG::Vec3f spot_direction; // in object space, also used for dir of directional lights (see shader code)
129 OSG::Color3f Ia; // ambient max. Intensity
130 OSG::Color3f Id; // diffuse max. Intensity
131 OSG::Color3f Is; // specular max. Intensity
133 OSG::Vec3f attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0
134 OSG::Real32 spot_cos_cutoff; // cosine cut of angle
135 OSG::Real32 spot_exponent; // [0-128]
136 OSG::Int32 type; // directional_light, point_light, spot_light, no_light
139 typedef std::vector<Light> VecLightsT; // multiple lights
141 const std::size_t num_lights = 1; // simple example with just one light
143 VecLightsT initialize_lights() // helper to create lights
145 VecLightsT lights;
147 lights.push_back(Light::create_light(Light::directional_light));
149 assert(lights.size() == num_lights);
151 return lights;
154 VecLightsT lights = initialize_lights(); // the lights
158 // Simple material data structure
160 struct Material
162 Material()
163 : ambient (0.f, 0.f, 0.f)
164 , diffuse (0.f, 0.f, 0.f)
165 , specular(0.f, 0.f, 0.f)
166 , emissive(0.f, 0.f, 0.f)
167 , opacity(1.f)
168 , shininess(100.f)
171 OSG::Color3f ambient;
172 OSG::Color3f diffuse;
173 OSG::Color3f specular;
174 OSG::Color3f emissive;
176 OSG::Real32 opacity;
177 OSG::Real32 shininess;
180 typedef std::vector<Material> VecMaterialsT; // multiple materials
182 VecMaterialsT initialize_materials(std::size_t num) // helper to create materials
184 VecMaterialsT materials;
186 for (std::size_t i = 0; i < num; ++i)
188 Material m;
190 m.ambient = OSG::Color3f(0.1f, 0.1f, 0.1f);
191 m.diffuse.setRandom();
192 m.specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
193 m.emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
194 m.opacity = 1.f;
195 m.shininess = 80.f;
197 materials.push_back(m);
200 return materials;
203 const std::size_t num_materials = 100; // any number of materials
204 VecMaterialsT materials = initialize_materials(num_materials); // the material database
208 // Simple geometry state data structure
210 struct GeomState
212 GeomState()
213 : material_index(0)
216 OSG::UInt32 material_index;
220 // helper to calculate the correct buffer insert positions on std140
222 std::size_t align_offset(std::size_t base_alignment, std::size_t base_offset)
224 return base_alignment * ((base_alignment + base_offset - 1) / base_alignment);
228 // transform point from world space to eye space
230 OSG::Pnt3f transform_to_eye_space(const OSG::Pnt3f& p, OSG::SimpleSceneManager* pSSM)
232 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
233 return p;
235 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
237 OSG::Pnt3f p_es;
239 OSG::Matrix view;
240 OSG::Int16 width = pPort->calcPixelWidth();
241 OSG::Int16 height = pPort->calcPixelHeight();
243 pPort->getCamera()->getViewing(view, width, height);
245 view.multFull( p, p_es);
247 return p_es;
251 // transform vector from world space to eye space
253 OSG::Vec3f transform_to_eye_space(const OSG::Vec3f& v, OSG::SimpleSceneManager* pSSM)
255 if (!pSSM || !pSSM->getWindow() || pSSM->getWindow()->getMFPort()->size() == 0)
256 return v;
258 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
260 OSG::Vec3f v_es;
262 OSG::Matrix view;
263 OSG::Int16 width = pPort->calcPixelWidth();
264 OSG::Int16 height = pPort->calcPixelHeight();
266 pPort->getCamera()->getViewing(view, width, height);
268 view.multFull( v, v_es);
270 return v_es;
274 // the light uniform buffer object
275 // see comment *) at the top of the file
277 std::size_t calc_light_buffer_size(const VecLightsT& vLights)
279 std::size_t ao = 0; // aligned offset
280 std::size_t bo = 0; // base offset
282 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Pnt4f); // OSG::Pnt3f position;
283 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Vec4f); // OSG::Vec3f spot_direction;
284 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Ia;
285 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Id;
286 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f Is;
287 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Vec4f); // OSG::Vec3f attenuation;
288 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 spot_cos_cutoff;
289 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 spot_exponent;
290 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Int32); // OSG::Int32 type;
291 ao = align_offset( 16, bo); bo = ao; // padding
293 ao *= vLights.size(); bo = ao; // array
294 ao = align_offset( 16, bo); bo = ao; // padding
296 return ao;
299 std::vector<OSG::UInt8> create_light_buffer(const VecLightsT& vLights)
301 std::size_t size = calc_light_buffer_size(vLights);
303 std::vector<OSG::UInt8> buffer(size);
305 std::size_t ao = 0; // aligned offset
306 std::size_t bo = 0; // base offset
308 for (std::size_t i = 0; i < vLights.size(); ++i)
310 OSG::Pnt3f position_es = transform_to_eye_space(vLights[i].position, mgr);
311 OSG::Vec3f spot_direction_es = transform_to_eye_space(vLights[i].spot_direction, mgr);
313 ao = align_offset(16, bo);
314 memcpy(&buffer[0] + ao, &position_es[0], sizeof(OSG::Pnt3f));
315 bo = ao + sizeof(OSG::Pnt4f);
317 ao = align_offset(16, bo);
318 memcpy(&buffer[0] + ao, &spot_direction_es[0], sizeof(OSG::Vec3f));
319 bo = ao + sizeof(OSG::Vec4f);
321 ao = align_offset(16, bo);
322 memcpy(&buffer[0] + ao, &vLights[i].Ia[0], sizeof(OSG::Color3f));
323 bo = ao + sizeof(OSG::Color4f);
325 ao = align_offset(16, bo);
326 memcpy(&buffer[0] + ao, &vLights[i].Id[0], sizeof(OSG::Color3f));
327 bo = ao + sizeof(OSG::Color4f);
329 ao = align_offset(16, bo);
330 memcpy(&buffer[0] + ao, &vLights[i].Is[0], sizeof(OSG::Color3f));
331 bo = ao + sizeof(OSG::Color4f);
333 ao = align_offset(16, bo);
334 memcpy(&buffer[0] + ao, &vLights[i].attenuation[0], sizeof(OSG::Vec3f));
335 bo = ao + sizeof(OSG::Vec4f);
337 ao = align_offset( 4, bo);
338 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vLights[i].spot_cos_cutoff;
339 bo = ao + sizeof(OSG::Real32);
341 ao = align_offset( 4, bo);
342 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vLights[i].spot_exponent;
343 bo = ao + sizeof(OSG::Real32);
345 ao = align_offset( 4, bo);
346 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = vLights[i].type;
347 bo = ao + sizeof(OSG::Int32);
349 ao = align_offset( 16, bo); bo = ao; // padding
352 return buffer;
355 OSG::UniformBufferObjStd140ChunkTransitPtr create_light_state(const VecLightsT& vLights)
357 OSG::UniformBufferObjStd140ChunkRefPtr ubo = OSG::UniformBufferObjStd140Chunk::create();
359 std::vector<OSG::UInt8> buffer = create_light_buffer(vLights);
361 ubo->editMFBuffer()->setValues(buffer);
362 ubo->setUsage(GL_DYNAMIC_DRAW);
364 return OSG::UniformBufferObjStd140ChunkTransitPtr(ubo);
367 void update_light_state(OSG::UniformBufferObjStd140Chunk* ubo, const VecLightsT& vLights)
369 if (ubo) {
370 std::vector<OSG::UInt8> buffer = create_light_buffer(vLights);
371 ubo->editMFBuffer()->setValues(buffer);
376 // the material uniform buffer object
377 // see comment *) at the top of the file
379 std::size_t calc_material_database_buffer_size(const VecMaterialsT& vMaterials)
381 std::size_t ao = 0; // aligned offset
382 std::size_t bo = 0; // base offset
384 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f ambient;
385 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f diffuse;
386 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f specular;
387 ao = align_offset( 16, bo); bo = ao + sizeof(OSG::Color4f); // OSG::Color3f emissive;
388 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 opacity;
389 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::Real32); // OSG::Real32 shininess;
390 ao = align_offset( 16, bo); bo = ao; // padding
392 ao *= vMaterials.size(); bo = ao; // array
393 ao = align_offset( 16, bo); bo = ao; // padding
395 return ao;
398 std::vector<OSG::UInt8> create_material_database_buffer(const VecMaterialsT& vMaterials)
400 std::size_t size = calc_material_database_buffer_size(vMaterials);
402 std::vector<OSG::UInt8> buffer(size);
404 std::size_t ao = 0; // aligned offset
405 std::size_t bo = 0; // base offset
407 for (std::size_t i = 0; i < vMaterials.size(); ++i)
409 ao = align_offset(16, bo);
410 memcpy(&buffer[0] + ao, &vMaterials[i].ambient[0], sizeof(OSG::Color3f));
411 bo = ao + sizeof(OSG::Color4f);
413 ao = align_offset(16, bo);
414 memcpy(&buffer[0] + ao, &vMaterials[i].diffuse[0], sizeof(OSG::Color3f));
415 bo = ao + sizeof(OSG::Color4f);
417 ao = align_offset(16, bo);
418 memcpy(&buffer[0] + ao, &vMaterials[i].specular[0], sizeof(OSG::Color3f));
419 bo = ao + sizeof(OSG::Color4f);
421 ao = align_offset(16, bo);
422 memcpy(&buffer[0] + ao, &vMaterials[i].emissive[0], sizeof(OSG::Color3f));
423 bo = ao + sizeof(OSG::Color4f);
425 ao = align_offset( 4, bo);
426 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vMaterials[i].opacity;
427 bo = ao + sizeof(OSG::Real32);
429 ao = align_offset( 4, bo);
430 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vMaterials[i].shininess;
431 bo = ao + sizeof(OSG::Real32);
433 ao = align_offset( 16, bo); bo = ao; // padding
436 return buffer;
439 OSG::UniformBufferObjStd140ChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
441 OSG::UniformBufferObjStd140ChunkRefPtr ubo = OSG::UniformBufferObjStd140Chunk::create();
443 std::vector<OSG::UInt8> buffer = create_material_database_buffer(vMaterials);
445 ubo->editMFBuffer()->setValues(buffer);
446 ubo->setUsage(GL_STATIC_DRAW);
448 return OSG::UniformBufferObjStd140ChunkTransitPtr(ubo);
451 void update_material_database_state(OSG::UniformBufferObjStd140Chunk* ubo, const VecMaterialsT& vMaterials)
453 if (ubo) {
454 std::vector<OSG::UInt8> buffer = create_material_database_buffer(vMaterials);
455 ubo->editMFBuffer()->setValues(buffer);
460 // the geomertry uniform buffer object
462 std::size_t calc_geometry_material_buffer_size()
464 std::size_t ao = 0; // aligned offset
465 std::size_t bo = 0; // base offset
467 ao = align_offset( 4, bo); bo = ao + sizeof(OSG::UInt32); // OSG::UInt32 material_index;
468 ao = align_offset( 16, bo); bo = ao; // padding
470 return ao;
473 std::vector<OSG::UInt8> create_geometry_material_buffer(const GeomState& geom_state)
475 std::size_t size = calc_geometry_material_buffer_size();
477 std::vector<OSG::UInt8> buffer(size);
479 std::size_t ao = 0; // aligned offset
480 std::size_t bo = 0; // base offset
482 ao = align_offset( 4, bo);
483 *(reinterpret_cast<OSG::UInt32*>(&buffer[0] + ao)) = geom_state.material_index;
484 bo = ao + sizeof(OSG::UInt32);
486 return buffer;
489 OSG::UniformBufferObjStd140ChunkTransitPtr create_geometry_material_state(const GeomState& geom_state)
491 OSG::UniformBufferObjStd140ChunkRefPtr ubo = OSG::UniformBufferObjStd140Chunk::create();
493 std::vector<OSG::UInt8> buffer = create_geometry_material_buffer(geom_state);
495 ubo->editMFBuffer()->setValues(buffer);
496 ubo->setUsage(GL_DYNAMIC_DRAW);
498 return OSG::UniformBufferObjStd140ChunkTransitPtr(ubo);
501 void update_geometry_material_state(OSG::UniformBufferObjStd140Chunk* ubo, const GeomState& geom_state)
503 if (ubo) {
504 std::vector<OSG::UInt8> buffer = create_geometry_material_buffer(geom_state);
505 ubo->editMFBuffer()->setValues(buffer);
510 // vertex shader program.
512 std::string get_vp_program();
515 // fragment shader program for bump mapping in surface local coordinates
517 std::string get_fp_program();
520 // random number generator
522 boost::random::mt19937 generator;
523 boost::random::uniform_int_distribution<> dist(0, num_materials-1);
526 // a separate transformation for every object
528 OSG::TransformRefPtr cyltrans, tortrans;
531 // Uniform buffer objects corresponding to transient shader blocks
533 OSG::UniformBufferObjStd140ChunkRefPtr ubo_light_state = NULL;
534 OSG::UniformBufferObjStd140ChunkRefPtr ubo_geom_state_1 = NULL;
535 OSG::UniformBufferObjStd140ChunkRefPtr ubo_geom_state_2 = NULL;
538 // forward declaration so we can have the interesting stuff upfront
540 int setupGLUT(int *argc, char *argv[]);
543 // redraw the window
545 void display(void)
547 // light spot direction and light position must be provided in eye space
548 update_light_state(ubo_light_state, lights);
550 // create the matrix
551 OSG::Matrix m;
552 OSG::Real32 t = glutGet(GLUT_ELAPSED_TIME );
554 // set the transforms' matrices
555 m.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t / 1000.f) * 1.5),
556 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t / 500.f));
558 cyltrans->setMatrix(m);
560 m.setTransform(OSG::Vec3f(OSG::osgSin(t / 1000.f), 0, 0),
561 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t / 1000.f));
563 tortrans->setMatrix(m);
565 OSG::commitChanges();
567 mgr->redraw();
571 // Initialize GLUT & OpenSG and set up the scene
573 int main(int argc, char **argv)
575 // OSG init
576 OSG::osgInit(argc,argv);
578 // GLUT init
579 int winid = setupGLUT(&argc, argv);
581 // open a new scope, because the pointers below should go out of scope
582 // before entering glutMainLoop.
583 // Otherwise OpenSG will complain about objects being alive after shutdown.
585 // the connection between GLUT and OpenSG
586 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
587 gwin->setGlutId(winid);
588 gwin->init();
590 // create the SimpleSceneManager helper
591 mgr = OSG::SimpleSceneManager::create();
592 mgr->setWindow(gwin);
594 // create a pretty simple graph: a Group with two Transforms as children,
595 // each of which carries a single Geometry.
597 // The scene
599 OSG::NodeRefPtr scene = OSG::Node::create();
601 // The cylinder and its transformation
602 OSG::NodeRefPtr cyl = OSG::Node::create();
603 OSG::GeometryRefPtr cylgeo = OSG::makeCylinderGeo( 1.4f, .3f, 24,
604 true, true, true );
606 cyl->setCore(cylgeo);
608 cyltrans = OSG::Transform::create();
610 OSG::NodeRefPtr cyltransnode = OSG::Node::create();
611 cyltransnode->setCore (cyltrans);
612 cyltransnode->addChild(cyl );
614 // add it to the scene
615 scene->addChild(cyltransnode);
617 // The torus and its transformation
618 OSG::NodeRefPtr torus = OSG::Node::create();
619 OSG::GeometryRefPtr torusgeo = OSG::makeTorusGeo( .2f, 1, 24, 36 );
621 torus->setCore(torusgeo);
623 tortrans = OSG::Transform::create();
625 OSG::NodeRefPtr tortransnode = OSG::Node::create();
626 tortransnode->setCore (tortrans);
627 tortransnode->addChild(torus );
629 // add it to the scene
630 scene->addChild(tortransnode);
633 // create the shader program
635 OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
636 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
637 OSG::ShaderProgramRefPtr fragShader = OSG::ShaderProgram::createFragmentShader();
639 vertShader->setProgram(get_vp_program());
640 fragShader->setProgram(get_fp_program());
643 // binding the unifrom block to a buffer binding point can be performed
644 // either by calling the shaders's addUniformBlock method or by
645 // adding a 'uniform block' variable to a ShaderProgramVariableChunk.
646 // In the following we use both variants for illustration.
648 fragShader->addUniformBlock("Materials", 1); // block binding point
649 fragShader->addUniformBlock("Lights", 2); // block binding point
652 // The following is replaced by adding ShaderProgramVariableChunk objects
653 // to the chunk material. See below...
655 // fragShader->addUniformBlock("GeomState", 3); // block binding point
657 prog_chunk->addShader(vertShader);
658 prog_chunk->addShader(fragShader);
661 // create uniform buffer objects and corresponding materials
663 OSG::UniformBufferObjStd140ChunkRefPtr ubo_material_database = create_material_database_state(materials);
664 ubo_light_state = create_light_state(lights);
666 OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
667 polygon_chunk->setFrontMode(GL_FILL);
668 polygon_chunk->setBackMode(GL_FILL);
669 polygon_chunk->setCullFace(GL_NONE);
671 OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
672 depth_chunk->setEnable(true);
674 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
675 prog_state->addChunk(ubo_material_database, 1); // buffer binding point 1
676 prog_state->addChunk(ubo_light_state, 2); // buffer binding point 2
677 prog_state->addChunk(prog_chunk);
678 prog_state->addChunk(polygon_chunk);
679 prog_state->addChunk(depth_chunk);
681 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
682 shader_var_chunk->addUniformBlock("GeomState", 3);
684 GeomState geom1; geom1.material_index = dist(generator);
685 OSG::ChunkMaterialRefPtr geom1_state = OSG::ChunkMaterial::create();
686 ubo_geom_state_1 = create_geometry_material_state(geom1);
687 geom1_state->addChunk(ubo_geom_state_1, 3); // buffer binding point 3
688 geom1_state->addChunk(shader_var_chunk); // block binding point
690 GeomState geom2; geom2.material_index = dist(generator);
691 OSG::ChunkMaterialRefPtr geom2_state = OSG::ChunkMaterial::create();
692 ubo_geom_state_2 = create_geometry_material_state(geom2);
693 geom2_state->addChunk(ubo_geom_state_2, 3); // buffer binding point 3
694 geom2_state->addChunk(shader_var_chunk); // block binding point
696 cylgeo ->setMaterial(geom1_state);
697 torusgeo->setMaterial(geom2_state);
699 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
700 mgrp->setMaterial(prog_state);
701 scene->setCore(mgrp);
703 OSG::commitChanges();
705 mgr->setRoot(scene);
707 // show the whole scene
708 mgr->showAll();
711 // GLUT main loop
712 glutMainLoop();
714 return 0;
718 // GLUT callback functions
722 // react to size changes
724 void reshape(int w, int h)
726 mgr->resize(w, h);
727 glutPostRedisplay();
731 // react to mouse button presses
733 void mouse(int button, int state, int x, int y)
735 if (state)
736 mgr->mouseButtonRelease(button, x, y);
737 else
738 mgr->mouseButtonPress(button, x, y);
740 glutPostRedisplay();
744 // react to mouse motions with pressed buttons
746 void motion(int x, int y)
748 mgr->mouseMove(x, y);
749 glutPostRedisplay();
753 // react to keys
755 void keyboard(unsigned char k, int x, int y)
757 switch(k)
759 case 27:
761 // clean up global variables
762 cyltrans = NULL;
763 tortrans = NULL;
764 mgr = NULL;
766 ubo_light_state = NULL;
767 ubo_geom_state_1 = NULL;
768 ubo_geom_state_2 = NULL;
770 OSG::osgExit();
771 exit(0);
773 break;
775 case 'm':
777 GeomState geom1; geom1.material_index = dist(generator);
778 GeomState geom2; geom2.material_index = dist(generator);
780 update_geometry_material_state(ubo_geom_state_1, geom1);
781 update_geometry_material_state(ubo_geom_state_2, geom2);
783 glutPostRedisplay();
785 break;
787 case 's':
789 mgr->setStatistics(!mgr->getStatistics());
791 break;
796 // setup the GLUT library which handles the windows for us
798 int setupGLUT(int *argc, char *argv[])
800 glutInit(argc, argv);
801 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
803 int winid = glutCreateWindow("OpenSG");
805 glutReshapeFunc(reshape);
806 glutDisplayFunc(display);
807 glutMouseFunc(mouse);
808 glutMotionFunc(motion);
809 glutKeyboardFunc(keyboard);
811 // call the redraw function whenever there's nothing else to do
812 glutIdleFunc(display);
814 return winid;
818 // vertex shader program.
820 std::string get_vp_program()
822 std::string vp_program =
823 "\n"
824 "#version 330 compatibility\n"
825 "\n"
826 "#extension GL_ARB_separate_shader_objects: enable\n"
827 "#extension GL_ARB_uniform_buffer_object: enable\n"
828 "\n"
829 "smooth out vec3 vNormalES; // eye space normal\n"
830 "smooth out vec3 vPositionES; // eye space position\n"
831 "\n"
832 "void main()\n"
833 "{\n"
834 " //\n"
835 " // multiply the object space vertex position with the modelview matrix \n"
836 " // to get the eye space vertex position\n"
837 " //\n"
838 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
839 "\n"
840 " //\n"
841 " // multiply the object space normal with the normal matrix (transpose of the inverse \n"
842 " // model view matrix) to get the eye space normal\n"
843 " //\n"
844 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
845 "\n"
846 " //\n"
847 " // multiply the combiend modelview projection matrix with the object space vertex\n"
848 " // position to get the clip space position\n"
849 " //\n"
850 " gl_Position = ftransform();\n"
851 "}\n"
852 "\n"
855 return vp_program;
859 // fragment shader program for bump mapping in surface local coordinates
861 std::string get_fp_program()
863 std::string fp_program =
864 "\n"
865 "#version 330 compatibility\n"
866 "\n"
867 "#extension GL_ARB_separate_shader_objects: enable\n"
868 "#extension GL_ARB_uniform_buffer_object: enable\n"
869 "\n"
870 "smooth in vec3 vNormalES; // eye space normal\n"
871 "smooth in vec3 vPositionES; // eye space position\n"
872 "\n"
873 "const int num_lights = 1;\n"
874 "const int num_materials = 100;\n"
875 "\n"
876 "const int directional_light = 0;\n"
877 "const int point_light = 1;\n"
878 "const int spot_light = 2;\n"
879 "const int no_light = 3;\n"
880 "\n"
881 "struct Light\n"
882 "{\n"
883 " vec4 position; // in eye space\n"
884 " vec4 spot_direction; // in eye space\n"
885 "\n"
886 " vec4 Ia; // ambient max. Intensity\n"
887 " vec4 Id; // diffuse max. Intensity\n"
888 " vec4 Is; // specular max. Intensity\n"
889 "\n"
890 " vec4 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
891 " \n"
892 " float spot_cos_cutoff; // cosine cut of angle\n"
893 "\n"
894 " float spot_exponent; // [0-128]\n"
895 " int type; // directional_light, point_light, spot_light, no_light\n"
896 "};\n"
897 "\n"
898 "layout (std140) uniform Lights\n"
899 "{\n"
900 " Light light[num_lights];\n"
901 "} lights;\n"
902 "\n"
903 "struct Material\n"
904 "{\n"
905 " vec4 ambient;\n"
906 " vec4 diffuse;\n"
907 " vec4 specular;\n"
908 " vec4 emissive;\n"
909 "\n"
910 " float opacity;\n"
911 " float shininess;\n"
912 "};\n"
913 "\n"
914 "layout (std140) uniform Materials\n"
915 "{\n"
916 " Material material[num_materials];\n"
917 "} materials;\n"
918 "\n"
919 "\n"
920 "layout (std140) uniform GeomState\n"
921 "{\n"
922 " int material_index;\n"
923 "} geom_state;\n"
924 "\n"
925 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
926 "\n"
927 "layout(location = 0) out vec4 vFragColor;\n"
928 "\n"
929 "//\n"
930 "// directional light contribution\n"
931 "//\n"
932 "vec3 directionalLight(\n"
933 " in int i, // light identifier, i.e. current light\n"
934 " in int j, // material identifier\n"
935 " in vec3 n, // vertex normal in eye space\n"
936 " in vec3 v) // view direction in eye space\n"
937 "{\n"
938 " if (lights.light[i].type != directional_light)\n"
939 " return vec3(0.0, 0.0, 0.0);\n"
940 "\n"
941 " //\n"
942 " // the light direction in eye space\n"
943 " //\n"
944 " vec3 l = -lights.light[i].spot_direction.xyz; // we carry the directional light direction in the spot_direction slot\n"
945 "\n"
946 " //\n"
947 " // the half vector\n"
948 " //\n"
949 " vec3 h = normalize(l + v);\n"
950 "\n"
951 " float n_dot_l = max(0.0, dot(n, l));\n"
952 " float n_dot_h = max(0.0, dot(n, h));\n"
953 "\n"
954 " float m = materials.material[j].shininess;\n"
955 "\n"
956 " float pf; // power factor\n"
957 "\n"
958 " if (n_dot_l == 0.0)\n"
959 " pf = 0.0;\n"
960 " else\n"
961 " pf = pow(n_dot_h, m);\n"
962 "\n"
963 " return materials.material[j].emissive.rgb \n"
964 " + lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
965 " + lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
966 " + lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
967 "}\n"
968 "\n"
969 "//\n"
970 "// point light contribution\n"
971 "//\n"
972 "vec3 pointLight(\n"
973 " in int i, // light identifier, i.e. current light\n"
974 " in int j, // material identifier\n"
975 " in vec3 n, // vertex normal in eye space\n"
976 " in vec3 v, // view direction in eye space\n"
977 " in vec3 p) // vertex position in eye space\n"
978 "{\n"
979 " if (lights.light[i].type != point_light)\n"
980 " return vec3(0.0, 0.0, 0.0);\n"
981 "\n"
982 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
983 " float d = length(l); // distance from surface to light source\n"
984 " l = normalize(l); // normalized direction from surface to light position\n"
985 "\n"
986 " //\n"
987 " // the half vector\n"
988 " //\n"
989 " vec3 h = normalize(l + v);\n"
990 "\n"
991 " float n_dot_l = max(0.0, dot(n, l));\n"
992 " float n_dot_h = max(0.0, dot(n, h));\n"
993 "\n"
994 " float m = materials.material[j].shininess;\n"
995 "\n"
996 " float pf; // power factor\n"
997 "\n"
998 " if (n_dot_l == 0.0)\n"
999 " pf = 0.0;\n"
1000 " else\n"
1001 " pf = pow(n_dot_h, m);\n"
1002 "\n"
1003 " //\n"
1004 " // Compute attenuation\n"
1005 " //\n"
1006 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1007 " (lights.light[i].attenuation.y * d) + \n"
1008 " (lights.light[i].attenuation.z * d * d));\n"
1009 "\n"
1010 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1011 "\n"
1012 " return materials.material[j].emissive.rgb \n"
1013 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1014 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1015 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1016 "}\n"
1017 "\n"
1018 "//\n"
1019 "// spot light contribution\n"
1020 "//\n"
1021 "vec3 spotLight(\n"
1022 " in int i, // light identifier, i.e. current light\n"
1023 " in int j, // material identifier\n"
1024 " in vec3 n, // vertex normal in eye space\n"
1025 " in vec3 v, // view direction in eye space\n"
1026 " in vec3 p) // vertex position in eye space\n"
1027 "{\n"
1028 " if (lights.light[i].type != spot_light)\n"
1029 " return vec3(0.0, 0.0, 0.0);\n"
1030 "\n"
1031 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1032 " float d = length(l); // distance from surface to light source\n"
1033 " l = normalize(l); // normalized direction from surface to light position\n"
1034 " \n"
1035 " vec3 s = lights.light[i].spot_direction.xyz; // spot direction\n"
1036 "\n"
1037 " //\n"
1038 " // the half vector\n"
1039 " //\n"
1040 " vec3 h = normalize(l + v);\n"
1041 "\n"
1042 " float n_dot_l = max(0.0, dot(n, l));\n"
1043 " float n_dot_h = max(0.0, dot(n, h));\n"
1044 " float l_dot_s = dot(-l, s);\n"
1045 "\n"
1046 " float m = materials.material[j].shininess;\n"
1047 "\n"
1048 " float pf; // power factor\n"
1049 "\n"
1050 " if (n_dot_l == 0.0)\n"
1051 " pf = 0.0;\n"
1052 " else\n"
1053 " pf = pow(n_dot_h, m);\n"
1054 "\n"
1055 " //\n"
1056 " // Compute attenuation\n"
1057 " //\n"
1058 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1059 " (lights.light[i].attenuation.y * d) + \n"
1060 " (lights.light[i].attenuation.z * d * d));\n"
1061 "\n"
1062 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1063 "\n"
1064 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
1065 " attenuation = 0.0;\n"
1066 " else\n"
1067 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\n"
1068 "\n"
1069 " return materials.material[j].emissive.rgb \n"
1070 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1071 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1072 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1073 "}\n"
1074 "\n"
1075 "void main()\n"
1076 "{\n"
1077 " //\n"
1078 " // normalize the eye space normal\n"
1079 " //\n"
1080 " vec3 N = normalize(vNormalES);\n"
1081 "\n"
1082 " //\n"
1083 " // get the view vector and normalize it\n"
1084 " //\n"
1085 " vec3 V = normalize(cCameraPositionES - vPositionES);\n"
1086 "\n"
1087 " //\n"
1088 " // Integrate over all lights: Any unused light does not contribute and each light\n"
1089 " // contribute either from the directional light, the point light or the spot light.\n"
1090 " //\n"
1091 " vec3 color = vec3(0.0, 0.0, 0.0);\n"
1092 " for (int i = 0; i < num_lights; ++i) {\n"
1093 " color += directionalLight(i, geom_state.material_index, N, V) \n"
1094 " + pointLight(i, geom_state.material_index, N, V, vPositionES) \n"
1095 " + spotLight(i, geom_state.material_index, N, V, vPositionES);\n"
1096 " }\n"
1097 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"
1098 "}\n"
1099 "\n"
1102 return fp_program;