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 std430 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 std430
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 std430 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
= 2; // simple example with just one light
311 VecLightsT
initialize_lights() // helper to create lights
315 lights
.push_back(Light::create_light(Light::directional_light
));
316 lights
.push_back(Light::create_light(Light::point_light
));
318 assert(lights
.size() == num_lights
);
323 VecLightsT lights
= initialize_lights(); // the lights
327 // Simple material data structure
332 : ambient (0.f
, 0.f
, 0.f
)
333 , diffuse (0.f
, 0.f
, 0.f
)
334 , specular(0.f
, 0.f
, 0.f
)
335 , emissive(0.f
, 0.f
, 0.f
)
340 OSG::Color3f ambient
;
341 OSG::Color3f diffuse
;
342 OSG::Color3f specular
;
343 OSG::Color3f emissive
;
346 OSG::Real32 shininess
;
349 typedef std::vector
<Material
> VecMaterialsT
; // multiple materials
351 VecMaterialsT
initialize_materials(std::size_t num
) // helper to create materials
353 VecMaterialsT materials
;
355 for (std::size_t i
= 0; i
< num
; ++i
)
359 m
.ambient
= OSG::Color3f(0.1f
, 0.1f
, 0.1f
);
360 m
.diffuse
.setRandom();
361 m
.specular
= OSG::Color3f(0.9f
, 0.9f
, 0.9f
);
362 m
.emissive
= OSG::Color3f(0.0f
, 0.0f
, 0.0f
);
366 materials
.push_back(m
);
372 const std::size_t num_materials
= 5000; // any number of materials
373 VecMaterialsT materials
= initialize_materials(num_materials
); // the material database
377 // Simple geometry state data structure
385 OSG::UInt32 material_index
;
390 // Part II: Some helper functions:
391 // Pnt3f transform_to_eye_space(const Pnt3f& p, SimpleSceneManager* pSSM)
392 // Vec3f transform_to_eye_space(const Vec3f& v, SimpleSceneManager* pSSM)
393 // size_t align_offset (size_t base_alignment, size_t base_offset)
397 // transform point from world space to eye space
399 OSG::Pnt3f
transform_to_eye_space(const OSG::Pnt3f
& p
, OSG::SimpleSceneManager
* pSSM
)
401 if (!pSSM
|| !pSSM
->getWindow() || pSSM
->getWindow()->getMFPort()->size() == 0)
404 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
409 OSG::Int16 width
= pPort
->calcPixelWidth();
410 OSG::Int16 height
= pPort
->calcPixelHeight();
412 pPort
->getCamera()->getViewing(view
, width
, height
);
414 view
.multFull( p
, p_es
);
420 // transform vector from world space to eye space
422 OSG::Vec3f
transform_to_eye_space(const OSG::Vec3f
& v
, OSG::SimpleSceneManager
* pSSM
)
424 if (!pSSM
|| !pSSM
->getWindow() || pSSM
->getWindow()->getMFPort()->size() == 0)
427 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
432 OSG::Int16 width
= pPort
->calcPixelWidth();
433 OSG::Int16 height
= pPort
->calcPixelHeight();
435 pPort
->getCamera()->getViewing(view
, width
, height
);
437 view
.multFull( v
, v_es
);
443 // helper to calculate the correct buffer insert positions on std140 or std430
445 std::size_t align_offset(std::size_t base_alignment
, std::size_t base_offset
)
447 return base_alignment
* ((base_alignment
+ base_offset
- 1) / base_alignment
);
452 // Part III: Some routines for handling of the memory buffer and the the creation of
453 // the ShaderStorageBufferObjStdLayoutChunk objects:
455 // i) calc_test_block_buffer_size,
456 // create_test_block_buffer,
457 // create_test_block_state,
458 // update_test_block_state
460 // ii) calc_light_buffer_size,
461 // create_light_buffer,
462 // create_light_state,
463 // update_light_state
465 // iii) calc_material_database_buffer_size,
466 // create_material_database_buffer,
467 // create_material_database_state,
468 // update_material_database_state
470 // iv) calc_geometry_material_buffer_size,
471 // create_geometry_material_buffer,
472 // create_geometry_material_state,
473 // update_geometry_material_state
477 // i) the test block shader storage buffer object
479 std::size_t calc_test_block_buffer_size(const TestBlock
& test_block
)
482 // Introduction to the std430 storage layout
483 // =========================================
485 // When using the "std430" storage layout, structures will be laid out in
486 // buffer storage with its members stored in monotonically increasing order
487 // based on their location in the declaration. A structure and each
488 // structure member have a base offset and a base alignment, from which an
489 // aligned offset is computed by rounding the base offset up to a multiple of
490 // the base alignment. The base offset of the first member of a structure is
491 // taken from the aligned offset of the structure itself. The base offset of
492 // all other structure members is derived by taking the offset of the last
493 // basic machine unit consumed by the previous member and adding one. Each
494 // structure member is stored in memory at its aligned offset. The members
495 // of a top-level shader storage block are laid out in buffer storage by treating
496 // the shader storage block as a structure with a base offset of zero.
498 // When using the std430 storage layout, shader storage blocks will be laid out in
499 // buffer storage identically to uniform and shader storage blocks using the
500 // std140 layout, except that the base alignment and stride of arrays of scalars
501 // and vectors in rule 4 and of structures in rule 9 are not rounded up a multiple
502 // of the base alignment of a vec4.
504 // (1) If the member is a scalar consuming <N> basic machine units, the
505 // base alignment is <N>.
507 // (2) If the member is a two- or four-component vector with components
508 // consuming <N> basic machine units, the base alignment is 2<N> or
509 // 4<N>, respectively.
511 // (3) If the member is a three-component vector with components consuming
512 // <N> basic machine units, the base alignment is 4<N>.
514 // (4) If the member is an array of scalars or vectors, the base alignment
515 // and array stride are set to match the base alignment of a single
516 // array element, according to rules (1), (2), and (3), and are not rounded
517 // up to the base alignment of a vec4. The array may have padding at the
518 // end; the base offset of the member following the array is rounded up
519 // to the next multiple of the base alignment.
521 // (5) If the member is a column-major matrix with <C> columns and <R>
522 // rows, the matrix is stored identically to an array of <C> column
523 // vectors with <R> components each, according to rule (4).
525 // (6) If the member is an array of <S> column-major matrices with <C>
526 // columns and <R> rows, the matrix is stored identically to a row of
527 // <S>*<C> column vectors with <R> components each, according to rule
530 // (7) If the member is a row-major matrix with <C> columns and <R> rows,
531 // the matrix is stored identically to an array of <R> row vectors
532 // with <C> components each, according to rule (4).
534 // (8) If the member is an array of <S> row-major matrices with <C> columns
535 // and <R> rows, the matrix is stored identically to a row of <S>*<R>
536 // row vectors with <C> components each, according to rule (4).
538 // (9) If the member is a structure, the base alignment of the structure is
539 // <N>, where <N> is the largest base alignment value of any of its
540 // members, and are not rounded up to the base alignment of a vec4. The
541 // individual members of this sub-structure are then assigned offsets
542 // by applying this set of rules recursively, where the base offset of
543 // the first member of the sub-structure is equal to the aligned offset
544 // of the structure. The structure may have padding at the end; the
545 // base offset of the member following the sub-structure is rounded up
546 // to the next multiple of the base alignment of the structure.
548 // (10) If the member is an array of <S> structures, the <S> elements of
549 // the array are laid out in order, according to rule (9).
551 // For shader storage blocks laid out according to these rules, the minimum buffer
552 // object size returned by the GL_BUFFER_DATA_SIZE query is derived by
553 // taking the offset of the last basic machine unit consumed by the last
554 // entry of the shader storage block (including any end-of-array or
555 // end-of-structure padding), adding one, and rounding up to the next
556 // multiple of the base alignment required for a vec4.
559 // Using Standard Layout Qualifiers
560 // ================================
561 // When you group a number of variables in a uniform buffer or shader
562 // storage buffer, and want to read or write their values outside a shader, you
563 // need to know the offset of each one. You can query these offsets, but for
564 // large collections of uniforms this process requires many queries and is
565 // cumbersome. As an alternative, the standard layout qualifiers request that
566 // the GLSL shader compiler organize the variables according to a set of rules,
567 // where you can predictably compute the offset of any member in the block.
568 // In order to qualify a block to use the std430 layout, you need to add a
569 // layout directive to its declaration, as demonstrated below:
571 // layout (std430) buffer BufferBlock {
572 // // declared variables
575 // This std430 qualification only works for shader storage buffer objects.
577 // To use these, the offset of a member in the block is the accumulated total
578 // of the alignment and sizes of the previous members in the block (those
579 // declared before the variable in question), bumped up to the alignment of
580 // the member. The starting offset of the first member is always zero.
582 // The std430 Layout Rules
583 // =======================
584 // The set of rules shown in the table are used by the GLSL compiler to place
585 // members in an std430-qualified uniform block. This feature is available
586 // only with GLSL Version 4.30 or greater.
588 // Variable Type Variable Size and Alignment
589 // --------------------------------------------------------------------------------
590 // Scalar bool, int, uint, float and Both the size and alignment are the size
591 // double of the scalar in basic machine types
592 // (e.g., sizeof(GLfloat)).
594 // Two-component vectors (e.g., ivec2) Both the size and alignment are twice
595 // the size of the underlying scalar type.
597 // Three-component vectors (e.g., vec3) Both the size and alignment are four
598 // and times the size of the underlying scalar
599 // Four-component vectors (e.g., vec4) type. However, this is true only when
600 // the member is not part of an array or
603 // An array of scalars or vectors The size of each element in the array
604 // will be the same size of the element
605 // type, where three-component vectors
606 // are not rounded up to the size of
607 // four-component vectors. This is also the
608 // array’s alignment. The array’s size will
609 // be the element’s size times the number
610 // of elements in the array.
612 // A column-major matrix or an array Same layout as an array of N vectors
613 // of column-major matrices of size C each with R components, where N is
614 // columns and R rows the total number of columns present.
616 // A row-major matrix or an array of Same layout as an array of N vectors
617 // row-major matrices with R rows and C each with C components, where N is
618 // columns the total number of rows present.
620 // A single-structure definition or Structure alignment is the same as the
621 // an array of structures alignment for the biggest structure
622 // member, where three-component
623 // vectors are not rounded up to the size of
624 // four-component vectors. Each structure
625 // will start on this alignment, and its size
626 // will be the space needed by its
627 // members, according to the previous
628 // rules, rounded up to a multiple of the
629 // structure alignment.
632 std::size_t ao
= 0; // aligned offset
633 std::size_t bo
= 0; // base offset
634 // layout(std430) uniform Example
636 // // Base types below consume 4 basic machine units
638 // // base base align
639 // // rule align off. off. bytes used
640 // // ---- ------ ---- ---- -----------------------
641 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // Real32 a; // 1 4 0 0 0..3
642 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // Vec2f b; // 2 8 4 8 8..15
643 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // Vec3f c; // 3 16 16 16 16..27
644 ao
= align_offset( 8, bo
); bo
= ao
; // struct { // 9 8 28 32 (align begin)
645 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Int32
); // Int32 d; // 1 4 32 32 32..35
646 ao
= align_offset( 8, bo
); bo
= ao
+ 2*sizeof(OSG::Int32
); // Vec2b e; // 2 8 36 40 40..47
647 ao
= align_offset( 8, bo
); bo
= ao
; // } f; // 9 8 48 48 (pad end)
648 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // Real32 g; // 1 4 48 48 48..51
649 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // Real32 h[2]; // 4 4 52 52 52..55 (h[0])
650 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // // 4 56 56 56..59 (h[1])
651 ao
= align_offset( 4, bo
); bo
= ao
; // // 4 4 60 60 (pad end of h)
652 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // Matrix2x3f i; //5/4/3 16 60 64 64..75 (i, column 0)
653 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 76 80 80..91 (i, column 1)
654 ao
= align_offset(16, bo
); bo
= ao
; // // 5/4 16 92 96 (pad end of i)
655 ao
= align_offset(16, bo
); bo
= ao
; // struct { //10/9 16 96 96 (align begin)
656 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3u
); // Vec3u j; // 3 16 96 96 96..107 (o[0].j)
657 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // Vec2f k; // 2 8 108 112 112..119 (o[0].k)
658 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // Real32 l[2]; // 4 4 120 120 120..123 (o[0].l[0])
659 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // // 4 124 124 124..127 (o[0].l[1])
660 ao
= align_offset( 4, bo
); bo
= ao
; // // 4 4 128 128 (pad end of o[0].l)
661 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // Vec2f m; // 2 8 128 128 128..135 (o[0].m)
662 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // Matrix3f n[2]; // 6/4 16 136 144 144..155 (o[0].n[0], column 0)
663 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 156 160 160..171 (o[0].n[0], column 1)
664 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 172 176 176..187 (o[0].n[0], column 2)
665 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 188 192 192..203 (o[0].n[1], column 0)
666 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 204 208 208..219 (o[0].n[1], column 1)
667 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 220 224 224..235 (o[0].n[1], column 2)
668 ao
= align_offset(16, bo
); bo
= ao
; // // 6/4 16 236 240 (pad end of o[0].n)
669 ao
= align_offset(16, bo
); bo
= ao
; // //10/9 16 240 240 (pad end of o[0])
670 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3u
); // // 3 16 240 240 240..251 (o[1].j)
671 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // // 2 8 252 256 256..263 (o[1].k)
672 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // // 4 4 264 264 264..267 (o[1].l[0])
673 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // // 4 268 268 268..271 (o[1].l[1])
674 ao
= align_offset( 4, bo
); bo
= ao
; // // 4 4 272 272 (pad end of o[1].l)
675 ao
= align_offset( 8, bo
); bo
= ao
+ sizeof(OSG::Vec2f
); // // 2 8 272 272 272..279 (o[1].m)
676 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 6/4 16 280 288 288..299 o[1].n[0], column 0)
677 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 300 304 304..315 (o[1].n[0], column 1)
678 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 316 320 320..331 (o[1].n[0], column 2)
679 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 332 336 336..347 (o[1].n[1], column 0)
680 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 348 352 352..363 (o[1].n[1], column 1)
681 ao
= align_offset(16, bo
); bo
= ao
+ sizeof(OSG::Vec3f
); // // 16 364 368 368..379 (o[1].n[1], column 2)
682 ao
= align_offset(16, bo
); bo
= ao
; // // 6/4 16 380 384 (pad end of o[1].n)
683 ao
= align_offset(16, bo
); bo
= ao
; // //10/9 16 384 384 (pad end of o[1])
689 std::vector
<OSG::UInt8
> create_test_block_buffer(const TestBlock
& test_block
)
691 std::size_t size
= calc_test_block_buffer_size(test_block
);
693 std::vector
<OSG::UInt8
> buffer(size
);
695 std::size_t ao
= 0; // aligned offset
696 std::size_t bo
= 0; // base offset
698 ao
= align_offset( 4, bo
);
699 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.a
;
700 bo
= ao
+ sizeof(OSG::Real32
);
702 ao
= align_offset( 8, bo
);
703 memcpy(&buffer
[0] + ao
, &test_block
.b
[0], sizeof(OSG::Vec2f
));
704 bo
= ao
+ sizeof(OSG::Vec2f
);
706 ao
= align_offset(16, bo
);
707 memcpy(&buffer
[0] + ao
, &test_block
.c
[0], sizeof(OSG::Vec3f
));
708 bo
= ao
+ sizeof(OSG::Vec3f
);
710 ao
= align_offset( 8, bo
);
713 ao
= align_offset( 4, bo
);
714 *(reinterpret_cast<OSG::Int32
*>(&buffer
[0] + ao
)) = test_block
.f
.d
;
715 bo
= ao
+ sizeof(OSG::Int32
);
717 ao
= align_offset( 8, bo
);
718 *(reinterpret_cast<OSG::Int32
*>(&buffer
[0] + ao
)) = test_block
.f
.e
[0];
719 bo
= ao
+ sizeof(OSG::Int32
);
721 *(reinterpret_cast<OSG::Int32
*>(&buffer
[0] + ao
)) = test_block
.f
.e
[1];
722 bo
= ao
+ sizeof(OSG::Int32
);
724 ao
= align_offset( 8, bo
);
727 ao
= align_offset( 4, bo
);
728 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.g
;
729 bo
= ao
+ sizeof(OSG::Real32
);
731 ao
= align_offset( 4, bo
);
732 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.h
[0];
733 bo
= ao
+ sizeof(OSG::Real32
);
735 ao
= align_offset( 4, bo
);
736 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.h
[1];
737 bo
= ao
+ sizeof(OSG::Real32
);
739 ao
= align_offset( 4, bo
);
742 ao
= align_offset(16, bo
);
743 memcpy(&buffer
[0] + ao
, &test_block
.i
.row1
[0], sizeof(OSG::Vec3f
));
744 bo
= ao
+ sizeof(OSG::Vec3f
);
746 ao
= align_offset(16, bo
);
747 memcpy(&buffer
[0] + ao
, &test_block
.i
.row2
[0], sizeof(OSG::Vec3f
));
748 bo
= ao
+ sizeof(OSG::Vec3f
);
750 ao
= align_offset(16, bo
);
753 ao
= align_offset(16, bo
);
756 ao
= align_offset(16, bo
);
757 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].j
[0], sizeof(OSG::Vec3u
));
758 bo
= ao
+ sizeof(OSG::Vec3u
);
760 ao
= align_offset( 8, bo
);
761 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].k
[0], sizeof(OSG::Vec2f
));
762 bo
= ao
+ sizeof(OSG::Vec2f
);
764 ao
= align_offset(4, bo
);
765 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.o
[0].l
[0];
766 bo
= ao
+ sizeof(OSG::Real32
);
768 ao
= align_offset(4, bo
);
769 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.o
[0].l
[1];
770 bo
= ao
+ sizeof(OSG::Real32
);
772 ao
= align_offset(4, bo
);
775 ao
= align_offset( 8, bo
);
776 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].m
[0], sizeof(OSG::Vec2f
));
777 bo
= ao
+ sizeof(OSG::Vec2f
);
779 ao
= align_offset(16, bo
);
780 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[0].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
[0].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
[0].row3
[0], sizeof(OSG::Vec3f
));
789 bo
= ao
+ sizeof(OSG::Vec3f
);
791 ao
= align_offset(16, bo
);
792 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[1].row1
[0], sizeof(OSG::Vec3f
));
793 bo
= ao
+ sizeof(OSG::Vec3f
);
795 ao
= align_offset(16, bo
);
796 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[1].row2
[0], sizeof(OSG::Vec3f
));
797 bo
= ao
+ sizeof(OSG::Vec3f
);
799 ao
= align_offset(16, bo
);
800 memcpy(&buffer
[0] + ao
, &test_block
.o
[0].n
[1].row3
[0], sizeof(OSG::Vec3f
));
801 bo
= ao
+ sizeof(OSG::Vec3f
);
803 ao
= align_offset(16, bo
);
806 ao
= align_offset(16, bo
);
809 ao
= align_offset(16, bo
);
810 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].j
[0], sizeof(OSG::Vec3u
));
811 bo
= ao
+ sizeof(OSG::Vec3u
);
813 ao
= align_offset( 8, bo
);
814 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].k
[0], sizeof(OSG::Vec2f
));
815 bo
= ao
+ sizeof(OSG::Vec2f
);
817 ao
= align_offset( 4, bo
);
818 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.o
[1].l
[0];
819 bo
= ao
+ sizeof(OSG::Real32
);
821 ao
= align_offset( 4, bo
);
822 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = test_block
.o
[1].l
[1];
823 bo
= ao
+ sizeof(OSG::Real32
);
825 ao
= align_offset( 4, bo
);
828 ao
= align_offset( 8, bo
);
829 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].m
[0], sizeof(OSG::Vec2f
));
830 bo
= ao
+ sizeof(OSG::Vec2f
);
832 ao
= align_offset(16, bo
);
833 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[0].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
[0].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
[0].row3
[0], sizeof(OSG::Vec3f
));
842 bo
= ao
+ sizeof(OSG::Vec3f
);
844 ao
= align_offset(16, bo
);
845 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[1].row1
[0], sizeof(OSG::Vec3f
));
846 bo
= ao
+ sizeof(OSG::Vec3f
);
848 ao
= align_offset(16, bo
);
849 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[1].row2
[0], sizeof(OSG::Vec3f
));
850 bo
= ao
+ sizeof(OSG::Vec3f
);
852 ao
= align_offset(16, bo
);
853 memcpy(&buffer
[0] + ao
, &test_block
.o
[1].n
[1].row3
[0], sizeof(OSG::Vec3f
));
854 bo
= ao
+ sizeof(OSG::Vec3f
);
856 ao
= align_offset(16, bo
);
859 ao
= align_offset(16, bo
);
865 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr
create_test_block_state(const TestBlock
& test_block
)
867 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjStdLayoutChunk::create();
869 std::vector
<OSG::UInt8
> buffer
= create_test_block_buffer(test_block
);
871 ssbo
->editMFBuffer()->setValues(buffer
);
872 ssbo
->setUsage(GL_DYNAMIC_DRAW
);
874 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo
);
877 void update_test_block_state(OSG::ShaderStorageBufferObjStdLayoutChunk
* ssbo
, const TestBlock
& test_block
)
880 std::vector
<OSG::UInt8
> buffer
= create_test_block_buffer(test_block
);
881 ssbo
->editMFBuffer()->setValues(buffer
);
886 // ii) the light shader storage buffer object
888 std::size_t calc_light_buffer_size(const VecLightsT
& vLights
)
890 std::size_t ao
= 0; // aligned offset
891 std::size_t bo
= 0; // base offset
893 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Pnt4f
); // OSG::Pnt3f position;
894 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Vec4f
); // OSG::Vec3f spot_direction;
895 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f Ia;
896 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f Id;
897 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f Is;
898 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Vec4f
); // OSG::Vec3f attenuation;
899 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // OSG::Real32 spot_cos_cutoff;
900 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // OSG::Real32 spot_exponent;
901 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Int32
); // OSG::Int32 type;
902 ao
= align_offset( 16, bo
); bo
= ao
; // padding
904 ao
*= vLights
.size(); bo
= ao
; // array
905 ao
= align_offset( 16, bo
); bo
= ao
; // padding
910 std::vector
<OSG::UInt8
> create_light_buffer(const VecLightsT
& vLights
)
912 std::size_t size
= calc_light_buffer_size(vLights
);
914 std::vector
<OSG::UInt8
> buffer(size
);
916 std::size_t ao
= 0; // aligned offset
917 std::size_t bo
= 0; // base offset
919 for (std::size_t i
= 0; i
< vLights
.size(); ++i
)
921 OSG::Pnt3f position_es
= transform_to_eye_space(vLights
[i
].position
, mgr
);
922 OSG::Vec3f spot_direction_es
= transform_to_eye_space(vLights
[i
].spot_direction
, mgr
);
924 ao
= align_offset(16, bo
);
925 memcpy(&buffer
[0] + ao
, &position_es
[0], sizeof(OSG::Pnt3f
));
926 bo
= ao
+ sizeof(OSG::Pnt4f
);
928 ao
= align_offset(16, bo
);
929 memcpy(&buffer
[0] + ao
, &spot_direction_es
[0], sizeof(OSG::Vec3f
));
930 bo
= ao
+ sizeof(OSG::Vec4f
);
932 ao
= align_offset(16, bo
);
933 memcpy(&buffer
[0] + ao
, &vLights
[i
].Ia
[0], sizeof(OSG::Color3f
));
934 bo
= ao
+ sizeof(OSG::Color4f
);
936 ao
= align_offset(16, bo
);
937 memcpy(&buffer
[0] + ao
, &vLights
[i
].Id
[0], sizeof(OSG::Color3f
));
938 bo
= ao
+ sizeof(OSG::Color4f
);
940 ao
= align_offset(16, bo
);
941 memcpy(&buffer
[0] + ao
, &vLights
[i
].Is
[0], sizeof(OSG::Color3f
));
942 bo
= ao
+ sizeof(OSG::Color4f
);
944 ao
= align_offset(16, bo
);
945 memcpy(&buffer
[0] + ao
, &vLights
[i
].attenuation
[0], sizeof(OSG::Vec3f
));
946 bo
= ao
+ sizeof(OSG::Vec4f
);
948 ao
= align_offset( 4, bo
);
949 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = vLights
[i
].spot_cos_cutoff
;
950 bo
= ao
+ sizeof(OSG::Real32
);
952 ao
= align_offset( 4, bo
);
953 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = vLights
[i
].spot_exponent
;
954 bo
= ao
+ sizeof(OSG::Real32
);
956 ao
= align_offset( 4, bo
);
957 *(reinterpret_cast<OSG::Int32
*>(&buffer
[0] + ao
)) = vLights
[i
].type
;
958 bo
= ao
+ sizeof(OSG::Int32
);
960 ao
= align_offset( 16, bo
); bo
= ao
; // padding
966 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr
create_light_state(const VecLightsT
& vLights
)
968 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjStdLayoutChunk::create();
970 std::vector
<OSG::UInt8
> buffer
= create_light_buffer(vLights
);
972 ssbo
->editMFBuffer()->setValues(buffer
);
973 ssbo
->setUsage(GL_DYNAMIC_DRAW
);
975 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo
);
978 void update_light_state(OSG::ShaderStorageBufferObjStdLayoutChunk
* ssbo
, const VecLightsT
& vLights
)
981 std::vector
<OSG::UInt8
> buffer
= create_light_buffer(vLights
);
982 ssbo
->editMFBuffer()->setValues(buffer
);
987 // iii) the material shader storage buffer object
989 std::size_t calc_material_database_buffer_size(const VecMaterialsT
& vMaterials
)
991 std::size_t ao
= 0; // aligned offset
992 std::size_t bo
= 0; // base offset
994 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f ambient;
995 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f diffuse;
996 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f specular;
997 ao
= align_offset( 16, bo
); bo
= ao
+ sizeof(OSG::Color4f
); // OSG::Color3f emissive;
998 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // OSG::Real32 opacity;
999 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::Real32
); // OSG::Real32 shininess;
1000 ao
= align_offset( 16, bo
); bo
= ao
; // padding
1002 ao
*= vMaterials
.size(); bo
= ao
; // array
1003 ao
= align_offset( 16, bo
); bo
= ao
; // padding
1008 std::vector
<OSG::UInt8
> create_material_database_buffer(const VecMaterialsT
& vMaterials
)
1010 std::size_t size
= calc_material_database_buffer_size(vMaterials
);
1012 std::vector
<OSG::UInt8
> buffer(size
);
1014 std::size_t ao
= 0; // aligned offset
1015 std::size_t bo
= 0; // base offset
1017 for (std::size_t i
= 0; i
< vMaterials
.size(); ++i
)
1019 ao
= align_offset(16, bo
);
1020 memcpy(&buffer
[0] + ao
, &vMaterials
[i
].ambient
[0], sizeof(OSG::Color3f
));
1021 bo
= ao
+ sizeof(OSG::Color4f
);
1023 ao
= align_offset(16, bo
);
1024 memcpy(&buffer
[0] + ao
, &vMaterials
[i
].diffuse
[0], sizeof(OSG::Color3f
));
1025 bo
= ao
+ sizeof(OSG::Color4f
);
1027 ao
= align_offset(16, bo
);
1028 memcpy(&buffer
[0] + ao
, &vMaterials
[i
].specular
[0], sizeof(OSG::Color3f
));
1029 bo
= ao
+ sizeof(OSG::Color4f
);
1031 ao
= align_offset(16, bo
);
1032 memcpy(&buffer
[0] + ao
, &vMaterials
[i
].emissive
[0], sizeof(OSG::Color3f
));
1033 bo
= ao
+ sizeof(OSG::Color4f
);
1035 ao
= align_offset( 4, bo
);
1036 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = vMaterials
[i
].opacity
;
1037 bo
= ao
+ sizeof(OSG::Real32
);
1039 ao
= align_offset( 4, bo
);
1040 *(reinterpret_cast<OSG::Real32
*>(&buffer
[0] + ao
)) = vMaterials
[i
].shininess
;
1041 bo
= ao
+ sizeof(OSG::Real32
);
1043 ao
= align_offset( 16, bo
); bo
= ao
; // padding
1049 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr
create_material_database_state(const VecMaterialsT
& vMaterials
)
1051 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1053 std::vector
<OSG::UInt8
> buffer
= create_material_database_buffer(vMaterials
);
1055 ssbo
->editMFBuffer()->setValues(buffer
);
1056 ssbo
->setUsage(GL_STATIC_DRAW
);
1058 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo
);
1061 void update_material_database_state(OSG::ShaderStorageBufferObjStdLayoutChunk
* ssbo
, const VecMaterialsT
& vMaterials
)
1064 std::vector
<OSG::UInt8
> buffer
= create_material_database_buffer(vMaterials
);
1065 ssbo
->editMFBuffer()->setValues(buffer
);
1070 // iv) the geomertry shader storage buffer object
1072 std::size_t calc_geometry_material_buffer_size()
1074 std::size_t ao
= 0; // aligned offset
1075 std::size_t bo
= 0; // base offset
1077 ao
= align_offset( 4, bo
); bo
= ao
+ sizeof(OSG::UInt32
); // OSG::UInt32 material_index;
1078 ao
= align_offset( 16, bo
); bo
= ao
; // padding
1083 std::vector
<OSG::UInt8
> create_geometry_material_buffer(const GeomState
& geom_state
)
1085 std::size_t size
= calc_geometry_material_buffer_size();
1087 std::vector
<OSG::UInt8
> buffer(size
);
1089 std::size_t ao
= 0; // aligned offset
1090 std::size_t bo
= 0; // base offset
1092 ao
= align_offset( 4, bo
);
1093 *(reinterpret_cast<OSG::UInt32
*>(&buffer
[0] + ao
)) = geom_state
.material_index
;
1094 bo
= ao
+ sizeof(OSG::UInt32
);
1099 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr
create_geometry_material_state(const GeomState
& geom_state
)
1101 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo
= OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1103 std::vector
<OSG::UInt8
> buffer
= create_geometry_material_buffer(geom_state
);
1105 ssbo
->editMFBuffer()->setValues(buffer
);
1106 ssbo
->setUsage(GL_DYNAMIC_DRAW
);
1108 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo
);
1111 void update_geometry_material_state(OSG::ShaderStorageBufferObjStdLayoutChunk
* ssbo
, const GeomState
& geom_state
)
1114 std::vector
<OSG::UInt8
> buffer
= create_geometry_material_buffer(geom_state
);
1115 ssbo
->editMFBuffer()->setValues(buffer
);
1120 // Part IV: The application starts here
1124 // vertex shader program.
1126 std::string
get_vp_program();
1129 // fragment shader program for bump mapping in surface local coordinates
1131 std::string
get_fp_program();
1134 // random number generator
1136 boost::random::mt19937 generator
;
1137 boost::random::uniform_int_distribution
<> dist(0, num_materials
-1);
1140 // a separate transformation for every object
1142 OSG::TransformRefPtr cyltrans
, tortrans
;
1145 // Shader Storage buffer objects corresponding to transient shader blocks
1147 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_light_state
= NULL
;
1148 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_geom_state_1
= NULL
;
1149 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_geom_state_2
= NULL
;
1152 // forward declaration so we can have the interesting stuff upfront
1154 int setupGLUT(int *argc
, char *argv
[]);
1157 // redraw the window
1161 // light spot direction and light position must be provided in eye space
1162 update_light_state(ssbo_light_state
, lights
);
1164 // create the matrix
1166 OSG::Real32 t
= glutGet(GLUT_ELAPSED_TIME
);
1168 // set the transforms' matrices
1169 m
.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t
/ 1000.f
) * 1.5),
1170 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t
/ 500.f
));
1172 cyltrans
->setMatrix(m
);
1174 m
.setTransform(OSG::Vec3f(OSG::osgSin(t
/ 1000.f
), 0, 0),
1175 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t
/ 1000.f
));
1177 tortrans
->setMatrix(m
);
1179 OSG::commitChanges();
1185 // Initialize GLUT & OpenSG and set up the scene
1187 int main(int argc
, char **argv
)
1190 OSG::osgInit(argc
,argv
);
1193 int winid
= setupGLUT(&argc
, argv
);
1195 // open a new scope, because the pointers below should go out of scope
1196 // before entering glutMainLoop.
1197 // Otherwise OpenSG will complain about objects being alive after shutdown.
1199 // the connection between GLUT and OpenSG
1200 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
1201 gwin
->setGlutId(winid
);
1204 // create the SimpleSceneManager helper
1205 mgr
= OSG::SimpleSceneManager::create();
1206 mgr
->setWindow(gwin
);
1208 // create a pretty simple graph: a Group with two Transforms as children,
1209 // each of which carries a single Geometry.
1213 OSG::NodeRefPtr scene
= OSG::Node::create();
1215 // The cylinder and its transformation
1216 OSG::NodeRefPtr cyl
= OSG::Node::create();
1217 OSG::GeometryRefPtr cylgeo
= OSG::makeCylinderGeo( 1.4f
, .3f
, 24,
1220 cyl
->setCore(cylgeo
);
1222 cyltrans
= OSG::Transform::create();
1224 OSG::NodeRefPtr cyltransnode
= OSG::Node::create();
1225 cyltransnode
->setCore (cyltrans
);
1226 cyltransnode
->addChild(cyl
);
1228 // add it to the scene
1229 scene
->addChild(cyltransnode
);
1231 // The torus and its transformation
1232 OSG::NodeRefPtr torus
= OSG::Node::create();
1233 OSG::GeometryRefPtr torusgeo
= OSG::makeTorusGeo( .2f
, 1, 24, 36 );
1235 torus
->setCore(torusgeo
);
1237 tortrans
= OSG::Transform::create();
1239 OSG::NodeRefPtr tortransnode
= OSG::Node::create();
1240 tortransnode
->setCore (tortrans
);
1241 tortransnode
->addChild(torus
);
1243 // add it to the scene
1244 scene
->addChild(tortransnode
);
1247 // create the shader program
1249 OSG::ShaderProgramChunkRefPtr prog_chunk
= OSG::ShaderProgramChunk::create();
1250 OSG::ShaderProgramRefPtr vertShader
= OSG::ShaderProgram::createVertexShader();
1251 OSG::ShaderProgramRefPtr fragShader
= OSG::ShaderProgram::createFragmentShader();
1253 vertShader
->setProgram(get_vp_program());
1254 fragShader
->setProgram(get_fp_program());
1257 // binding the shader storage block to a buffer binding point can be performed
1258 // either by calling the shaders's addShaderStorageBlock method or by
1259 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
1260 // In the following we use both variants for illustration.
1262 fragShader
->addShaderStorageBlock("Materials", 1); // block binding point
1263 fragShader
->addShaderStorageBlock("Lights", 2); // block binding point
1266 // The following is replaced by adding ShaderProgramVariableChunk objects
1267 // to the chunk material. See below...
1269 // fragShader->addShaderStorageBlock("GeomState", 3); // block binding point
1271 fragShader
->addShaderStorageBlock("TestBlock", 4); // block binding point
1273 prog_chunk
->addShader(vertShader
);
1274 prog_chunk
->addShader(fragShader
);
1277 // create shader storage buffer objects and corresponding materials
1279 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_material_database
= create_material_database_state(materials
);
1280 ssbo_light_state
= create_light_state(lights
);
1282 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_test_block
= create_test_block_state(global_test_block
);
1284 OSG::PolygonChunkRefPtr polygon_chunk
= OSG::PolygonChunk::create();
1285 polygon_chunk
->setFrontMode(GL_FILL
);
1286 polygon_chunk
->setBackMode(GL_FILL
);
1287 polygon_chunk
->setCullFace(GL_NONE
);
1289 OSG::DepthChunkRefPtr depth_chunk
= OSG::DepthChunk::create();
1290 depth_chunk
->setEnable(true);
1292 OSG::ChunkMaterialRefPtr prog_state
= OSG::ChunkMaterial::create();
1293 prog_state
->addChunk(ssbo_material_database
, 1); // buffer binding point 1
1294 prog_state
->addChunk(ssbo_light_state
, 2); // buffer binding point 2
1295 prog_state
->addChunk(ssbo_test_block
, 4); // buffer binding point 4
1296 prog_state
->addChunk(prog_chunk
);
1297 prog_state
->addChunk(polygon_chunk
);
1298 prog_state
->addChunk(depth_chunk
);
1300 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk
= OSG::ShaderProgramVariableChunk::create();
1301 shader_var_chunk
->addShaderStorageBlock("GeomState", 3);
1303 GeomState geom1
; geom1
.material_index
= dist(generator
);
1304 OSG::ChunkMaterialRefPtr geom1_state
= OSG::ChunkMaterial::create();
1305 ssbo_geom_state_1
= create_geometry_material_state(geom1
);
1306 geom1_state
->addChunk(ssbo_geom_state_1
, 3); // buffer binding point 3
1307 geom1_state
->addChunk(shader_var_chunk
); // block binding point
1309 GeomState geom2
; geom2
.material_index
= dist(generator
);
1310 OSG::ChunkMaterialRefPtr geom2_state
= OSG::ChunkMaterial::create();
1311 ssbo_geom_state_2
= create_geometry_material_state(geom2
);
1312 geom2_state
->addChunk(ssbo_geom_state_2
, 3); // buffer binding point 3
1313 geom2_state
->addChunk(shader_var_chunk
); // block binding point
1315 cylgeo
->setMaterial(geom1_state
);
1316 torusgeo
->setMaterial(geom2_state
);
1318 OSG::MaterialChunkOverrideGroupRefPtr mgrp
= OSG::MaterialChunkOverrideGroup::create();
1319 mgrp
->setMaterial(prog_state
);
1320 scene
->setCore(mgrp
);
1322 OSG::commitChanges();
1324 mgr
->setRoot(scene
);
1326 // show the whole scene
1337 // GLUT callback functions
1341 // react to size changes
1343 void reshape(int w
, int h
)
1346 glutPostRedisplay();
1350 // react to mouse button presses
1352 void mouse(int button
, int state
, int x
, int y
)
1355 mgr
->mouseButtonRelease(button
, x
, y
);
1357 mgr
->mouseButtonPress(button
, x
, y
);
1359 glutPostRedisplay();
1363 // react to mouse motions with pressed buttons
1365 void motion(int x
, int y
)
1367 mgr
->mouseMove(x
, y
);
1368 glutPostRedisplay();
1374 void keyboard(unsigned char k
, int x
, int y
)
1380 // clean up global variables
1385 ssbo_light_state
= NULL
;
1386 ssbo_geom_state_1
= NULL
;
1387 ssbo_geom_state_2
= NULL
;
1396 GeomState geom1
; geom1
.material_index
= dist(generator
);
1397 GeomState geom2
; geom2
.material_index
= dist(generator
);
1399 update_geometry_material_state(ssbo_geom_state_1
, geom1
);
1400 update_geometry_material_state(ssbo_geom_state_2
, geom2
);
1402 glutPostRedisplay();
1408 mgr
->setStatistics(!mgr
->getStatistics());
1415 // setup the GLUT library which handles the windows for us
1417 int setupGLUT(int *argc
, char *argv
[])
1419 glutInit(argc
, argv
);
1420 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
1422 int winid
= glutCreateWindow("OpenSG");
1424 glutReshapeFunc(reshape
);
1425 glutDisplayFunc(display
);
1426 glutMouseFunc(mouse
);
1427 glutMotionFunc(motion
);
1428 glutKeyboardFunc(keyboard
);
1430 // call the redraw function whenever there's nothing else to do
1431 glutIdleFunc(display
);
1437 // Part V: The shader programs
1441 // vertex shader program.
1443 std::string
get_vp_program()
1445 std::string vp_program
=
1447 "#version 440 compatibility\n"
1449 "#extension GL_ARB_separate_shader_objects: enable\n"
1450 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
1452 "smooth out vec3 vNormalES; // eye space normal\n"
1453 "smooth out vec3 vPositionES; // eye space position\n"
1458 " // multiply the object space vertex position with the modelview matrix \n"
1459 " // to get the eye space vertex position\n"
1461 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
1464 " // multiply the object space normal with the normal matrix (transpose of the inverse \n"
1465 " // model view matrix) to get the eye space normal\n"
1467 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
1470 " // multiply the combiend modelview projection matrix with the object space vertex\n"
1471 " // position to get the clip space position\n"
1473 " gl_Position = ftransform();\n"
1481 // fragment shader program for bump mapping in surface local coordinates
1483 std::string
get_fp_program()
1485 std::string fp_program
=
1487 "#version 440 compatibility\n"
1489 "#extension GL_ARB_separate_shader_objects: enable\n"
1490 "#extension GL_ARB_shader_storage_buffer_object: enable\n"
1492 "smooth in vec3 vNormalES; // eye space normal\n"
1493 "smooth in vec3 vPositionES; // eye space position\n"
1495 "const int num_lights = 2;\n"
1496 "const int num_materials = 5000;\n"
1498 "const int directional_light = 0;\n"
1499 "const int point_light = 1;\n"
1500 "const int spot_light = 2;\n"
1501 "const int no_light = 3;\n"
1505 " vec4 position; // in eye space\n"
1506 " vec4 spot_direction; // in eye space\n"
1508 " vec4 Ia; // ambient max. Intensity\n"
1509 " vec4 Id; // diffuse max. Intensity\n"
1510 " vec4 Is; // specular max. Intensity\n"
1512 " vec4 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
1514 " float spot_cos_cutoff; // cosine cut of angle\n"
1516 " float spot_exponent; // [0-128]\n"
1517 " int type; // directional_light, point_light, spot_light, no_light\n"
1520 "layout (std430) buffer Lights\n"
1522 " Light light[num_lights];\n"
1533 " float shininess;\n"
1536 "layout (std430) buffer Materials\n"
1538 " Material material[num_materials];\n"
1542 "layout (std430) buffer GeomState\n"
1544 " int material_index;\n"
1547 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
1549 "layout(location = 0) out vec4 vFragColor;\n"
1552 "// The test block from the GL_ARB_uniform_buffer_object\n"
1553 "// specification. \n"
1570 "layout (std430) buffer TestBlock\n"
1583 "// directional light contribution\n"
1585 "vec3 directionalLight(\n"
1586 " in int i, // light identifier, i.e. current light\n"
1587 " in int j, // material identifier\n"
1588 " in vec3 n, // vertex normal in eye space\n"
1589 " in vec3 v) // view direction in eye space\n"
1591 " if (lights.light[i].type != directional_light)\n"
1592 " return vec3(0.0, 0.0, 0.0);\n"
1595 " // the light direction in eye space\n"
1597 " vec3 l = -lights.light[i].spot_direction.xyz; // we carry the directional light direction in the spot_direction slot\n"
1600 " // the half vector\n"
1602 " vec3 h = normalize(l + v);\n"
1604 " float n_dot_l = max(0.0, dot(n, l));\n"
1605 " float n_dot_h = max(0.0, dot(n, h));\n"
1607 " float m = materials.material[j].shininess;\n"
1609 " float pf; // power factor\n"
1611 " if (n_dot_l == 0.0)\n"
1614 " pf = pow(n_dot_h, m);\n"
1616 " return materials.material[j].emissive.rgb \n"
1617 " + lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1618 " + lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1619 " + lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1623 "// point light contribution\n"
1625 "vec3 pointLight(\n"
1626 " in int i, // light identifier, i.e. current light\n"
1627 " in int j, // material identifier\n"
1628 " in vec3 n, // vertex normal in eye space\n"
1629 " in vec3 v, // view direction in eye space\n"
1630 " in vec3 p) // vertex position in eye space\n"
1632 " if (lights.light[i].type != point_light)\n"
1633 " return vec3(0.0, 0.0, 0.0);\n"
1635 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1636 " float d = length(l); // distance from surface to light source\n"
1637 " l = normalize(l); // normalized direction from surface to light position\n"
1640 " // the half vector\n"
1642 " vec3 h = normalize(l + v);\n"
1644 " float n_dot_l = max(0.0, dot(n, l));\n"
1645 " float n_dot_h = max(0.0, dot(n, h));\n"
1647 " float m = materials.material[j].shininess;\n"
1649 " float pf; // power factor\n"
1651 " if (n_dot_l == 0.0)\n"
1654 " pf = pow(n_dot_h, m);\n"
1657 " // Compute attenuation\n"
1659 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1660 " (lights.light[i].attenuation.y * d) + \n"
1661 " (lights.light[i].attenuation.z * d * d));\n"
1663 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1665 " return materials.material[j].emissive.rgb \n"
1666 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1667 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1668 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1672 "// spot light contribution\n"
1675 " in int i, // light identifier, i.e. current light\n"
1676 " in int j, // material identifier\n"
1677 " in vec3 n, // vertex normal in eye space\n"
1678 " in vec3 v, // view direction in eye space\n"
1679 " in vec3 p) // vertex position in eye space\n"
1681 " if (lights.light[i].type != spot_light)\n"
1682 " return vec3(0.0, 0.0, 0.0);\n"
1684 " vec3 l = vec3(lights.light[i].position.xyz) - p; // direction from surface to light position\n"
1685 " float d = length(l); // distance from surface to light source\n"
1686 " l = normalize(l); // normalized direction from surface to light position\n"
1688 " vec3 s = lights.light[i].spot_direction.xyz; // spot direction\n"
1691 " // the half vector\n"
1693 " vec3 h = normalize(l + v);\n"
1695 " float n_dot_l = max(0.0, dot(n, l));\n"
1696 " float n_dot_h = max(0.0, dot(n, h));\n"
1697 " float l_dot_s = dot(-l, s);\n"
1699 " float m = materials.material[j].shininess;\n"
1701 " float pf; // power factor\n"
1703 " if (n_dot_l == 0.0)\n"
1706 " pf = pow(n_dot_h, m);\n"
1709 " // Compute attenuation\n"
1711 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
1712 " (lights.light[i].attenuation.y * d) + \n"
1713 " (lights.light[i].attenuation.z * d * d));\n"
1715 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
1717 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
1718 " attenuation = 0.0;\n"
1720 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\n"
1722 " return materials.material[j].emissive.rgb \n"
1723 " + attenuation * lights.light[i].Ia.rgb * materials.material[j].ambient.rgb \n"
1724 " + attenuation * lights.light[i].Id.rgb * materials.material[j].diffuse.rgb * n_dot_l // / PI\n"
1725 " + attenuation * lights.light[i].Is.rgb * materials.material[j].specular.rgb * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
1731 " // normalize the eye space normal\n"
1733 " vec3 N = normalize(vNormalES);\n"
1736 " // get the view vector and normalize it\n"
1738 " vec3 V = normalize(cCameraPositionES - vPositionES);\n"
1741 " // Integrate over all lights: Any unused light does not contribute and each light\n"
1742 " // contribute either from the directional light, the point light or the spot light.\n"
1744 " vec3 color = vec3(0.0, 0.0, 0.0);\n"
1745 " for (int i = 0; i < num_lights; ++i) {\n"
1746 " color += directionalLight(i, geom_state.material_index, N, V) \n"
1747 " + pointLight(i, geom_state.material_index, N, V, vPositionES) \n"
1748 " + spotLight(i, geom_state.material_index, N, V, vPositionES);\n"
1750 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"
1753 " // Test TestBlock\n"
1755 " if (test_block.a != 27.4) vFragColor = vec4(1, 0, 0, 1);\n"
1756 " if (test_block.b != vec2(15.3, 12.8)) vFragColor = vec4(1, 0, 0, 1);\n"
1757 " if (test_block.c != vec3(11.4, 21.9, 10.5)) vFragColor = vec4(1, 0, 0, 1);\n"
1759 " if (test_block.f.d != 61) vFragColor = vec4(1, 0, 0, 1);\n"
1760 " if (test_block.f.e != bvec2(true, false)) vFragColor = vec4(1, 0, 0, 1);\n"
1762 " if (test_block.g != 57.3) vFragColor = vec4(1, 0, 0, 1);\n"
1764 " if (test_block.h[0] != 9.1) vFragColor = vec4(1, 0, 0, 1);\n"
1765 " if (test_block.h[1] != 17.56) vFragColor = vec4(1, 0, 0, 1);\n"
1767 " if (test_block.i[0] != vec3(19.43,1243.2, 0.56)) vFragColor = vec4(1, 0, 0, 1);\n"
1768 " if (test_block.i[1] != vec3(13.54,264.22, 65.52)) vFragColor = vec4(1, 0, 0, 1);\n"
1770 " if (test_block.o[0].j != uvec3(10,11,12)) vFragColor = vec4(1, 0, 0, 1);\n"
1771 " if (test_block.o[0].k != vec2(64.62, 275.21)) vFragColor = vec4(1, 0, 0, 1);\n"
1772 " if (test_block.o[0].l[0] != 41.346) vFragColor = vec4(1, 0, 0, 1);\n"
1773 " if (test_block.o[0].l[1] != 67.9456) vFragColor = vec4(1, 0, 0, 1);\n"
1774 " if (test_block.o[0].m != vec2(-56.62, 768.276)) vFragColor = vec4(1, 0, 0, 1);\n"
1775 " if (test_block.o[0].n[0][0] != vec3(-0.4,-0.5,-0.6)) vFragColor = vec4(1, 0, 0, 1);\n"
1776 " if (test_block.o[0].n[0][1] != vec3(-0.7,-0.8,-0.9)) vFragColor = vec4(1, 0, 0, 1);\n"
1777 " if (test_block.o[0].n[0][2] != vec3(-0.1,-0.2,-0.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1778 " if (test_block.o[0].n[1][0] != vec3(1.1,2.2,3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1779 " if (test_block.o[0].n[1][1] != vec3(1.2,2.3,3.4)) vFragColor = vec4(1, 0, 0, 1);\n"
1780 " if (test_block.o[0].n[1][2] != vec3(1.3,2.4,3.5)) vFragColor = vec4(1, 0, 0, 1);\n"
1782 " if (test_block.o[1].j != uvec3(20,31,42)) vFragColor = vec4(1, 0, 0, 1);\n"
1783 " if (test_block.o[1].k != vec2(-96.62, -658.456)) vFragColor = vec4(1, 0, 0, 1);\n"
1784 " if (test_block.o[1].l[0] != 88.34) vFragColor = vec4(1, 0, 0, 1);\n"
1785 " if (test_block.o[1].l[1] != -488.21) vFragColor = vec4(1, 0, 0, 1);\n"
1786 " if (test_block.o[1].m != vec2(777.7, 888.8)) vFragColor = vec4(1, 0, 0, 1);\n"
1787 " if (test_block.o[1].n[0][0] != vec3(1.1,1.2,1.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1788 " if (test_block.o[1].n[0][1] != vec3(2.1,2.2,2.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1789 " if (test_block.o[1].n[0][2] != vec3(3.1,3.2,3.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1790 " if (test_block.o[1].n[1][0] != vec3(-1.1,-1.2,-1.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1791 " if (test_block.o[1].n[1][1] != vec3(-2.1,-2.2,-2.3)) vFragColor = vec4(1, 0, 0, 1);\n"
1792 " if (test_block.o[1].n[1][2] != vec3(-3.1,-3.2,-3.3)) vFragColor = vec4(1, 0, 0, 1);\n"