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.
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,
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
33 #include <OSGConfig.h>
34 #include <OSGSimpleGeometry.h>
35 #include <OSGGLUTWindow.h>
36 #include <OSGSimpleSceneManager.h>
37 #include <OSGBaseFunctions.h>
38 #include <OSGTransform.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>
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>
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>
80 // The SimpleSceneManager to manage simple applications
82 OSG::SimpleSceneManagerRefPtr mgr
;
85 // simple light data structure
91 directional_light
= 0,
98 : position(0.f
, 0.f
, 0.f
)
99 , spot_direction(0.f
, 1.f
, 0.f
)
103 , attenuation(1.f
, 0.f
, 0.f
)
104 , spot_cos_cutoff(cosf(45.f
))
109 static Light
create_light(Type e
)
115 case directional_light
: l
.spot_direction
= OSG::Vec3f(1.f
, 0.f
, 0.f
);
117 case point_light
: l
.position
= OSG::Pnt3f(0.f
, 0.2f
, 0.f
);
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
;
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
147 lights
.push_back(Light::create_light(Light::directional_light
));
149 assert(lights
.size() == num_lights
);
154 VecLightsT lights
= initialize_lights(); // the lights
158 // Simple material data structure
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
)
171 OSG::Color3f ambient
;
172 OSG::Color3f diffuse
;
173 OSG::Color3f specular
;
174 OSG::Color3f emissive
;
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
)
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
);
197 materials
.push_back(m
);
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
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)
235 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
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
);
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)
258 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
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
);
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
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
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
)
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
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
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
)
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
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
);
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
)
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
[]);
547 // light spot direction and light position must be provided in eye space
548 update_light_state(ubo_light_state
, lights
);
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();
571 // Initialize GLUT & OpenSG and set up the scene
573 int main(int argc
, char **argv
)
576 OSG::osgInit(argc
,argv
);
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
);
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.
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,
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();
707 // show the whole scene
718 // GLUT callback functions
722 // react to size changes
724 void reshape(int w
, int h
)
731 // react to mouse button presses
733 void mouse(int button
, int state
, int x
, int y
)
736 mgr
->mouseButtonRelease(button
, x
, y
);
738 mgr
->mouseButtonPress(button
, x
, y
);
744 // react to mouse motions with pressed buttons
746 void motion(int x
, int y
)
748 mgr
->mouseMove(x
, y
);
755 void keyboard(unsigned char k
, int x
, int y
)
761 // clean up global variables
766 ubo_light_state
= NULL
;
767 ubo_geom_state_1
= NULL
;
768 ubo_geom_state_2
= NULL
;
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
);
789 mgr
->setStatistics(!mgr
->getStatistics());
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
);
818 // vertex shader program.
820 std::string
get_vp_program()
822 std::string vp_program
=
824 "#version 330 compatibility\n"
826 "#extension GL_ARB_separate_shader_objects: enable\n"
827 "#extension GL_ARB_uniform_buffer_object: enable\n"
829 "smooth out vec3 vNormalES; // eye space normal\n"
830 "smooth out vec3 vPositionES; // eye space position\n"
835 " // multiply the object space vertex position with the modelview matrix \n"
836 " // to get the eye space vertex position\n"
838 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\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"
844 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
847 " // multiply the combiend modelview projection matrix with the object space vertex\n"
848 " // position to get the clip space position\n"
850 " gl_Position = ftransform();\n"
859 // fragment shader program for bump mapping in surface local coordinates
861 std::string
get_fp_program()
863 std::string fp_program
=
865 "#version 330 compatibility\n"
867 "#extension GL_ARB_separate_shader_objects: enable\n"
868 "#extension GL_ARB_uniform_buffer_object: enable\n"
870 "smooth in vec3 vNormalES; // eye space normal\n"
871 "smooth in vec3 vPositionES; // eye space position\n"
873 "const int num_lights = 1;\n"
874 "const int num_materials = 100;\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"
883 " vec4 position; // in eye space\n"
884 " vec4 spot_direction; // in eye space\n"
886 " vec4 Ia; // ambient max. Intensity\n"
887 " vec4 Id; // diffuse max. Intensity\n"
888 " vec4 Is; // specular max. Intensity\n"
890 " vec4 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
892 " float spot_cos_cutoff; // cosine cut of angle\n"
894 " float spot_exponent; // [0-128]\n"
895 " int type; // directional_light, point_light, spot_light, no_light\n"
898 "layout (std140) uniform Lights\n"
900 " Light light[num_lights];\n"
911 " float shininess;\n"
914 "layout (std140) uniform Materials\n"
916 " Material material[num_materials];\n"
920 "layout (std140) uniform GeomState\n"
922 " int material_index;\n"
925 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
927 "layout(location = 0) out vec4 vFragColor;\n"
930 "// directional light contribution\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"
938 " if (lights.light[i].type != directional_light)\n"
939 " return vec3(0.0, 0.0, 0.0);\n"
942 " // the light direction in eye space\n"
944 " vec3 l = -lights.light[i].spot_direction.xyz; // we carry the directional light direction in the spot_direction slot\n"
947 " // the half vector\n"
949 " vec3 h = normalize(l + v);\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"
954 " float m = materials.material[j].shininess;\n"
956 " float pf; // power factor\n"
958 " if (n_dot_l == 0.0)\n"
961 " pf = pow(n_dot_h, m);\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"
970 "// point light contribution\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"
979 " if (lights.light[i].type != point_light)\n"
980 " return vec3(0.0, 0.0, 0.0);\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"
987 " // the half vector\n"
989 " vec3 h = normalize(l + v);\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"
994 " float m = materials.material[j].shininess;\n"
996 " float pf; // power factor\n"
998 " if (n_dot_l == 0.0)\n"
1001 " pf = pow(n_dot_h, m);\n"
1004 " // Compute attenuation\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"
1010 " attenuation = clamp(attenuation, 0.0, 1.0);\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"
1019 "// spot light contribution\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"
1028 " if (lights.light[i].type != spot_light)\n"
1029 " return vec3(0.0, 0.0, 0.0);\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"
1035 " vec3 s = lights.light[i].spot_direction.xyz; // spot direction\n"
1038 " // the half vector\n"
1040 " vec3 h = normalize(l + v);\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"
1046 " float m = materials.material[j].shininess;\n"
1048 " float pf; // power factor\n"
1050 " if (n_dot_l == 0.0)\n"
1053 " pf = pow(n_dot_h, m);\n"
1056 " // Compute attenuation\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"
1062 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1064 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
1065 " attenuation = 0.0;\n"
1067 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\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"
1078 " // normalize the eye space normal\n"
1080 " vec3 N = normalize(vNormalES);\n"
1083 " // get the view vector and normalize it\n"
1085 " vec3 V = normalize(cCameraPositionES - vPositionES);\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"
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"
1097 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"