1 // OpenSG Tutorial Example: UniformBufferObject
3 // This example shows how to create a shader uniform block and binding it
4 // to a uniform buffer object.
6 // The example does use the UniformBufferObjChunk which allows the host
7 // application to provide the uniform block member values directly to
8 // the chunk. The layout of the uniform block is determined by the
9 // shader code. Any of the layout values of the specification (shared,
10 // packed, std140) are allowed.
11 // It is however, important the the order and the cardinality of the
12 // members is matched exactly.
14 // Internally, the shader uniform block is queried for the offsets,
15 // array and matrix strides of the block variables.
19 #include <boost/random/mersenne_twister.hpp>
20 #include <boost/random/uniform_int_distribution.hpp>
22 #ifdef OSG_BUILD_ACTIVE
25 #include <OSGConfig.h>
26 #include <OSGSimpleGeometry.h>
27 #include <OSGGLUTWindow.h>
28 #include <OSGSimpleSceneManager.h>
29 #include <OSGBaseFunctions.h>
30 #include <OSGTransform.h>
35 #include <OSGShaderProgramChunk.h>
36 #include <OSGShaderProgram.h>
37 #include <OSGShaderVariableOSG.h>
38 #include <OSGChunkMaterial.h>
39 #include <OSGMaterialGroup.h>
40 #include <OSGMaterialChunkOverrideGroup.h>
41 #include <OSGUniformBufferObjChunk.h>
42 #include <OSGPolygonChunk.h>
43 #include <OSGDepthChunk.h>
44 #include <OSGShaderProgramVariableChunk.h>
48 #include <OpenSG/OSGGLUT.h>
49 #include <OpenSG/OSGConfig.h>
50 #include <OpenSG/OSGSimpleGeometry.h>
51 #include <OpenSG/OSGGLUTWindow.h>
52 #include <OpenSG/OSGSimpleSceneManager.h>
53 #include <OpenSG/OSGBaseFunctions.h>
54 #include <OpenSG/OSGTransform.h>
55 #include <OpenSG/OSGGroup.h>
58 #include <OpenSG/OSGGLEXT.h>
59 #include <OpenSG/OSGShaderProgramChunk.h>
60 #include <OpenSG/OSGShaderProgram.h>
61 #include <OpenSG/OSGShaderVariableOSG.h>
62 #include <OpenSG/OSGChunkMaterial.h>
63 #include <OpenSG/OSGMaterialGroup.h>
64 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
65 #include <OpenSG/OSGUniformBufferObjChunk.h>
66 #include <OpenSG/OSGPolygonChunk.h>
67 #include <OpenSG/OSGDepthChunk.h>
68 #include <OpenSG/OSGShaderProgramVariableChunk.h>
74 // Activate a test mode that does test the material and light at index 0,
75 // respectively, against specific values set by the application. If all
76 // values are read correctly in the shader the geometry is colored in green.
77 // Otherwise the geometry is colored red indicating failure.
79 //#define USE_TEST_FP_SHADER
82 // The SimpleSceneManager to manage simple applications
84 OSG::SimpleSceneManagerRefPtr mgr
;
87 // simple light data structure
93 directional_light
= 0,
100 : position(0.f
, 0.f
, 0.f
)
101 , spot_direction(0.f
, 1.f
, 0.f
)
105 , attenuation(1.f
, 0.f
, 0.f
)
106 , spot_cos_cutoff(cosf(45.f
))
111 static Light
create_light(Type e
)
117 case directional_light
: l
.spot_direction
= OSG::Vec3f(1.f
, 0.f
, 0.f
);
119 case point_light
: l
.position
= OSG::Pnt3f(0.f
, 0.2f
, 0.f
);
121 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
;
129 OSG::Pnt3f position
; // in object space
130 OSG::Vec3f spot_direction
; // in object space, also used for dir of directional lights (see shader code)
131 OSG::Color3f Ia
; // ambient max. Intensity
132 OSG::Color3f Id
; // diffuse max. Intensity
133 OSG::Color3f Is
; // specular max. Intensity
135 OSG::Vec3f attenuation
; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0
136 OSG::Real32 spot_cos_cutoff
; // cosine cut of angle
137 OSG::Real32 spot_exponent
; // [0-128]
138 OSG::Int32 type
; // directional_light, point_light, spot_light, no_light
141 typedef std::vector
<Light
> VecLightsT
; // multiple lights
143 const std::size_t num_lights
= 1; // simple example with just one light
145 VecLightsT
initialize_lights() // helper to create lights
149 lights
.push_back(Light::create_light(Light::directional_light
));
151 assert(lights
.size() == num_lights
);
156 VecLightsT lights
= initialize_lights(); // the lights
160 // Simple material data structure
165 : ambient (0.f
, 0.f
, 0.f
)
166 , diffuse (0.f
, 0.f
, 0.f
)
167 , specular(0.f
, 0.f
, 0.f
)
168 , emissive(0.f
, 0.f
, 0.f
)
173 OSG::Color3f ambient
;
174 OSG::Color3f diffuse
;
175 OSG::Color3f specular
;
176 OSG::Color3f emissive
;
179 OSG::Real32 shininess
;
182 typedef std::vector
<Material
> VecMaterialsT
; // multiple materials
184 VecMaterialsT
initialize_materials(std::size_t num
) // helper to create materials
186 VecMaterialsT materials
;
188 for (std::size_t i
= 0; i
< num
; ++i
)
192 m
.ambient
= OSG::Color3f(0.1f
, 0.1f
, 0.1f
);
193 m
.diffuse
.setRandom();
194 m
.specular
= OSG::Color3f(0.9f
, 0.9f
, 0.9f
);
195 m
.emissive
= OSG::Color3f(0.0f
, 0.0f
, 0.0f
);
199 materials
.push_back(m
);
205 const std::size_t num_materials
= 100; // any numnber of materials
206 VecMaterialsT materials
= initialize_materials(num_materials
); // the material database
210 // Simple geometry state data structure
218 OSG::UInt32 material_index
;
222 // transform point from world space to eye space
224 OSG::Pnt3f
transform_to_eye_space(const OSG::Pnt3f
& p
, OSG::SimpleSceneManager
* pSSM
)
226 if (!pSSM
|| !pSSM
->getWindow() || pSSM
->getWindow()->getMFPort()->size() == 0)
229 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
234 OSG::Int16 width
= pPort
->calcPixelWidth();
235 OSG::Int16 height
= pPort
->calcPixelHeight();
237 pPort
->getCamera()->getViewing(view
, width
, height
);
239 view
.multFull( p
, p_es
);
245 // transform vector from world space to eye space
247 OSG::Vec3f
transform_to_eye_space(const OSG::Vec3f
& v
, OSG::SimpleSceneManager
* pSSM
)
249 if (!pSSM
|| !pSSM
->getWindow() || pSSM
->getWindow()->getMFPort()->size() == 0)
252 OSG::Viewport
* pPort
= mgr
->getWindow()->getPort(0);
257 OSG::Int16 width
= pPort
->calcPixelWidth();
258 OSG::Int16 height
= pPort
->calcPixelHeight();
260 pPort
->getCamera()->getViewing(view
, width
, height
);
262 view
.multFull( v
, v_es
);
270 void update_light_state(OSG::UniformBufferObjChunk
* ubo
, const VecLightsT
& vLights
)
273 for (std::size_t i
= 0; i
< vLights
.size(); ++i
) {
274 std::stringstream stream
;
275 stream
<< "Lights.light[" << i
<< "]." << std::flush
;
277 #ifndef USE_TEST_FP_SHADER
278 OSG::Pnt3f position_es
= transform_to_eye_space(vLights
[i
].position
, mgr
);
279 OSG::Vec3f spot_direction_es
= transform_to_eye_space(vLights
[i
].spot_direction
, mgr
);
281 name
= stream
.str() + "position"; ubo
->setVec3 (name
, position_es
);
282 name
= stream
.str() + "spot_direction"; ubo
->setVec3 (name
, spot_direction_es
);
283 name
= stream
.str() + "Ia"; ubo
->setVec3 (name
, vLights
[i
].Ia
);
284 name
= stream
.str() + "Id"; ubo
->setVec3 (name
, vLights
[i
].Id
);
285 name
= stream
.str() + "Is"; ubo
->setVec3 (name
, vLights
[i
].Is
);
286 name
= stream
.str() + "attenuation"; ubo
->setVec3 (name
, vLights
[i
].attenuation
);
287 name
= stream
.str() + "spot_cos_cutoff"; ubo
->setFloat(name
, vLights
[i
].spot_cos_cutoff
);
288 name
= stream
.str() + "spot_exponent"; ubo
->setFloat(name
, vLights
[i
].spot_exponent
);
289 name
= stream
.str() + "type"; ubo
->setInt (name
, vLights
[i
].type
);
291 name
= stream
.str() + "position"; ubo
->setVec3 (name
, OSG::Pnt3f(1.1f
, 2.2f
, 3.3f
));
292 name
= stream
.str() + "spot_direction"; ubo
->setVec3 (name
, OSG::Vec3f(4.4f
, 5.5f
, 6.6f
));
293 name
= stream
.str() + "Ia"; ubo
->setVec3 (name
, OSG::Color3f(0.2f
, 0.2f
, 0.2f
));
294 name
= stream
.str() + "Id"; ubo
->setVec3 (name
, OSG::Color3f(0.4f
, 0.4f
, 0.4f
));
295 name
= stream
.str() + "Is"; ubo
->setVec3 (name
, OSG::Color3f(0.6f
, 0.6f
, 0.6f
));
296 name
= stream
.str() + "attenuation"; ubo
->setVec3 (name
, OSG::Vec3f(0.8f
, 0.8f
, 0.8f
));
297 name
= stream
.str() + "spot_cos_cutoff"; ubo
->setFloat(name
, 0.8f
);
298 name
= stream
.str() + "spot_exponent"; ubo
->setFloat(name
, 12.3f
);
299 name
= stream
.str() + "type"; ubo
->setInt (name
, Light::point_light
);
305 OSG::UniformBufferObjChunkTransitPtr
create_light_state(const VecLightsT
& vLights
)
307 OSG::UniformBufferObjChunkRefPtr ubo
= OSG::UniformBufferObjChunk::create();
309 ubo
->setBlockName("Lights");
310 ubo
->setUsage(GL_STREAM_DRAW
);
312 for (std::size_t i
= 0; i
< vLights
.size(); ++i
) {
313 std::stringstream stream
;
314 stream
<< "Lights.light[" << i
<< "]." << std::flush
;
317 name
= stream
.str() + "position"; ubo
->addVec3 (name
);
318 name
= stream
.str() + "spot_direction"; ubo
->addVec3 (name
);
319 name
= stream
.str() + "Ia"; ubo
->addVec3 (name
);
320 name
= stream
.str() + "Id"; ubo
->addVec3 (name
);
321 name
= stream
.str() + "Is"; ubo
->addVec3 (name
);
322 name
= stream
.str() + "attenuation"; ubo
->addVec3 (name
);
323 name
= stream
.str() + "spot_cos_cutoff"; ubo
->addFloat(name
);
324 name
= stream
.str() + "spot_exponent"; ubo
->addFloat(name
);
325 name
= stream
.str() + "type"; ubo
->addInt (name
);
328 update_light_state(ubo
, vLights
);
330 return OSG::UniformBufferObjChunkTransitPtr(ubo
);
334 // The material state
336 void update_material_database_state(OSG::UniformBufferObjChunk
* ubo
, const VecMaterialsT
& vMaterials
)
339 for (std::size_t i
= 0; i
< vMaterials
.size(); ++i
) {
340 std::stringstream stream
;
341 stream
<< "Materials.material[" << i
<< "]." << std::flush
;
343 #ifndef USE_TEST_FP_SHADER
344 name
= stream
.str() + "ambient"; ubo
->setVec3 (name
, vMaterials
[i
].ambient
);
345 name
= stream
.str() + "diffuse"; ubo
->setVec3 (name
, vMaterials
[i
].diffuse
);
346 name
= stream
.str() + "specular"; ubo
->setVec3 (name
, vMaterials
[i
].specular
);
347 name
= stream
.str() + "emissive"; ubo
->setVec3 (name
, vMaterials
[i
].emissive
);
348 name
= stream
.str() + "opacity"; ubo
->setFloat(name
, vMaterials
[i
].opacity
);
349 name
= stream
.str() + "shininess"; ubo
->setFloat(name
, vMaterials
[i
].shininess
);
351 name
= stream
.str() + "ambient"; ubo
->setVec3 (name
, OSG::Color3f(0.1f
,0.2f
,0.3f
));
352 name
= stream
.str() + "diffuse"; ubo
->setVec3 (name
, OSG::Color3f(0.2f
,0.4f
,0.6f
));
353 name
= stream
.str() + "specular"; ubo
->setVec3 (name
, OSG::Color3f(0.4f
,0.6f
,0.8f
));
354 name
= stream
.str() + "emissive"; ubo
->setVec3 (name
, OSG::Color3f(0.6f
,0.8f
,1.0f
));
355 name
= stream
.str() + "opacity"; ubo
->setFloat(name
, 0.7f
);
356 name
= stream
.str() + "shininess"; ubo
->setFloat(name
, 25.4f
);
362 OSG::UniformBufferObjChunkTransitPtr
create_material_database_state(const VecMaterialsT
& vMaterials
)
364 OSG::UniformBufferObjChunkRefPtr ubo
= OSG::UniformBufferObjChunk::create();
366 ubo
->setBlockName("Materials");
367 ubo
->setUsage(GL_STATIC_DRAW
);
369 for (std::size_t i
= 0; i
< vMaterials
.size(); ++i
) {
370 std::stringstream stream
;
371 stream
<< "Materials.material[" << i
<< "]." << std::flush
;
374 name
= stream
.str() + "ambient"; ubo
->addVec3 (name
);
375 name
= stream
.str() + "diffuse"; ubo
->addVec3 (name
);
376 name
= stream
.str() + "specular"; ubo
->addVec3 (name
);
377 name
= stream
.str() + "emissive"; ubo
->addVec3 (name
);
378 name
= stream
.str() + "opacity"; ubo
->addFloat(name
);
379 name
= stream
.str() + "shininess"; ubo
->addFloat(name
);
382 update_material_database_state(ubo
, vMaterials
);
384 return OSG::UniformBufferObjChunkTransitPtr(ubo
);
388 // The geometry material state
390 void update_geometry_material_state(OSG::UniformBufferObjChunk
* ubo
, const GeomState
& geom_state
)
393 #ifndef USE_TEST_FP_SHADER
394 ubo
->setInt("GeomState.material_index", geom_state
.material_index
);
396 ubo
->setInt("GeomState.material_index", 7);
401 OSG::UniformBufferObjChunkTransitPtr
create_geometry_material_state(const GeomState
& geom_state
)
403 OSG::UniformBufferObjChunkRefPtr ubo
= OSG::UniformBufferObjChunk::create();
405 ubo
->setBlockName("GeomState");
406 ubo
->setUsage(GL_DYNAMIC_DRAW
);
408 ubo
->addInt("GeomState.material_index");
410 update_geometry_material_state(ubo
, geom_state
);
412 return OSG::UniformBufferObjChunkTransitPtr(ubo
);
416 // vertex shader program.
418 std::string
get_vp_program();
421 // fragment shader program for bump mapping in surface local coordinates
423 std::string
get_fp_program();
426 // random number generator
428 boost::random::mt19937 generator
;
429 boost::random::uniform_int_distribution
<> dist(0, num_materials
-1);
432 // a separate transformation for every object
434 OSG::TransformRefPtr cyltrans
, tortrans
;
437 // Uniform buffer objects corresponding to transient shader blocks
439 OSG::UniformBufferObjChunkRefPtr ubo_light_state
= NULL
;
440 OSG::UniformBufferObjChunkRefPtr ubo_geom_state_1
= NULL
;
441 OSG::UniformBufferObjChunkRefPtr ubo_geom_state_2
= NULL
;
444 // forward declaration so we can have the interesting stuff upfront
446 int setupGLUT(int *argc
, char *argv
[]);
453 // light spot direction and light position must be provided in eye space
454 update_light_state(ubo_light_state
, lights
);
458 OSG::Real32 t
= glutGet(GLUT_ELAPSED_TIME
);
460 // set the transforms' matrices
461 m
.setTransform(OSG::Vec3f(0, 0, OSG::osgSin(t
/ 1000.f
) * 1.5),
462 OSG::Quaternion( OSG::Vec3f (1, 0, 0), t
/ 500.f
));
464 cyltrans
->setMatrix(m
);
466 m
.setTransform(OSG::Vec3f(OSG::osgSin(t
/ 1000.f
), 0, 0),
467 OSG::Quaternion( OSG::Vec3f (0, 0, 1), t
/ 1000.f
));
469 tortrans
->setMatrix(m
);
471 OSG::commitChanges();
477 // Initialize GLUT & OpenSG and set up the scene
479 int main(int argc
, char **argv
)
482 OSG::osgInit(argc
,argv
);
485 int winid
= setupGLUT(&argc
, argv
);
487 // open a new scope, because the pointers below should go out of scope
488 // before entering glutMainLoop.
489 // Otherwise OpenSG will complain about objects being alive after shutdown.
491 // the connection between GLUT and OpenSG
492 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
493 gwin
->setGlutId(winid
);
496 // create the SimpleSceneManager helper
497 mgr
= OSG::SimpleSceneManager::create();
498 mgr
->setWindow(gwin
);
500 // create a pretty simple graph: a Group with two Transforms as children,
501 // each of which carries a single Geometry.
505 OSG::NodeRefPtr scene
= OSG::Node::create();
507 // The cylinder and its transformation
508 OSG::NodeRefPtr cyl
= OSG::Node::create();
509 OSG::GeometryRefPtr cylgeo
= OSG::makeCylinderGeo( 1.4f
, .3f
, 24,
512 cyl
->setCore(cylgeo
);
514 cyltrans
= OSG::Transform::create();
516 OSG::NodeRefPtr cyltransnode
= OSG::Node::create();
517 cyltransnode
->setCore (cyltrans
);
518 cyltransnode
->addChild(cyl
);
520 // add it to the scene
521 scene
->addChild(cyltransnode
);
523 // The torus and its transformation
524 OSG::NodeRefPtr torus
= OSG::Node::create();
525 OSG::GeometryRefPtr torusgeo
= OSG::makeTorusGeo( .2f
, 1, 24, 36 );
527 torus
->setCore(torusgeo
);
529 tortrans
= OSG::Transform::create();
531 OSG::NodeRefPtr tortransnode
= OSG::Node::create();
532 tortransnode
->setCore (tortrans
);
533 tortransnode
->addChild(torus
);
535 // add it to the scene
536 scene
->addChild(tortransnode
);
539 // create the shader program
541 OSG::ShaderProgramChunkRefPtr prog_chunk
= OSG::ShaderProgramChunk::create();
542 OSG::ShaderProgramRefPtr vertShader
= OSG::ShaderProgram::createVertexShader();
543 OSG::ShaderProgramRefPtr fragShader
= OSG::ShaderProgram::createFragmentShader();
545 vertShader
->setProgram(get_vp_program());
546 fragShader
->setProgram(get_fp_program());
549 // binding the unifrom block to a buffer binding point can be performed
550 // either by calling the shaders's addUniformBlock method or by
551 // adding a 'uniform block' variable to a ShaderProgramVariableChunk.
552 // In the following we use both variants for illustration.
554 fragShader
->addUniformBlock("Materials", 1); // block binding point
555 fragShader
->addUniformBlock("Lights", 2); // block binding point
558 // The following is replaced by adding ShaderProgramVariableChunk objects
559 // to the chunk material. See below...
561 // fragShader->addUniformBlock("GeomState", 3); // block binding point
563 prog_chunk
->addShader(vertShader
);
564 prog_chunk
->addShader(fragShader
);
567 // create uniform buffer objects and corresponding materials
569 OSG::UniformBufferObjChunkRefPtr ubo_material_database
= create_material_database_state(materials
);
570 ubo_light_state
= create_light_state(lights
);
572 OSG::PolygonChunkRefPtr polygon_chunk
= OSG::PolygonChunk::create();
573 polygon_chunk
->setFrontMode(GL_FILL
);
574 polygon_chunk
->setBackMode(GL_FILL
);
575 polygon_chunk
->setCullFace(GL_NONE
);
577 OSG::DepthChunkRefPtr depth_chunk
= OSG::DepthChunk::create();
578 depth_chunk
->setEnable(true);
580 OSG::ChunkMaterialRefPtr prog_state
= OSG::ChunkMaterial::create();
581 prog_state
->addChunk(ubo_material_database
, 1); // buffer binding point 1
582 prog_state
->addChunk(ubo_light_state
, 2); // buffer binding point 2
583 prog_state
->addChunk(prog_chunk
);
584 prog_state
->addChunk(polygon_chunk
);
585 prog_state
->addChunk(depth_chunk
);
587 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk
= OSG::ShaderProgramVariableChunk::create();
588 shader_var_chunk
->addUniformBlock("GeomState", 3);
590 GeomState geom1
; geom1
.material_index
= dist(generator
);
591 OSG::ChunkMaterialRefPtr geom1_state
= OSG::ChunkMaterial::create();
592 ubo_geom_state_1
= create_geometry_material_state(geom1
);
593 geom1_state
->addChunk(ubo_geom_state_1
, 3); // buffer binding point 3
594 geom1_state
->addChunk(shader_var_chunk
); // block binding point
596 GeomState geom2
; geom2
.material_index
= dist(generator
);
597 OSG::ChunkMaterialRefPtr geom2_state
= OSG::ChunkMaterial::create();
598 ubo_geom_state_2
= create_geometry_material_state(geom2
);
599 geom2_state
->addChunk(ubo_geom_state_2
, 3); // buffer binding point 3
600 geom2_state
->addChunk(shader_var_chunk
); // block binding point
602 cylgeo
->setMaterial(geom1_state
);
603 torusgeo
->setMaterial(geom2_state
);
605 OSG::MaterialChunkOverrideGroupRefPtr mgrp
= OSG::MaterialChunkOverrideGroup::create();
606 mgrp
->setMaterial(prog_state
);
607 scene
->setCore(mgrp
);
609 OSG::commitChanges();
613 // show the whole scene
624 // GLUT callback functions
628 // react to size changes
630 void reshape(int w
, int h
)
637 // react to mouse button presses
639 void mouse(int button
, int state
, int x
, int y
)
642 mgr
->mouseButtonRelease(button
, x
, y
);
644 mgr
->mouseButtonPress(button
, x
, y
);
650 // react to mouse motions with pressed buttons
652 void motion(int x
, int y
)
654 mgr
->mouseMove(x
, y
);
661 void keyboard(unsigned char k
, int x
, int y
)
667 // clean up global variables
672 ubo_light_state
= NULL
;
673 ubo_geom_state_1
= NULL
;
674 ubo_geom_state_2
= NULL
;
683 GeomState geom1
; geom1
.material_index
= dist(generator
);
684 GeomState geom2
; geom2
.material_index
= dist(generator
);
686 update_geometry_material_state(ubo_geom_state_1
, geom1
);
687 update_geometry_material_state(ubo_geom_state_2
, geom2
);
695 mgr
->setStatistics(!mgr
->getStatistics());
702 // setup the GLUT library which handles the windows for us
704 int setupGLUT(int *argc
, char *argv
[])
706 glutInit(argc
, argv
);
707 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
709 int winid
= glutCreateWindow("OpenSG");
711 glutReshapeFunc(reshape
);
712 glutDisplayFunc(display
);
713 glutMouseFunc(mouse
);
714 glutMotionFunc(motion
);
715 glutKeyboardFunc(keyboard
);
717 // call the redraw function whenever there's nothing else to do
718 glutIdleFunc(display
);
724 // vertex shader program.
726 std::string
get_vp_program()
728 std::string vp_program
=
730 "#version 330 compatibility\n"
732 "#extension GL_ARB_separate_shader_objects: enable\n"
733 "#extension GL_ARB_uniform_buffer_object: enable\n"
735 "smooth out vec3 vNormalES; // eye space normal\n"
736 "smooth out vec3 vPositionES; // eye space position\n"
741 " // multiply the object space vertex position with the modelview matrix \n"
742 " // to get the eye space vertex position\n"
744 " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;\n"
747 " // multiply the object space normal with the normal matrix (transpose of the inverse \n"
748 " // model view matrix) to get the eye space normal\n"
750 " vNormalES = gl_NormalMatrix * gl_Normal;\n"
753 " // multiply the combiend modelview projection matrix with the object space vertex\n"
754 " // position to get the clip space position\n"
756 " gl_Position = ftransform();\n"
764 // fragment shader program for bump mapping in surface local coordinates
766 std::string
get_fp_program()
768 #ifndef USE_TEST_FP_SHADER
769 std::string fp_program
=
771 "#version 330 compatibility\n"
773 "#extension GL_ARB_separate_shader_objects: enable\n"
774 "#extension GL_ARB_uniform_buffer_object: enable\n"
776 "smooth in vec3 vNormalES; // eye space normal\n"
777 "smooth in vec3 vPositionES; // eye space position\n"
779 "const int num_lights = 1;\n"
780 "const int num_materials = 100;\n"
782 "const int directional_light = 0;\n"
783 "const int point_light = 1;\n"
784 "const int spot_light = 2;\n"
785 "const int no_light = 3;\n"
789 " vec3 position; // in eye space\n"
790 " vec3 spot_direction; // in eye space\n"
792 " vec3 Ia; // ambient max. Intensity\n"
793 " vec3 Id; // diffuse max. Intensity\n"
794 " vec3 Is; // specular max. Intensity\n"
796 " vec3 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
798 " float spot_cos_cutoff; // cosine cut of angle\n"
800 " float spot_exponent; // [0-128]\n"
801 " int type; // directional_light, point_light, spot_light, no_light\n"
804 "layout (shared) uniform Lights\n"
806 " Light light[num_lights];\n"
817 " float shininess;\n"
820 "layout (shared) uniform Materials\n"
822 " Material material[num_materials];\n"
826 "layout (shared) uniform GeomState\n"
828 " int material_index;\n"
831 "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!\n"
833 "layout(location = 0) out vec4 vFragColor;\n"
836 "// directional light contribution\n"
838 "vec3 directionalLight(\n"
839 " in int i, // light identifier, i.e. current light\n"
840 " in int j, // material identifier\n"
841 " in vec3 n, // vertex normal in eye space\n"
842 " in vec3 v) // view direction in eye space\n"
844 " if (lights.light[i].type != directional_light)\n"
845 " return vec3(0.0, 0.0, 0.0);\n"
848 " // the light direction in eye space\n"
850 " vec3 l = -lights.light[i].spot_direction; // we carry the directional light direction in the spot_direction slot\n"
853 " // the half vector\n"
855 " vec3 h = normalize(l + v);\n"
857 " float n_dot_l = max(0.0, dot(n, l));\n"
858 " float n_dot_h = max(0.0, dot(n, h));\n"
860 " float m = materials.material[j].shininess;\n"
862 " float pf; // power factor\n"
864 " if (n_dot_l == 0.0)\n"
867 " pf = pow(n_dot_h, m);\n"
869 " return materials.material[j].emissive \n"
870 " + lights.light[i].Ia * materials.material[j].ambient \n"
871 " + lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI\n"
872 " + lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
876 "// point light contribution\n"
879 " in int i, // light identifier, i.e. current light\n"
880 " in int j, // material identifier\n"
881 " in vec3 n, // vertex normal in eye space\n"
882 " in vec3 v, // view direction in eye space\n"
883 " in vec3 p) // vertex position in eye space\n"
885 " if (lights.light[i].type != point_light)\n"
886 " return vec3(0.0, 0.0, 0.0);\n"
888 " vec3 l = vec3(lights.light[i].position) - p; // direction from surface to light position\n"
889 " float d = length(l); // distance from surface to light source\n"
890 " l = normalize(l); // normalized direction from surface to light position\n"
893 " // the half vector\n"
895 " vec3 h = normalize(l + v);\n"
897 " float n_dot_l = max(0.0, dot(n, l));\n"
898 " float n_dot_h = max(0.0, dot(n, h));\n"
900 " float m = materials.material[j].shininess;\n"
902 " float pf; // power factor\n"
904 " if (n_dot_l == 0.0)\n"
907 " pf = pow(n_dot_h, m);\n"
910 " // Compute attenuation\n"
912 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
913 " (lights.light[i].attenuation.y * d) + \n"
914 " (lights.light[i].attenuation.z * d * d));\n"
916 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
918 " return materials.material[j].emissive \n"
919 " + attenuation * lights.light[i].Ia * materials.material[j].ambient \n"
920 " + attenuation * lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI\n"
921 " + attenuation * lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
925 "// spot light contribution\n"
928 " in int i, // light identifier, i.e. current light\n"
929 " in int j, // material identifier\n"
930 " in vec3 n, // vertex normal in eye space\n"
931 " in vec3 v, // view direction in eye space\n"
932 " in vec3 p) // vertex position in eye space\n"
934 " if (lights.light[i].type != spot_light)\n"
935 " return vec3(0.0, 0.0, 0.0);\n"
937 " vec3 l = vec3(lights.light[i].position) - p; // direction from surface to light position\n"
938 " float d = length(l); // distance from surface to light source\n"
939 " l = normalize(l); // normalized direction from surface to light position\n"
941 " vec3 s = lights.light[i].spot_direction; // spot direction\n"
944 " // the half vector\n"
946 " vec3 h = normalize(l + v);\n"
948 " float n_dot_l = max(0.0, dot(n, l));\n"
949 " float n_dot_h = max(0.0, dot(n, h));\n"
950 " float l_dot_s = dot(-l, s);\n"
952 " float m = materials.material[j].shininess;\n"
954 " float pf; // power factor\n"
956 " if (n_dot_l == 0.0)\n"
959 " pf = pow(n_dot_h, m);\n"
962 " // Compute attenuation\n"
964 " float attenuation = 1.0 / (lights.light[i].attenuation.x + \n"
965 " (lights.light[i].attenuation.y * d) + \n"
966 " (lights.light[i].attenuation.z * d * d));\n"
968 " attenuation = clamp(attenuation, 0.0, 1.0);\n"
970 " if (l_dot_s < lights.light[i].spot_cos_cutoff) \n"
971 " attenuation = 0.0;\n"
973 " attenuation *= pow(l_dot_s, lights.light[i].spot_exponent);\n"
975 " return materials.material[j].emissive \n"
976 " + attenuation * lights.light[i].Ia * materials.material[j].ambient \n"
977 " + attenuation * lights.light[i].Id * materials.material[j].diffuse * n_dot_l // / PI\n"
978 " + attenuation * lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf; // * (m+8)/(8*PI)\n"
984 " // normalize the eye space normal\n"
986 " vec3 N = normalize(vNormalES);\n"
989 " // get the view vector and normalize it\n"
991 " vec3 V = normalize(cCameraPositionES - vPositionES);\n"
994 " // Integrate over all lights: Any unused light does not contribute and each light\n"
995 " // contribute either from the directional light, the point light or the spot light.\n"
997 " vec3 color = vec3(0.0, 0.0, 0.0);\n"
998 " for (int i = 0; i < num_lights; ++i) {\n"
999 " color += directionalLight(i, geom_state.material_index, N, V) \n"
1000 " + pointLight(i, geom_state.material_index, N, V, vPositionES) \n"
1001 " + spotLight(i, geom_state.material_index, N, V, vPositionES);\n"
1003 " vFragColor = vec4(color, materials.material[geom_state.material_index ].opacity);\n"
1008 std::string fp_program
=
1010 "#version 330 compatibility\n"
1012 "#extension GL_ARB_separate_shader_objects: enable\n"
1013 "#extension GL_ARB_uniform_buffer_object: enable\n"
1015 "smooth in vec3 vNormalES; // eye space normal\n"
1016 "smooth in vec3 vPositionES; // eye space position\n"
1018 "const int num_lights = 1;\n"
1019 "const int num_materials = 100;\n"
1021 "const int directional_light = 0;\n"
1022 "const int point_light = 1;\n"
1023 "const int spot_light = 2;\n"
1024 "const int no_light = 3;\n"
1028 " vec3 position; // in eye space\n"
1029 " vec3 spot_direction; // in eye space\n"
1031 " vec3 Ia; // ambient max. Intensity\n"
1032 " vec3 Id; // diffuse max. Intensity\n"
1033 " vec3 Is; // specular max. Intensity\n"
1035 " vec3 attenuation; // (constant, linear, quadratic) with constant >= 1 and linear,quadratic >= 0\n"
1037 " float spot_cos_cutoff; // cosine cut of angle\n"
1038 " float spot_exponent; // [0-128]\n"
1039 " int type; // directional_light, point_light, spot_light, no_light\n"
1042 "layout (shared) uniform Lights\n"
1044 " Light light[num_lights];\n"
1055 " float shininess;\n"
1058 "layout (shared) uniform Materials\n"
1060 " Material material[num_materials];\n"
1064 "layout (shared) uniform GeomState\n"
1066 " int material_index;\n"
1069 "layout(location = 0) out vec4 vFragColor;\n"
1075 " int type = lights.light[0].type;\n"
1076 " vec3 position = lights.light[0].position;\n"
1077 " vec3 spot_direction = lights.light[0].spot_direction;\n"
1078 " vec3 Ia = lights.light[0].Ia;\n"
1079 " vec3 Id = lights.light[0].Id;\n"
1080 " vec3 Is = lights.light[0].Is;\n"
1081 " vec3 attenuation = lights.light[0].attenuation;\n"
1082 " float spot_cos_cutoff = lights.light[0].spot_cos_cutoff;\n"
1083 " float spot_exponent = lights.light[0].spot_exponent;\n"
1085 " vec3 ambient = materials.material[0].ambient;\n"
1086 " vec3 diffuse = materials.material[0].diffuse;\n"
1087 " vec3 specular = materials.material[0].specular;\n"
1088 " vec3 emissive = materials.material[0].emissive;\n"
1089 " float opacity = materials.material[0].opacity;\n"
1090 " float shininess = materials.material[0].shininess;\n"
1092 " int material_index = geom_state.material_index;\n"
1094 " vec4 error = vec4(1.0, 0.0, 0.0, 1.0);\n"
1095 " vec4 color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1097 " if (type != point_light)\n"
1100 " if (position != vec3(1.1, 2.2, 3.3))\n"
1103 " if (spot_direction != vec3(4.4, 5.5, 6.6))\n"
1106 " if (Ia != vec3(0.2, 0.2, 0.2))\n"
1109 " if (Id != vec3(0.4, 0.4, 0.4))\n"
1112 " if (Is != vec3(0.6, 0.6, 0.6))\n"
1115 " if (attenuation != vec3(0.8, 0.8, 0.8))\n"
1118 " if (spot_cos_cutoff != 0.8)\n"
1121 " if (spot_exponent != 12.3)\n"
1124 " if (ambient != vec3(0.1, 0.2, 0.3))\n"
1127 " if (diffuse != vec3(0.2, 0.4, 0.6))\n"
1130 " if (specular != vec3(0.4, 0.6, 0.8))\n"
1133 " if (emissive != vec3(0.6, 0.8, 1.0))\n"
1136 " if (opacity != 0.7)\n"
1139 " if (shininess != 25.4)\n"
1142 " if (material_index != 7)\n"
1146 " vFragColor = color;\n"