1 // OpenSG Tutorial Example: ShaderStorageBufferObject
3 // This example shows how to create a shader buffer block and binding it
4 // to a shader storage buffer object.
6 // The example does use the ShaderStorageBufferObjStdLayoutChunk which
7 // allows the host application to directly provide a buffer to the chunk
8 // according to the std140 or std430 specification. Which specification
9 // is used is determined by the buffer block layout declaration in the
12 // This example uses solely the std140 layout.
14 // We create a simple scene geometry consisting of a cylinder and a
15 // torus. The materials for these objects are indexed from a material
16 // database. The indices are part of the material state of the objects.
17 // In particular, the geometry objects do have chunk materials with
18 // exactly one ShaderStorageBufferObjStdLayoutChunk each, which only
19 // contain the index into the material database.
20 // The material database itself is also a ShaderStorageBufferObjStd-
21 // LayoutChunk as well as the active lights of the scene. These are
22 // added globally with the help of a MaterialChunkOverrideGroup for
23 // all geometry of the scene.
25 // Additionally, a ShaderStorageBufferObjStdLayoutChunk is also
26 // added to the MaterialChunkOverrideGroup that does access a shader
27 // storage test block with the same layout as in the OpenGL std140
28 // specification. The shader does check the content of this block.
29 // If the content is invalid the complete fragement color is switched
30 // to plain red, indicating an error.
33 // In real life one would probably not use a shader storage buffer
34 // for the geometry material index state. But this example should
35 // only use a couple of shader storage buffers for illustration
38 // Shader Storage buffer objects in this example:
39 // test block -> added to the MaterialChunkOverrideGroup
40 // material database -> added to the MaterialChunkOverrideGroup
41 // lights -> added to the MaterialChunkOverrideGroup
42 // geom (indices) states -> added to geometry material
44 // The example is roughly grouped into five parts:
46 // Part I: Declaration of structurs corresponding to buffer blocks in the shader.
47 // Part II: Some helper functions.
48 // Part III: Memory buffer handling and creation routines.
49 // Part IV: The main example application.
50 // Part V: The shader programs.
53 #include <boost/random/mersenne_twister.hpp>
54 #include <boost/random/uniform_int_distribution.hpp>
56 #ifdef OSG_BUILD_ACTIVE
59 #include <OSGConfig.h>
60 #include <OSGSimpleGeometry.h>
61 #include <OSGGLUTWindow.h>
62 #include <OSGSimpleSceneManager.h>
63 #include <OSGBaseFunctions.h>
64 #include <OSGTransform.h>
69 #include <OSGShaderProgramChunk.h>
70 #include <OSGShaderProgram.h>
71 #include <OSGShaderVariableOSG.h>
72 #include <OSGChunkMaterial.h>
73 #include <OSGMaterialGroup.h>
74 #include <OSGMaterialChunkOverrideGroup.h>
75 #include <OSGShaderStorageBufferObjStdLayoutChunk.h>
76 #include <OSGPolygonChunk.h>
77 #include <OSGDepthChunk.h>
78 #include <OSGShaderProgramVariableChunk.h>
82 #include <OpenSG/OSGGLUT.h>
83 #include <OpenSG/OSGConfig.h>
84 #include <OpenSG/OSGSimpleGeometry.h>
85 #include <OpenSG/OSGGLUTWindow.h>
86 #include <OpenSG/OSGSimpleSceneManager.h>
87 #include <OpenSG/OSGBaseFunctions.h>
88 #include <OpenSG/OSGTransform.h>
89 #include <OpenSG/OSGGroup.h>
92 #include <OpenSG/OSGGLEXT.h>
93 #include <OpenSG/OSGShaderProgramChunk.h>
94 #include <OpenSG/OSGShaderProgram.h>
95 #include <OpenSG/OSGShaderVariableOSG.h>
96 #include <OpenSG/OSGChunkMaterial.h>
97 #include <OpenSG/OSGMaterialGroup.h>
98 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
99 #include <OpenSG/OSGShaderStorageBufferObjStdLayoutChunk.h>
100 #include <OpenSG/OSGPolygonChunk.h>
101 #include <OpenSG/OSGDepthChunk.h>
102 #include <OpenSG/OSGShaderProgramVariableChunk.h>
106 // The SimpleSceneManager to manage simple applications
108 OSG::SimpleSceneManagerRefPtr mgr
;
111 // Part I: Declaration of
113 // struct Light and type VecLightsT,
114 // struct Material and type VecMaterialsT,
116 // and corresponding initialization routines.
120 // The OpenGL std140 specification test block
121 // Remark: Since OpenSG does not have a Matrix3f or a Matrix2x3f which
122 // are used in the specification, we provide dummy structs for
204 TestBlock
initialize_test_block()
206 TestBlock test_block
;
208 test_block
.a
= 27.4f
;
209 test_block
.b
= OSG::Vec2f(15.3f
, 12.8f
);
210 test_block
.c
= OSG::Vec3f(11.4f
, 21.9f
, 10.5f
);
213 test_block
.f
.e
= OSG::Vec2b(true, false);
215 test_block
.g
= 57.3f
;
217 test_block
.h
[0] = 9.1f
;
218 test_block
.h
[1] = 17.56f
;
220 test_block
.i
.row1
= OSG::Vec3f(19.43f
, 1243.2f
, 0.56f
);
221 test_block
.i
.row2
= OSG::Vec3f(13.54f
, 264.22f
, 65.52f
);
223 test_block
.o
[0].j
= OSG::Vec3u(10, 11, 12);
224 test_block
.o
[0].k
= OSG::Vec2f(64.62f
, 275.21f
);
225 test_block
.o
[0].l
[0] = 41.346f
;
226 test_block
.o
[0].l
[1] = 67.9456f
;
227 test_block
.o
[0].m
= OSG::Vec2f(-56.62f
, 768.276f
);
228 test_block
.o
[0].n
[0].row1
= OSG::Vec3f(-0.4f
,-0.5f
,-0.6f
);
229 test_block
.o
[0].n
[0].row2
= OSG::Vec3f(-0.7f
,-0.8f
,-0.9f
);
230 test_block
.o
[0].n
[0].row3
= OSG::Vec3f(-0.1f
,-0.2f
,-0.3f
);
231 test_block
.o
[0].n
[1].row1
= OSG::Vec3f( 1.1f
, 2.2f
, 3.3f
);
232 test_block
.o
[0].n
[1].row2
= OSG::Vec3f( 1.2f
, 2.3f
, 3.4f
);
233 test_block
.o
[0].n
[1].row3
= OSG::Vec3f( 1.3f
, 2.4f
, 3.5f
);
235 test_block
.o
[1].j
= OSG::Vec3u(20, 31, 42);
236 test_block
.o
[1].k
= OSG::Vec2f(-96.62f
,-658.456f
);
237 test_block
.o
[1].l
[0] = 88.34f
;
238 test_block
.o
[1].l
[1] = -488.21f
;
239 test_block
.o
[1].m
= OSG::Vec2f(777.7f
, 888.8f
);
240 test_block
.o
[1].n
[0].row1
= OSG::Vec3f( 1.1f
, 1.2f
, 1.3f
);
241 test_block
.o
[1].n
[0].row2
= OSG::Vec3f( 2.1f
, 2.2f
, 2.3f
);
242 test_block
.o
[1].n
[0].row3
= OSG::Vec3f( 3.1f
, 3.2f
, 3.3f
);
243 test_block
.o
[1].n
[1].row1
= OSG::Vec3f(-1.1f
,-1.2f
,-1.3f
);
244 test_block
.o
[1].n
[1].row2
= OSG::Vec3f(-2.1f
,-2.2f
,-2.3f
);
245 test_block
.o
[1].n
[1].row3
= OSG::Vec3f(-3.1f
,-3.2f
,-3.3f
);
250 TestBlock global_test_block
= initialize_test_block();
253 // simple light data structure
259 directional_light
= 0,
266 : position(0.f
, 0.f
, 0.f
)
267 , spot_direction(0.f
, 1.f
, 0.f
)
271 , attenuation(1.f
, 0.f
, 0.f
)
272 , spot_cos_cutoff(cosf(45.f
))
277 static Light
create_light(Type e
)
283 case directional_light
: l
.spot_direction
= OSG::Vec3f(1.f
, 0.f
, 0.f
);
285 case point_light
: l
.position
= OSG::Pnt3f(0.f
, 0.2f
, 0.f
);
287 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
;
295 OSG::Pnt3f position
; // in object space
296 OSG::Vec3f spot_direction
; // in object space, also used for dir of directional lights (see shader code)
297 OSG::Color3f Ia
; // ambient max. Intensity
298 OSG::Color3f Id
; // diffuse max. Intensity
299 OSG::Color3f Is
; // specular max. Intensity
301 OSG::Vec3f attenuation
; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0
302 OSG::Real32 spot_cos_cutoff
; // cosine cut of angle
303 OSG::Real32 spot_exponent
; // [0-128]
304 OSG::Int32 type
; // directional_light, point_light, spot_light, no_light
307 typedef std::vector
<Light
> VecLightsT
; // multiple lights
309 const std::size_t num_lights
= 1; // simple example with just one light
311 VecLightsT
initialize_lights() // helper to create lights
315 lights
.push_back(Light::create_light(Light::directional_light
));
317 assert(lights
.size() == num_lights
);
322 VecLightsT lights
= initialize_lights(); // the lights
326 // Simple material data structure
331 : ambient (0.f
, 0.f
, 0.f
)
332 , diffuse (0.f
, 0.f
, 0.f
)
333 , specular(0.f
, 0.f
, 0.f
)
334 , emissive(0.f
, 0.f
, 0.f
)
339 OSG::Color3f ambient
;
340 OSG::Color3f diffuse
;
341 OSG::Color3f specular
;
342 OSG::Color3f emissive
;
345 OSG::Real32 shininess
;
348 typedef std::vector
<Material
> VecMaterialsT
; // multiple materials
350 VecMaterialsT
initialize_materials(std::size_t num
) // helper to create materials
352 VecMaterialsT materials
;
354 for (std::size_t i
= 0; i
< num
; ++i
)
358 m
.ambient
= OSG::Color3f(0.1f
, 0.1f
, 0.1f
);
359 m
.diffuse
.setRandom();
360 m
.specular
= OSG::Color3f(0.9f
, 0.9f
, 0.9f
);
361 m
.emissive
= OSG::Color3f(0.0f
, 0.0f
, 0.0f
);
365 materials
.push_back(m
);
371 const std::size_t num_materials
= 500; // any number of materials
372 VecMaterialsT materials
= initialize_materials(num_materials
); // the material database
376 // Simple geometry state data structure
384 OSG::UInt32 material_index
;
389 // Part II: Some helper functions:
390 // Pnt3f transform_to_eye_space(const Pnt3f& p, SimpleSceneManager* pSSM)
391 // Vec3f transform_to_eye_space(const Vec3f& v, SimpleSceneManager* pSSM)
392 // size_t align_offset (size_t base_alignment, size_t base_offset)
396 // transform point from world space to eye space
398 OSG::Pnt3f
transform_to_eye_space(const OSG::Pnt3f
& p
, OSG::SimpleSceneManager
* pSSM
)
400 if (!pSSM
|| !pSSM
->getWindow() || pSSM
->getWindow()->getMFPort()->size() == 0)
403 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
408 OSG::Int16 width
= pPort
->calcPixelWidth();
409 OSG::Int16 height
= pPort
->calcPixelHeight();
411 pPort
->getCamera()->getViewing(view
, width
, height
);
413 view
.multFull( p
, p_es
);
419 // transform vector from world space to eye space
421 OSG::Vec3f
transform_to_eye_space(const OSG::Vec3f
& v
, OSG::SimpleSceneManager
* pSSM
)
423 if (!pSSM
|| !pSSM
->getWindow() || pSSM
->getWindow()->getMFPort()->size() == 0)
426 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
431 OSG::Int16 width
= pPort
->calcPixelWidth();
432 OSG::Int16 height
= pPort
->calcPixelHeight();
434 pPort
->getCamera()->getViewing(view
, width
, height
);
436 view
.multFull( v
, v_es
);
442 // helper to calculate the correct buffer insert positions on std140 or std430
444 std::size_t align_offset(std::size_t base_alignment
, std::size_t base_offset
)
446 return base_alignment
* ((base_alignment
+ base_offset
- 1) / base_alignment
);
451 // Part III: Some routines for handling of the memory buffer and the the creation of
452 // the ShaderStorageBufferObjStdLayoutChunk objects:
454 // i) calc_test_block_buffer_size,
455 // create_test_block_buffer,
456 // create_test_block_state,
457 // update_test_block_state
459 // ii) calc_light_buffer_size,
460 // create_light_buffer,
461 // create_light_state,
462 // update_light_state
464 // iii) calc_material_database_buffer_size,
465 // create_material_database_buffer,
466 // create_material_database_state,
467 // update_material_database_state
469 // iv) calc_geometry_material_buffer_size,
470 // create_geometry_material_buffer,
471 // create_geometry_material_state,
472 // update_geometry_material_state
476 // i) the test block shader storage buffer object
478 std::size_t calc_test_block_buffer_size(const TestBlock
& test_block
)
481 // Introduction to the std140 storage layout
482 // =========================================
484 // When using the "std140" storage layout, structures will be laid out in
485 // buffer storage with its members stored in monotonically increasing order
486 // based on their location in the declaration. A structure and each
487 // structure member have a base offset and a base alignment, from which an
488 // aligned offset is computed by rounding the base offset up to a multiple of
489 // the base alignment. The base offset of the first member of a structure is
490 // taken from the aligned offset of the structure itself. The base offset of
491 // all other structure members is derived by taking the offset of the last
492 // basic machine unit consumed by the previous member and adding one. Each
493 // structure member is stored in memory at its aligned offset. The members
494 // of a top-level shader storage block are laid out in buffer storage by treating
495 // the shader storage block as a structure with a base offset of zero.
497 // (1) If the member is a scalar consuming <N> basic machine units, the
498 // base alignment is <N>.
500 // (2) If the member is a two- or four-component vector with components
501 // consuming <N> basic machine units, the base alignment is 2<N> or
502 // 4<N>, respectively.
504 // (3) If the member is a three-component vector with components consuming
505 // <N> basic machine units, the base alignment is 4<N>.
507 // (4) If the member is an array of scalars or vectors, the base alignment
508 // and array stride are set to match the base alignment of a single
509 // array element, according to rules (1), (2), and (3), and rounded up
510 // to the base alignment of a vec4. The array may have padding at the
511 // end; the base offset of the member following the array is rounded up
512 // to the next multiple of the base alignment.
514 // (5) If the member is a column-major matrix with <C> columns and <R>
515 // rows, the matrix is stored identically to an array of <C> column
516 // vectors with <R> components each, according to rule (4).
518 // (6) If the member is an array of <S> column-major matrices with <C>
519 // columns and <R> rows, the matrix is stored identically to a row of
520 // <S>*<C> column vectors with <R> components each, according to rule
523 // (7) If the member is a row-major matrix with <C> columns and <R> rows,
524 // the matrix is stored identically to an array of <R> row vectors
525 // with <C> components each, according to rule (4).
527 // (8) If the member is an array of <S> row-major matrices with <C> columns
528 // and <R> rows, the matrix is stored identically to a row of <S>*<R>
529 // row vectors with <C> components each, according to rule (4).
531 // (9) If the member is a structure, the base alignment of the structure is
532 // <N>, where <N> is the largest base alignment value of any of its
533 // members, and rounded up to the base alignment of a vec4. The
534 // individual members of this sub-structure are then assigned offsets
535 // by applying this set of rules recursively, where the base offset of
536 // the first member of the sub-structure is equal to the aligned offset
537 // of the structure. The structure may have padding at the end; the
538 // base offset of the member following the sub-structure is rounded up
539 // to the next multiple of the base alignment of the structure.
541 // (10) If the member is an array of <S> structures, the <S> elements of
542 // the array are laid out in order, according to rule (9).
544 // For shader storage blocks laid out according to these rules, the minimum buffer
545 // object size returned by the GL_BUFFER_DATA_SIZE query is derived by
546 // taking the offset of the last basic machine unit consumed by the last
547 // entry of the shader storage block (including any end-of-array or
548 // end-of-structure padding), adding one, and rounding up to the next
549 // multiple of the base alignment required for a vec4.
551 // Using Standard Layout Qualifiers
552 // ================================
553 // When you group a number of variables in a uniform buffer or shader
554 // storage buffer, and want to read or write their values outside a shader, you
555 // need to know the offset of each one. You can query these offsets, but for
556 // large collections of uniforms this process requires many queries and is
557 // cumbersome. As an alternative, the standard layout qualifiers request that
558 // the GLSL shader compiler organize the variables according to a set of rules,
559 // where you can predictably compute the offset of any member in the block.
560 // In order to qualify a block to use the std140 layout, you need to add a
561 // layout directive to its declaration, as demonstrated below:
563 // layout (std140) buffer UniformBlock {
564 // // declared variables
567 // This std140 qualification also works for shader storage buffer objects.
569 // To use these, the offset of a member in the block is the accumulated total
570 // of the alignment and sizes of the previous members in the block (those
571 // declared before the variable in question), bumped up to the alignment of
572 // the member. The starting offset of the first member is always zero.
574 // The std140 Layout Rules
575 // =======================
576 // The set of rules shown in the table are used by the GLSL compiler to place
577 // members in an std140-qualified uniform block. This feature is available
578 // only with GLSL Version 1.40 or greater.
580 // Variable Type Variable Size and Alignment
581 // --------------------------------------------------------------------------------
582 // Scalar bool, int, uint, float and Both the size and alignment are the size
583 // double of the scalar in basic machine types
584 // (e.g., sizeof(GLfloat)).
586 // Two-component vectors (e.g., ivec2) Both the size and alignment are twice
587 // the size of the underlying scalar type.
589 // Three-component vectors (e.g., vec3) Both the size and alignment are four
590 // and times the size of the underlying scalar
591 // Four-component vectors (e.g., vec4) type.
593 // An array of scalars or vectors The size of each element in the array
594 // will be the size of the element type,
595 // rounded up to a multiple of the size of a
596 // vec4. This is also the array’s alignment.
597 // The array’s size will be this rounded-up
598 // element’s size times the number of
599 // elements in the array.
601 // A column-major matrix or an array Same layout as an array of N vectors
602 // of column-major matrices of size C each with R components, where N is
603 // columns and R rows the total number of columns present.
605 // A row-major matrix or an array of Same layout as an array of N vectors
606 // row-major matrices with R rows and C each with C components, where N is
607 // columns the total number of rows present.
609 // A single-structure definition, Structure alignment will be
610 // or an array of structures the alignment for the biggest structure
611 // member, according to the previous
612 // rules, rounded up to a multiple of the
613 // size of a vec4. Each structure will start
614 // on this alignment, and its size will be the
615 // space needed by its members, according
616 // to the previous rules, rounded up to
617 // a multiple of the structure alignment.
620 std::size_t ao
= 0; // aligned offset
621 std::size_t bo
= 0; // base offset
622 // layout(std140) uniform Example
624 // // Base types below consume 4 basic machine units
626 // // base base align
627 // // rule align off. off. bytes used
628 // // ---- ------ ---- ---- -----------------------
629 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // Real32 a; // 1 4 0 0 0..3
630 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // Vec2f b; // 2 8 4 8 8..15
631 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // Vec3f c; // 3 16 16 16 16..27
632 ao
= align_offset(16, bo
); bo
= ao
; // struct { // 9 16 28 32 (align begin)
633 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Int32
); // Int32 d; // 1 4 32 32 32..35
634 ao
= align_offset( 8, bo
); bo
= ao
+ 2*sizeof(OSG::Int32
); // Vec2b e; // 2 8 36 40 40..47
635 ao
= align_offset(16, bo
); bo
= ao
; // } f; // 9 16 48 48 (pad end)
636 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // Real32 g; // 1 4 48 48 48..51
637 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Real32
); // Real32 h[2]; // 4 16 52 64 64..67 (h[0])
638 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Real32
); // // 16 68 80 80..83 (h[1])
639 ao
= align_offset(16, bo
); bo
= ao
; // // 4 16 84 96 (pad end of h)
640 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // Matrix2x3f i; // 5/4 16 96 96 96..107 (i, column 0)
641 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 108 112 112..123 (i, column 1)
642 ao
= align_offset(16, bo
); bo
= ao
; // // 5/4 16 124 128 (pad end of i)
643 ao
= align_offset(16, bo
); bo
= ao
; // struct { // 10 16 128 128 (align begin)
644 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3u
); // Vec3u j; // 3 16 128 128 128..139 (o[0].j)
645 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // Vec2f k; // 2 8 140 144 144..151 (o[0].k)
646 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Real32
); // Real32 l[2]; // 4 16 152 160 160..163 (o[0].l[0])
647 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Real32
); // // 16 164 176 176..179 (o[0].l[1])
648 ao
= align_offset(16, bo
); bo
= ao
; // // 4 16 180 192 (pad end of o[0].l)
649 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // Vec2f m; // 2 8 192 192 192..199 (o[0].m)
650 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // Matrix3f n[2]; // 6/4 16 200 208 208..219 (o[0].n[0], column 0)
651 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 220 224 224..235 (o[0].n[0], column 1)
652 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 236 240 240..251 (o[0].n[0], column 2)
653 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 252 256 256..267 (o[0].n[1], column 0)
654 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 268 272 272..283 (o[0].n[1], column 1)
655 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 284 288 288..299 (o[0].n[1], column 2)
656 ao
= align_offset(16, bo
); bo
= ao
; // // 6/4 16 300 304 (pad end of o[0].n)
657 ao
= align_offset(16, bo
); bo
= ao
; // // 9 16 304 304 (pad end of o[0])
658 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3u
); // // 3 16 304 304 304..315 (o[1].j)
659 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // // 2 8 316 320 320..327 (o[1].k)
660 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Real32
); // // 4 16 328 336 336..339 (o[1].l[0])
661 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Real32
); // // 16 340 352 352..355 (o[1].l[1])
662 ao
= align_offset(16, bo
); bo
= ao
; // // 4 16 356 368 (pad end of o[1].l)
663 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // // 2 8 368 368 368..375 (o[1].m)
664 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 6/4 16 376 384 384..395 (o[1].n[0], column 0)
665 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 396 400 400..411 (o[1].n[0], column 1)
666 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 412 416 416..427 (o[1].n[0], column 2)
667 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 428 432 432..443 (o[1].n[1], column 0)
668 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 444 448 448..459 (o[1].n[1], column 1)
669 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 460 464 464..475 (o[1].n[1], column 2)
670 ao
= align_offset(16, bo
); bo
= ao
; // // 6/4 16 476 480 (pad end of o[1].n)
671 ao
= align_offset(16, bo
); bo
= ao
; // // 9 16 480 480 (pad end of o[1])
677 std::vector
<OSG::UInt8
> create_test_block_buffer(const TestBlock
& test_block
)
679 std::size_t size
= calc_test_block_buffer_size(test_block
);
681 std::vector
<OSG::UInt8
> buffer(size
);
683 std::size_t ao
= 0; // aligned offset
684 std::size_t bo
= 0; // base offset
686 ao
= align_offset( 4, bo
);
687 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.a
;
688 bo
= ao
+ sizeof(OSG::Real32
);
690 ao
= align_offset( 8, bo
);
691 memcpy(&buffer
[0] + ao
, &test_block
.b
[0], sizeof(OSG::Vec2f
));
692 bo
= ao
+ sizeof(OSG::Vec2f
);
694 ao
= align_offset(16, bo
);
695 memcpy(&buffer
[0] + ao
, &test_block
.c
[0], sizeof(OSG::Vec3f
));
696 bo
= ao
+ sizeof(OSG::Vec3f
);
698 ao
= align_offset(16, bo
);
701 ao
= align_offset( 4, bo
);
702 *(reinterpret_cast<OSG::Int32
*>(&buffer
[0] + ao
)) = test_block
.f
.d
;
703 bo
= ao
+ sizeof(OSG::Int32
);
705 ao
= align_offset( 8, bo
);
706 *(reinterpret_cast<OSG::Int32
*>(&buffer
[0] + ao
)) = test_block
.f
.e
[0];
707 bo
= ao
+ sizeof(OSG::Int32
);
709 *(reinterpret_cast<OSG::Int32
*>(&buffer
[0] + ao
)) = test_block
.f
.e
[1];
710 bo
= ao
+ sizeof(OSG::Int32
);
712 ao
= align_offset(16, bo
);
715 ao
= align_offset( 4, bo
);
716 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.g
;
717 bo
= ao
+ sizeof(OSG::Real32
);
719 ao
= align_offset(16, bo
);
720 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.h
[0];
721 bo
= ao
+ sizeof(OSG::Real32
);
723 ao
= align_offset(16, bo
);
724 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.h
[1];
725 bo
= ao
+ sizeof(OSG::Real32
);
727 ao
= align_offset(16, bo
);
730 ao
= align_offset(16, bo
);
731 memcpy(&buffer
[0] + ao
, &test_block
.i
.row1
[0], sizeof(OSG::Vec3f
));
732 bo
= ao
+ sizeof(OSG::Vec3f
);
734 ao
= align_offset(16, bo
);
735 memcpy(&buffer
[0] + ao
, &test_block
.i
.row2
[0], sizeof(OSG::Vec3f
));
736 bo
= ao
+ sizeof(OSG::Vec3f
);
738 ao
= align_offset(16, bo
);
741 ao
= align_offset(16, bo
);
744 ao
= align_offset(16, bo
);
745 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].j
[0], sizeof(OSG::Vec3u
));
746 bo
= ao
+ sizeof(OSG::Vec3u
);
748 ao
= align_offset( 8, bo
);
749 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].k
[0], sizeof(OSG::Vec2f
));
750 bo
= ao
+ sizeof(OSG::Vec2f
);
752 ao
= align_offset(16, bo
);
753 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.o
[0].l
[0];
754 bo
= ao
+ sizeof(OSG::Real32
);
756 ao
= align_offset(16, bo
);
757 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.o
[0].l
[1];
758 bo
= ao
+ sizeof(OSG::Real32
);
760 ao
= align_offset(16, bo
);
763 ao
= align_offset( 8, bo
);
764 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].m
[0], sizeof(OSG::Vec2f
));
765 bo
= ao
+ sizeof(OSG::Vec2f
);
767 ao
= align_offset(16, bo
);
768 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[0].row1
[0], sizeof(OSG::Vec3f
));
769 bo
= ao
+ sizeof(OSG::Vec3f
);
771 ao
= align_offset(16, bo
);
772 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[0].row2
[0], sizeof(OSG::Vec3f
));
773 bo
= ao
+ sizeof(OSG::Vec3f
);
775 ao
= align_offset(16, bo
);
776 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[0].row3
[0], sizeof(OSG::Vec3f
));
777 bo
= ao
+ sizeof(OSG::Vec3f
);
779 ao
= align_offset(16, bo
);
780 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[1].row1
[0], sizeof(OSG::Vec3f
));
781 bo
= ao
+ sizeof(OSG::Vec3f
);
783 ao
= align_offset(16, bo
);
784 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[1].row2
[0], sizeof(OSG::Vec3f
));
785 bo
= ao
+ sizeof(OSG::Vec3f
);
787 ao
= align_offset(16, bo
);
788 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[1].row3
[0], sizeof(OSG::Vec3f
));
789 bo
= ao
+ sizeof(OSG::Vec3f
);
791 ao
= align_offset(16, bo
);
794 ao
= align_offset(16, bo
);
797 ao
= align_offset(16, bo
);
798 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].j
[0], sizeof(OSG::Vec3u
));
799 bo
= ao
+ sizeof(OSG::Vec3u
);
801 ao
= align_offset( 8, bo
);
802 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].k
[0], sizeof(OSG::Vec2f
));
803 bo
= ao
+ sizeof(OSG::Vec2f
);
805 ao
= align_offset(16, bo
);
806 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.o
[1].l
[0];
807 bo
= ao
+ sizeof(OSG::Real32
);
809 ao
= align_offset(16, bo
);
810 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.o
[1].l
[1];
811 bo
= ao
+ sizeof(OSG::Real32
);
813 ao
= align_offset(16, bo
);
816 ao
= align_offset( 8, bo
);
817 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].m
[0], sizeof(OSG::Vec2f
));
818 bo
= ao
+ sizeof(OSG::Vec2f
);
820 ao
= align_offset(16, bo
);
821 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[0].row1
[0], sizeof(OSG::Vec3f
));
822 bo
= ao
+ sizeof(OSG::Vec3f
);
824 ao
= align_offset(16, bo
);
825 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[0].row2
[0], sizeof(OSG::Vec3f
));
826 bo
= ao
+ sizeof(OSG::Vec3f
);
828 ao
= align_offset(16, bo
);
829 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[0].row3
[0], sizeof(OSG::Vec3f
));
830 bo
= ao
+ sizeof(OSG::Vec3f
);
832 ao
= align_offset(16, bo
);
833 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[1].row1
[0], sizeof(OSG::Vec3f
));
834 bo
= ao
+ sizeof(OSG::Vec3f
);
836 ao
= align_offset(16, bo
);
837 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[1].row2
[0], sizeof(OSG::Vec3f
));
838 bo
= ao
+ sizeof(OSG::Vec3f
);
840 ao
= align_offset(16, bo
);
841 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[1].row3
[0], sizeof(OSG::Vec3f
));
842 bo
= ao
+ sizeof(OSG::Vec3f
);
844 ao
= align_offset(16, bo
);
847 ao
= align_offset(16, bo
);
853 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr
create_test_block_state(const TestBlock
& test_block
)
855 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjStdLayoutChunk::create();
857 std::vector
<OSG::UInt8
> buffer
= create_test_block_buffer(test_block
);
859 ssbo
->editMFBuffer()->setValues(buffer
);
860 ssbo
->setUsage(GL_DYNAMIC_DRAW
);
862 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo
);
865 void update_test_block_state(OSG::ShaderStorageBufferObjStdLayoutChunk
* ssbo
, const TestBlock
& test_block
)
868 std::vector
<OSG::UInt8
> buffer
= create_test_block_buffer(test_block
);
869 ssbo
->editMFBuffer()->setValues(buffer
);
874 // ii) the light shader storage buffer object
876 std::size_t calc_light_buffer_size(const VecLightsT
& vLights
)
878 std::size_t ao
= 0; // aligned offset
879 std::size_t bo
= 0; // base offset
881 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Pnt4f
); // OSG::Pnt3f position;
882 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Vec4f
); // OSG::Vec3f spot_direction;
883 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f Ia;
884 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f Id;
885 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f Is;
886 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Vec4f
); // OSG::Vec3f attenuation;
887 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // OSG::Real32 spot_cos_cutoff;
888 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // OSG::Real32 spot_exponent;
889 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Int32
); // OSG::Int32 type;
890 ao
= align_offset( 16, bo
); bo
= ao
; // padding
892 ao
*= vLights
.size(); bo
= ao
; // array
893 ao
= align_offset( 16, bo
); bo
= ao
; // padding
898 std::vector
<OSG::UInt8
> create_light_buffer(const VecLightsT
& vLights
)
900 std::size_t size
= calc_light_buffer_size(vLights
);
902 std::vector
<OSG::UInt8
> buffer(size
);
904 std::size_t ao
= 0; // aligned offset
905 std::size_t bo
= 0; // base offset
907 for (std::size_t i
= 0; i
< vLights
.size(); ++i
)
909 OSG::Pnt3f position_es
= transform_to_eye_space(vLights
[i
].position
, mgr
);
910 OSG::Vec3f spot_direction_es
= transform_to_eye_space(vLights
[i
].spot_direction
, mgr
);
912 ao
= align_offset(16, bo
);
913 memcpy(&buffer
[0] + ao
, &position_es
[0], sizeof(OSG::Pnt3f
));
914 bo
= ao
+ sizeof(OSG::Pnt4f
);
916 ao
= align_offset(16, bo
);
917 memcpy(&buffer
[0] + ao
, &spot_direction_es
[0], sizeof(OSG::Vec3f
));
918 bo
= ao
+ sizeof(OSG::Vec4f
);
920 ao
= align_offset(16, bo
);
921 memcpy(&buffer
[0] + ao
, &vLights
[i
].Ia
[0], sizeof(OSG::Color3f
));
922 bo
= ao
+ sizeof(OSG::Color4f
);
924 ao
= align_offset(16, bo
);
925 memcpy(&buffer
[0] + ao
, &vLights
[i
].Id
[0], sizeof(OSG::Color3f
));
926 bo
= ao
+ sizeof(OSG::Color4f
);
928 ao
= align_offset(16, bo
);
929 memcpy(&buffer
[0] + ao
, &vLights
[i
].Is
[0], sizeof(OSG::Color3f
));
930 bo
= ao
+ sizeof(OSG::Color4f
);
932 ao
= align_offset(16, bo
);
933 memcpy(&buffer
[0] + ao
, &vLights
[i
].attenuation
[0], sizeof(OSG::Vec3f
));
934 bo
= ao
+ sizeof(OSG::Vec4f
);
936 ao
= align_offset( 4, bo
);
937 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = vLights
[i
].spot_cos_cutoff
;
938 bo
= ao
+ sizeof(OSG::Real32
);
940 ao
= align_offset( 4, bo
);
941 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = vLights
[i
].spot_exponent
;
942 bo
= ao
+ sizeof(OSG::Real32
);
944 ao
= align_offset( 4, bo
);
945 *(reinterpret_cast<OSG::Int32
*>(&buffer
[0] + ao
)) = vLights
[i
].type
;
946 bo
= ao
+ sizeof(OSG::Int32
);
948 ao
= align_offset( 16, bo
); bo
= ao
; // padding
954 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr
create_light_state(const VecLightsT
& vLights
)
956 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjStdLayoutChunk::create();
958 std::vector
<OSG::UInt8
> buffer
= create_light_buffer(vLights
);
960 ssbo
->editMFBuffer()->setValues(buffer
);
961 ssbo
->setUsage(GL_DYNAMIC_DRAW
);
963 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo
);
966 void update_light_state(OSG::ShaderStorageBufferObjStdLayoutChunk
* ssbo
, const VecLightsT
& vLights
)
969 std::vector
<OSG::UInt8
> buffer
= create_light_buffer(vLights
);
970 ssbo
->editMFBuffer()->setValues(buffer
);
975 // iii) the material shader storage buffer object
977 std::size_t calc_material_database_buffer_size(const VecMaterialsT
& vMaterials
)
979 std::size_t ao
= 0; // aligned offset
980 std::size_t bo
= 0; // base offset
982 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f ambient;
983 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f diffuse;
984 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f specular;
985 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f emissive;
986 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // OSG::Real32 opacity;
987 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // OSG::Real32 shininess;
988 ao
= align_offset( 16, bo
); bo
= ao
; // padding
990 ao
*= vMaterials
.size(); bo
= ao
; // array
991 ao
= align_offset( 16, bo
); bo
= ao
; // padding
996 std::vector
<OSG::UInt8
> create_material_database_buffer(const VecMaterialsT
& vMaterials
)
998 std::size_t size
= calc_material_database_buffer_size(vMaterials
);
1000 std::vector
<OSG::UInt8
> buffer(size
);
1002 std::size_t ao
= 0; // aligned offset
1003 std::size_t bo
= 0; // base offset
1005 for (std::size_t i
= 0; i
< vMaterials
.size(); ++i
)
1007 ao
= align_offset(16, bo
);
1008 memcpy(&buffer
[0] + ao
, &vMaterials
[i
].ambient
[0], sizeof(OSG::Color3f
));
1009 bo
= ao
+ sizeof(OSG::Color4f
);
1011 ao
= align_offset(16, bo
);
1012 memcpy(&buffer
[0] + ao
, &vMaterials
[i
].diffuse
[0], sizeof(OSG::Color3f
));
1013 bo
= ao
+ sizeof(OSG::Color4f
);
1015 ao
= align_offset(16, bo
);
1016 memcpy(&buffer
[0] + ao
, &vMaterials
[i
].specular
[0], sizeof(OSG::Color3f
));
1017 bo
= ao
+ sizeof(OSG::Color4f
);
1019 ao
= align_offset(16, bo
);
1020 memcpy(&buffer
[0] + ao
, &vMaterials
[i
].emissive
[0], sizeof(OSG::Color3f
));
1021 bo
= ao
+ sizeof(OSG::Color4f
);
1023 ao
= align_offset( 4, bo
);
1024 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = vMaterials
[i
].opacity
;
1025 bo
= ao
+ sizeof(OSG::Real32
);
1027 ao
= align_offset( 4, bo
);
1028 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = vMaterials
[i
].shininess
;
1029 bo
= ao
+ sizeof(OSG::Real32
);
1031 ao
= align_offset( 16, bo
); bo
= ao
; // padding
1037 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr
create_material_database_state(const VecMaterialsT
& vMaterials
)
1039 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1041 std::vector
<OSG::UInt8
> buffer
= create_material_database_buffer(vMaterials
);
1043 ssbo
->editMFBuffer()->setValues(buffer
);
1044 ssbo
->setUsage(GL_STATIC_DRAW
);
1046 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo
);
1049 void update_material_database_state(OSG::ShaderStorageBufferObjStdLayoutChunk
* ssbo
, const VecMaterialsT
& vMaterials
)
1052 std::vector
<OSG::UInt8
> buffer
= create_material_database_buffer(vMaterials
);
1053 ssbo
->editMFBuffer()->setValues(buffer
);
1058 // iv) the geomertry shader storage buffer object
1060 std::size_t calc_geometry_material_buffer_size()
1062 std::size_t ao
= 0; // aligned offset
1063 std::size_t bo
= 0; // base offset
1065 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::UInt32
); // OSG::UInt32 material_index;
1066 ao
= align_offset( 16, bo
); bo
= ao
; // padding
1071 std::vector
<OSG::UInt8
> create_geometry_material_buffer(const GeomState
& geom_state
)
1073 std::size_t size
= calc_geometry_material_buffer_size();
1075 std::vector
<OSG::UInt8
> buffer(size
);
1077 std::size_t ao
= 0; // aligned offset
1078 std::size_t bo
= 0; // base offset
1080 ao
= align_offset( 4, bo
);
1081 *(reinterpret_cast<OSG::UInt32
*>(&buffer
[0] + ao
)) = geom_state
.material_index
;
1082 bo
= ao
+ sizeof(OSG::UInt32
);
1087 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr
create_geometry_material_state(const GeomState
& geom_state
)
1089 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1091 std::vector
<OSG::UInt8
> buffer
= create_geometry_material_buffer(geom_state
);
1093 ssbo
->editMFBuffer()->setValues(buffer
);
1094 ssbo
->setUsage(GL_DYNAMIC_DRAW
);
1096 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo
);
1099 void update_geometry_material_state(OSG::ShaderStorageBufferObjStdLayoutChunk
* ssbo
, const GeomState
& geom_state
)
1102 std::vector
<OSG::UInt8
> buffer
= create_geometry_material_buffer(geom_state
);
1103 ssbo
->editMFBuffer()->setValues(buffer
);
1108 // Part IV: The application starts here
1112 // vertex shader program.
1114 std::string
get_vp_program();
1117 // fragment shader program for bump mapping in surface local coordinates
1119 std::string
get_fp_program();
1122 // random number generator
1124 boost::random::mt19937 generator
;
1125 boost::random::uniform_int_distribution
<> dist(0, num_materials
-1);
1128 // a separate transformation for every object
1130 OSG::TransformRefPtr cyltrans
, tortrans
;
1133 // Shader Storage buffer objects corresponding to transient shader blocks
1135 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_light_state
= NULL
;
1136 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_geom_state_1
= NULL
;
1137 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_geom_state_2
= NULL
;
1140 // forward declaration so we can have the interesting stuff upfront
1142 int setupGLUT(int *argc
, char *argv
[]);
1145 // redraw the window
1149 // light spot direction and light position must be provided in eye space
1150 update_light_state(ssbo_light_state
, lights
);
1152 // create the matrix
1154 OSG::Real32 t
= glutGet(GLUT_ELAPSED_TIME
);
1156 // set the transforms' matrices
1157 m
.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t
/ 1000.f
) * 1.5),
1158 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t
/ 500.f
));
1160 cyltrans
->setMatrix(m
);
1162 m
.setTransform(OSG::Vec3f(OSG::osgSin(t
/ 1000.f
), 0, 0),
1163 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t
/ 1000.f
));
1165 tortrans
->setMatrix(m
);
1167 OSG::commitChanges();
1173 // Initialize GLUT & OpenSG and set up the scene
1175 int main(int argc
, char **argv
)
1178 OSG::osgInit(argc
,argv
);
1181 int winid
= setupGLUT(&argc
, argv
);
1183 // open a new scope, because the pointers below should go out of scope
1184 // before entering glutMainLoop.
1185 // Otherwise OpenSG will complain about objects being alive after shutdown.
1187 // the connection between GLUT and OpenSG
1188 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
1189 gwin
->setGlutId(winid
);
1192 // create the SimpleSceneManager helper
1193 mgr
= OSG::SimpleSceneManager::create();
1194 mgr
->setWindow(gwin
);
1196 // create a pretty simple graph: a Group with two Transforms as children,
1197 // each of which carries a single Geometry.
1201 OSG::NodeRefPtr scene
= OSG::Node::create();
1203 // The cylinder and its transformation
1204 OSG::NodeRefPtr cyl
= OSG::Node::create();
1205 OSG::GeometryRefPtr cylgeo
= OSG::makeCylinderGeo( 1.4f
, .3f
, 24,
1208 cyl
->setCore(cylgeo
);
1210 cyltrans
= OSG::Transform::create();
1212 OSG::NodeRefPtr cyltransnode
= OSG::Node::create();
1213 cyltransnode
->setCore (cyltrans
);
1214 cyltransnode
->addChild(cyl
);
1216 // add it to the scene
1217 scene
->addChild(cyltransnode
);
1219 // The torus and its transformation
1220 OSG::NodeRefPtr torus
= OSG::Node::create();
1221 OSG::GeometryRefPtr torusgeo
= OSG::makeTorusGeo( .2f
, 1, 24, 36 );
1223 torus
->setCore(torusgeo
);
1225 tortrans
= OSG::Transform::create();
1227 OSG::NodeRefPtr tortransnode
= OSG::Node::create();
1228 tortransnode
->setCore (tortrans
);
1229 tortransnode
->addChild(torus
);
1231 // add it to the scene
1232 scene
->addChild(tortransnode
);
1235 // create the shader program
1237 OSG::ShaderProgramChunkRefPtr prog_chunk
= OSG::ShaderProgramChunk::create();
1238 OSG::ShaderProgramRefPtr vertShader
= OSG::ShaderProgram::createVertexShader();
1239 OSG::ShaderProgramRefPtr fragShader
= OSG::ShaderProgram::createFragmentShader();
1241 vertShader
->setProgram(get_vp_program());
1242 fragShader
->setProgram(get_fp_program());
1245 // binding the shader storage block to a buffer binding point can be performed
1246 // either by calling the shaders's addShaderStorageBlock method or by
1247 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
1248 // In the following we use both variants for illustration.
1250 fragShader
->addShaderStorageBlock("Materials", 1); // block binding point
1251 fragShader
->addShaderStorageBlock("Lights", 2); // block binding point
1254 // The following is replaced by adding ShaderProgramVariableChunk objects
1255 // to the chunk material. See below...
1257 // fragShader->addShaderStorageBlock("GeomState", 3); // block binding point
1259 fragShader
->addShaderStorageBlock("TestBlock", 4); // block binding point
1261 prog_chunk
->addShader(vertShader
);
1262 prog_chunk
->addShader(fragShader
);
1265 // create shader storage buffer objects and corresponding materials
1267 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_material_database
= create_material_database_state(materials
);
1268 ssbo_light_state
= create_light_state(lights
);
1270 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_test_block
= create_test_block_state(global_test_block
);
1272 OSG::PolygonChunkRefPtr polygon_chunk
= OSG::PolygonChunk::create();
1273 polygon_chunk
->setFrontMode(GL_FILL
);
1274 polygon_chunk
->setBackMode(GL_FILL
);
1275 polygon_chunk
->setCullFace(GL_NONE
);
1277 OSG::DepthChunkRefPtr depth_chunk
= OSG::DepthChunk::create();
1278 depth_chunk
->setEnable(true);
1280 OSG::ChunkMaterialRefPtr prog_state
= OSG::ChunkMaterial::create();
1281 prog_state
->addChunk(ssbo_material_database
, 1); // buffer binding point 1
1282 prog_state
->addChunk(ssbo_light_state
, 2); // buffer binding point 2
1283 prog_state
->addChunk(ssbo_test_block
, 4); // buffer binding point 4
1284 prog_state
->addChunk(prog_chunk
);
1285 prog_state
->addChunk(polygon_chunk
);
1286 prog_state
->addChunk(depth_chunk
);
1288 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk
= OSG::ShaderProgramVariableChunk::create();
1289 shader_var_chunk
->addShaderStorageBlock("GeomState", 3);
1291 GeomState geom1
; geom1
.material_index
= dist(generator
);
1292 OSG::ChunkMaterialRefPtr geom1_state
= OSG::ChunkMaterial::create();
1293 ssbo_geom_state_1
= create_geometry_material_state(geom1
);
1294 geom1_state
->addChunk(ssbo_geom_state_1
, 3); // buffer binding point 3
1295 geom1_state
->addChunk(shader_var_chunk
); // block binding point
1297 GeomState geom2
; geom2
.material_index
= dist(generator
);
1298 OSG::ChunkMaterialRefPtr geom2_state
= OSG::ChunkMaterial::create();
1299 ssbo_geom_state_2
= create_geometry_material_state(geom2
);
1300 geom2_state
->addChunk(ssbo_geom_state_2
, 3); // buffer binding point 3
1301 geom2_state
->addChunk(shader_var_chunk
); // block binding point
1303 cylgeo
->setMaterial(geom1_state
);
1304 torusgeo
->setMaterial(geom2_state
);
1306 OSG::MaterialChunkOverrideGroupRefPtr mgrp
= OSG::MaterialChunkOverrideGroup::create();
1307 mgrp
->setMaterial(prog_state
);
1308 scene
->setCore(mgrp
);
1310 OSG::commitChanges();
1312 mgr
->setRoot(scene
);
1314 // show the whole scene
1325 // GLUT callback functions
1329 // react to size changes
1331 void reshape(int w
, int h
)
1334 glutPostRedisplay();
1338 // react to mouse button presses
1340 void mouse(int button
, int state
, int x
, int y
)
1343 mgr
->mouseButtonRelease(button
, x
, y
);
1345 mgr
->mouseButtonPress(button
, x
, y
);
1347 glutPostRedisplay();
1351 // react to mouse motions with pressed buttons
1353 void motion(int x
, int y
)
1355 mgr
->mouseMove(x
, y
);
1356 glutPostRedisplay();
1362 void keyboard(unsigned char k
, int x
, int y
)
1368 // clean up global variables
1373 ssbo_light_state
= NULL
;
1374 ssbo_geom_state_1
= NULL
;
1375 ssbo_geom_state_2
= NULL
;
1384 GeomState geom1
; geom1
.material_index
= dist(generator
);
1385 GeomState geom2
; geom2
.material_index
= dist(generator
);
1387 update_geometry_material_state(ssbo_geom_state_1
, geom1
);
1388 update_geometry_material_state(ssbo_geom_state_2
, geom2
);
1390 glutPostRedisplay();
1396 mgr
->setStatistics(!mgr
->getStatistics());
1403 // setup the GLUT library which handles the windows for us
1405 int setupGLUT(int *argc
, char *argv
[])
1407 glutInit(argc
, argv
);
1408 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
1410 int winid
= glutCreateWindow("OpenSG");
1412 glutReshapeFunc(reshape
);
1413 glutDisplayFunc(display
);
1414 glutMouseFunc(mouse
);
1415 glutMotionFunc(motion
);
1416 glutKeyboardFunc(keyboard
);
1418 // call the redraw function whenever there's nothing else to do
1419 glutIdleFunc(display
);
1425 // Part V: The shader programs
1429 // vertex shader program.
1431 std::string
get_vp_program()
1433 std::string vp_program
=
1435 "#version 440 compatibility\n"
1437 "#extension GL_ARB_separate_shader_objects: enable\n"
1438 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
1440 "smooth out vec3 vNormalES; // eye space normal\n"
1441 "smooth out vec3 vPositionES; // eye space position\n"
1446 " // multiply the object space vertex position with the modelview matrix \n"
1447 " // to get the eye space vertex position\n"
1449 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
1452 " // multiply the object space normal with the normal matrix (transpose of the inverse \n"
1453 " // model view matrix) to get the eye space normal\n"
1455 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
1458 " // multiply the combiend modelview projection matrix with the object space vertex\n"
1459 " // position to get the clip space position\n"
1461 " gl_Position = ftransform();\n"
1469 // fragment shader program for bump mapping in surface local coordinates
1471 std::string
get_fp_program()
1473 std::string fp_program
=
1475 "#version 440 compatibility\n"
1477 "#extension GL_ARB_separate_shader_objects: enable\n"
1478 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
1480 "smooth in vec3 vNormalES; // eye space normal\n"
1481 "smooth in vec3 vPositionES; // eye space position\n"
1483 "const int num_lights = 1;\n"
1484 "const int num_materials = 5000;\n"
1486 "const int directional_light = 0;\n"
1487 "const int point_light = 1;\n"
1488 "const int spot_light = 2;\n"
1489 "const int no_light = 3;\n"
1493 " vec4 position; // in eye space\n"
1494 " vec4 spot_direction; // in eye space\n"
1496 " vec4 Ia; // ambient max. Intensity\n"
1497 " vec4 Id; // diffuse max. Intensity\n"
1498 " vec4 Is; // specular max. Intensity\n"
1500 " vec4 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
1502 " float spot_cos_cutoff; // cosine cut of angle\n"
1504 " float spot_exponent; // [0-128]\n"
1505 " int type; // directional_light, point_light, spot_light, no_light\n"
1508 "layout (std140) buffer Lights\n"
1510 " Light light[num_lights];\n"
1521 " float shininess;\n"
1524 "layout (std140) buffer Materials\n"
1526 " Material material[num_materials];\n"
1530 "layout (std140) buffer GeomState\n"
1532 " int material_index;\n"
1535 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
1537 "layout(location = 0) out vec4 vFragColor;\n"
1540 "// The test block from the GL_ARB_uniform_buffer_object\n"
1541 "// specification. \n"
1558 "layout (std140) buffer TestBlock\n"
1571 "// directional light contribution\n"
1573 "vec3 directionalLight(\n"
1574 " in int i, // light identifier, i.e. current light\n"
1575 " in int j, // material identifier\n"
1576 " in vec3 n, // vertex normal in eye space\n"
1577 " in vec3 v) // view direction in eye space\n"
1579 " if (lights.light[i].type != directional_light)\n"
1580 " return vec3(0.0, 0.0, 0.0);\n"
1583 " // the light direction in eye space\n"
1585 " vec3 l = -lights.light[i].spot_direction.xyz; // we carry the directional light direction in the spot_direction slot\n"
1588 " // the half vector\n"
1590 " vec3 h = normalize(l + v);\n"
1592 " float n_dot_l = max(0.0, dot(n, l));\n"
1593 " float n_dot_h = max(0.0, dot(n, h));\n"
1595 " float m = materials.material[j].shininess;\n"
1597 " float pf; // power factor\n"
1599 " if (n_dot_l == 0.0)\n"
1602 " pf = pow(n_dot_h, m);\n"
1604 " return materials.material[j].emissive.rgb \n"
1605 " + lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1606 " + lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1607 " + lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1611 "// point light contribution\n"
1613 "vec3 pointLight(\n"
1614 " in int i, // light identifier, i.e. current light\n"
1615 " in int j, // material identifier\n"
1616 " in vec3 n, // vertex normal in eye space\n"
1617 " in vec3 v, // view direction in eye space\n"
1618 " in vec3 p) // vertex position in eye space\n"
1620 " if (lights.light[i].type != point_light)\n"
1621 " return vec3(0.0, 0.0, 0.0);\n"
1623 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1624 " float d = length(l); // distance from surface to light source\n"
1625 " l = normalize(l); // normalized direction from surface to light position\n"
1628 " // the half vector\n"
1630 " vec3 h = normalize(l + v);\n"
1632 " float n_dot_l = max(0.0, dot(n, l));\n"
1633 " float n_dot_h = max(0.0, dot(n, h));\n"
1635 " float m = materials.material[j].shininess;\n"
1637 " float pf; // power factor\n"
1639 " if (n_dot_l == 0.0)\n"
1642 " pf = pow(n_dot_h, m);\n"
1645 " // Compute attenuation\n"
1647 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1648 " (lights.light[i].attenuation.y * d) + \n"
1649 " (lights.light[i].attenuation.z * d * d));\n"
1651 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1653 " return materials.material[j].emissive.rgb \n"
1654 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1655 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1656 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1660 "// spot light contribution\n"
1663 " in int i, // light identifier, i.e. current light\n"
1664 " in int j, // material identifier\n"
1665 " in vec3 n, // vertex normal in eye space\n"
1666 " in vec3 v, // view direction in eye space\n"
1667 " in vec3 p) // vertex position in eye space\n"
1669 " if (lights.light[i].type != spot_light)\n"
1670 " return vec3(0.0, 0.0, 0.0);\n"
1672 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1673 " float d = length(l); // distance from surface to light source\n"
1674 " l = normalize(l); // normalized direction from surface to light position\n"
1676 " vec3 s = lights.light[i].spot_direction.xyz; // spot direction\n"
1679 " // the half vector\n"
1681 " vec3 h = normalize(l + v);\n"
1683 " float n_dot_l = max(0.0, dot(n, l));\n"
1684 " float n_dot_h = max(0.0, dot(n, h));\n"
1685 " float l_dot_s = dot(-l, s);\n"
1687 " float m = materials.material[j].shininess;\n"
1689 " float pf; // power factor\n"
1691 " if (n_dot_l == 0.0)\n"
1694 " pf = pow(n_dot_h, m);\n"
1697 " // Compute attenuation\n"
1699 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1700 " (lights.light[i].attenuation.y * d) + \n"
1701 " (lights.light[i].attenuation.z * d * d));\n"
1703 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1705 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
1706 " attenuation = 0.0;\n"
1708 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\n"
1710 " return materials.material[j].emissive.rgb \n"
1711 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1712 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1713 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1719 " // normalize the eye space normal\n"
1721 " vec3 N = normalize(vNormalES);\n"
1724 " // get the view vector and normalize it\n"
1726 " vec3 V = normalize(cCameraPositionES - vPositionES);\n"
1729 " // Integrate over all lights: Any unused light does not contribute and each light\n"
1730 " // contribute either from the directional light, the point light or the spot light.\n"
1732 " vec3 color = vec3(0.0, 0.0, 0.0);\n"
1733 " for (int i = 0; i < num_lights; ++i) {\n"
1734 " color += directionalLight(i, geom_state.material_index, N, V) \n"
1735 " + pointLight(i, geom_state.material_index, N, V, vPositionES) \n"
1736 " + spotLight(i, geom_state.material_index, N, V, vPositionES);\n"
1738 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"
1741 " // Test TestBlock\n"
1743 " if (test_block.a != 27.4) vFragColor = vec4(1, 0, 0, 1);\n"
1744 " if (test_block.b != vec2(15.3, 12.8)) vFragColor = vec4(1, 0, 0, 1);\n"
1745 " if (test_block.c != vec3(11.4, 21.9, 10.5)) vFragColor = vec4(1, 0, 0, 1);\n"
1747 " if (test_block.f.d != 61) vFragColor = vec4(1, 0, 0, 1);\n"
1748 " if (test_block.f.e != bvec2(true, false)) vFragColor = vec4(1, 0, 0, 1);\n"
1750 " if (test_block.g != 57.3) vFragColor = vec4(1, 0, 0, 1);\n"
1752 " if (test_block.h[0] != 9.1) vFragColor = vec4(1, 0, 0, 1);\n"
1753 " if (test_block.h[1] != 17.56) vFragColor = vec4(1, 0, 0, 1);\n"
1755 " if (test_block.i[0] != vec3(19.43,1243.2, 0.56)) vFragColor = vec4(1, 0, 0, 1);\n"
1756 " if (test_block.i[1] != vec3(13.54,264.22, 65.52)) vFragColor = vec4(1, 0, 0, 1);\n"
1758 " if (test_block.o[0].j != uvec3(10,11,12)) vFragColor = vec4(1, 0, 0, 1);\n"
1759 " if (test_block.o[0].k != vec2(64.62, 275.21)) vFragColor = vec4(1, 0, 0, 1);\n"
1760 " if (test_block.o[0].l[0] != 41.346) vFragColor = vec4(1, 0, 0, 1);\n"
1761 " if (test_block.o[0].l[1] != 67.9456) vFragColor = vec4(1, 0, 0, 1);\n"
1762 " if (test_block.o[0].m != vec2(-56.62, 768.276)) vFragColor = vec4(1, 0, 0, 1);\n"
1763 " if (test_block.o[0].n[0][0] != vec3(-0.4,-0.5,-0.6)) vFragColor = vec4(1, 0, 0, 1);\n"
1764 " if (test_block.o[0].n[0][1] != vec3(-0.7,-0.8,-0.9)) vFragColor = vec4(1, 0, 0, 1);\n"
1765 " if (test_block.o[0].n[0][2] != vec3(-0.1,-0.2,-0.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1766 " if (test_block.o[0].n[1][0] != vec3(1.1,2.2,3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1767 " if (test_block.o[0].n[1][1] != vec3(1.2,2.3,3.4)) vFragColor = vec4(1, 0, 0, 1);\n"
1768 " if (test_block.o[0].n[1][2] != vec3(1.3,2.4,3.5)) vFragColor = vec4(1, 0, 0, 1);\n"
1770 " if (test_block.o[1].j != uvec3(20,31,42)) vFragColor = vec4(1, 0, 0, 1);\n"
1771 " if (test_block.o[1].k != vec2(-96.62, -658.456)) vFragColor = vec4(1, 0, 0, 1);\n"
1772 " if (test_block.o[1].l[0] != 88.34) vFragColor = vec4(1, 0, 0, 1);\n"
1773 " if (test_block.o[1].l[1] != -488.21) vFragColor = vec4(1, 0, 0, 1);\n"
1774 " if (test_block.o[1].m != vec2(777.7, 888.8)) vFragColor = vec4(1, 0, 0, 1);\n"
1775 " if (test_block.o[1].n[0][0] != vec3(1.1,1.2,1.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1776 " if (test_block.o[1].n[0][1] != vec3(2.1,2.2,2.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1777 " if (test_block.o[1].n[0][2] != vec3(3.1,3.2,3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1778 " if (test_block.o[1].n[1][0] != vec3(-1.1,-1.2,-1.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1779 " if (test_block.o[1].n[1][1] != vec3(-2.1,-2.2,-2.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1780 " if (test_block.o[1].n[1][2] != vec3(-3.1,-3.2,-3.3)) vFragColor = vec4(1, 0, 0, 1);\n"