1 // OpenSG Tutorial Example: UniformBufferObject
3 // This example shows how to create a shader uniform block and binding it
4 // to a uniform buffer object.
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.
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.
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,
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
38 #include <OSGConfig.h>
39 #include <OSGSimpleGeometry.h>
40 #include <OSGGLUTWindow.h>
41 #include <OSGSimpleSceneManager.h>
42 #include <OSGBaseFunctions.h>
43 #include <OSGTransform.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>
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>
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>
83 // The SimpleSceneManager to manage simple applications
85 OSG::SimpleSceneManagerRefPtr mgr
;
88 // simple light data structure
94 directional_light
= 0,
101 : position(0.f
, 0.f
, 0.f
)
102 , spot_direction(0.f
, 1.f
, 0.f
)
106 , attenuation(1.f
, 0.f
, 0.f
)
107 , spot_cos_cutoff(cosf(45.f
))
112 static Light
create_light(Type e
)
118 case directional_light
: l
.spot_direction
= OSG::Vec3f(1.f
, 0.f
, 0.f
);
120 case point_light
: l
.position
= OSG::Pnt3f(0.f
, 0.2f
, 0.f
);
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
;
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
150 lights
.push_back(Light::create_light(Light::directional_light
));
152 assert(lights
.size() == num_lights
);
157 VecLightsT lights
= initialize_lights(); // the lights
160 // Simple material data structure
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
)
173 OSG::Color3f ambient
;
174 OSG::Color3f diffuse
;
175 OSG::Color3f specular
;
176 OSG::Color3f emissive
;
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
)
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
);
199 materials
.push_back(m
);
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
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)
237 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
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
);
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)
260 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
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
);
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
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
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
)
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
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
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
)
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
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
);
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
)
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
[]);
549 // light spot direction and light position must be provided in eye space
550 update_light_state(ubo_light_state
, lights
);
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();
573 // Initialize GLUT & OpenSG and set up the scene
575 int main(int argc
, char **argv
)
578 OSG::osgInit(argc
,argv
);
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
);
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.
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,
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();
693 // show the whole scene
704 // GLUT callback functions
708 // react to size changes
710 void reshape(int w
, int h
)
717 // react to mouse button presses
719 void mouse(int button
, int state
, int x
, int y
)
722 mgr
->mouseButtonRelease(button
, x
, y
);
724 mgr
->mouseButtonPress(button
, x
, y
);
730 // react to mouse motions with pressed buttons
732 void motion(int x
, int y
)
734 mgr
->mouseMove(x
, y
);
741 void keyboard(unsigned char k
, int x
, int y
)
747 // clean up global variables
752 ubo_light_state
= NULL
;
753 ubo_geom_state_1
= NULL
;
754 ubo_geom_state_2
= NULL
;
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
);
775 mgr
->setStatistics(!mgr
->getStatistics());
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
);
804 // vertex shader program.
806 std::string
get_vp_program()
808 std::string vp_program
=
810 "#version 330 compatibility\n"
812 "#extension GL_ARB_separate_shader_objects: enable\n"
813 "#extension GL_ARB_uniform_buffer_object: enable\n"
815 "smooth out vec3 vNormalES; // eye space normal\n"
816 "smooth out vec3 vPositionES; // eye space position\n"
821 " // multiply the object space vertex position with the modelview matrix \n"
822 " // to get the eye space vertex position\n"
824 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\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"
830 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
833 " // multiply the combiend modelview projection matrix with the object space vertex\n"
834 " // position to get the clip space position\n"
836 " gl_Position = ftransform();\n"
845 // fragment shader program for bump mapping in surface local coordinates
847 std::string
get_fp_program()
849 std::string fp_program
=
851 "#version 330 compatibility\n"
853 "#extension GL_ARB_separate_shader_objects: enable\n"
854 "#extension GL_ARB_uniform_buffer_object: enable\n"
856 "smooth in vec3 vNormalES; // eye space normal\n"
857 "smooth in vec3 vPositionES; // eye space position\n"
859 "const int num_lights = 1;\n"
860 "const int num_materials = 100;\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"
869 " vec4 position; // in eye space\n"
870 " vec4 spot_direction; // in eye space\n"
872 " vec4 Ia; // ambient max. Intensity\n"
873 " vec4 Id; // diffuse max. Intensity\n"
874 " vec4 Is; // specular max. Intensity\n"
876 " vec4 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
878 " float spot_cos_cutoff; // cosine cut of angle\n"
880 " float spot_exponent; // [0-128]\n"
881 " int type; // directional_light, point_light, spot_light, no_light\n"
884 "layout (std140) uniform Lights\n"
886 " Light light[num_lights];\n"
897 " float shininess;\n"
900 "layout (std140) uniform Materials\n"
902 " Material material[num_materials];\n"
906 "layout (std140) uniform GeomState\n"
908 " int material_index;\n"
911 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
913 "layout(location = 0) out vec4 vFragColor;\n"
916 "// directional light contribution\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"
924 " if (lights.light[i].type != directional_light)\n"
925 " return vec3(0.0, 0.0, 0.0);\n"
928 " // the light direction in eye space\n"
930 " vec3 l = -lights.light[i].spot_direction.xyz; // we carry the directional light direction in the spot_direction slot\n"
933 " // the half vector\n"
935 " vec3 h = normalize(l + v);\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"
940 " float m = materials.material[j].shininess;\n"
942 " float pf; // power factor\n"
944 " if (n_dot_l == 0.0)\n"
947 " pf = pow(n_dot_h, m);\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"
956 "// point light contribution\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"
965 " if (lights.light[i].type != point_light)\n"
966 " return vec3(0.0, 0.0, 0.0);\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"
973 " // the half vector\n"
975 " vec3 h = normalize(l + v);\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"
980 " float m = materials.material[j].shininess;\n"
982 " float pf; // power factor\n"
984 " if (n_dot_l == 0.0)\n"
987 " pf = pow(n_dot_h, m);\n"
990 " // Compute attenuation\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"
996 " attenuation = clamp(attenuation, 0.0, 1.0);\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"
1005 "// spot light contribution\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"
1014 " if (lights.light[i].type != spot_light)\n"
1015 " return vec3(0.0, 0.0, 0.0);\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"
1021 " vec3 s = lights.light[i].spot_direction.xyz; // spot direction\n"
1024 " // the half vector\n"
1026 " vec3 h = normalize(l + v);\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"
1032 " float m = materials.material[j].shininess;\n"
1034 " float pf; // power factor\n"
1036 " if (n_dot_l == 0.0)\n"
1039 " pf = pow(n_dot_h, m);\n"
1042 " // Compute attenuation\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"
1048 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1050 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
1051 " attenuation = 0.0;\n"
1053 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\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"
1064 " // normalize the eye space normal\n"
1066 " vec3 N = normalize(vNormalES);\n"
1069 " // get the view vector and normalize it\n"
1071 " vec3 V = normalize(cCameraPositionES - vPositionES);\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"
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"
1083 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"