fixed: compile issue
[opensg.git] / Examples / Simple / multistandardlight.cpp
blob50b124056727d2fd70a30d32cb633a6bce7b8a77
1 // OpenSG Tutorial Example: MultiStandardLight
2 //
3 // This example introduces the MultiLightChunk, the MultiPropertySSBOChunk and
4 // the MultiPropertyUBOChunk. The first two chunks are derived from the
5 // ShaderStorageBufferObjStdLayoutChunk and easily permit the preparation
6 // of array buffers in shader code with std430 shader storage buffer block
7 // format. The third chunk is derived from the UniformBufferObjStd140Chunk
8 // and allows easy preparation of a std140 uniform array block.
9 //
10 // The MultiLightChunk models a light data structures for multiple lights.
11 // It supports a number of different light types and also gives the user
12 // freedom in the details of the data structure layout provided in shader code
13 // for these lights. It currently supports data for directional, point, spot
14 // and Ueber (cinema) lights. It is feasible to strip-down the light structure
15 // data layout somewhat if requested. This example actively only uses point and
16 // spot lights and uses the standard OpenGL light abstraction. Of course the
17 // shader code's responsibilty is to make usage of the provided light data
18 // attrubutes, and the writer of the shader can implement whatever light model
19 // he likes on the given light buffer layout.
21 // The MultiPropertyUBOChunk and MultiPropertySSBOChunk do also provides means
22 // to conviently create shader buffer data. They are, however, not as
23 // specialized as the MultiLightChunk.
24 // They have a simple interface for the data layout preparation but allows only
25 // a restricted subset of layout structure that the std140 uniform buffer block
26 // repspectively the std430 shader storage buffer block specifications allows.
28 // In this example a MultiPropertySSBOChunk is used to model a material database
29 // with the simple basic material properties. The material database shader
30 // buffer is shared by all geometry that is rendered by the example.
32 // The MultiPropertyUBOChunk is used to provide geometry state data to the
33 // fragment shader. That is, each geometry gets its own chunk, but for the
34 // purpose of the example only the material index to be used for the particular
35 // geometry is added to chunk.
37 // Additionally, the example runs riot with boost random number generators.
38 // Hopefully, that does not distract the reader.
40 // Different aspects of the example can be manipulated at runtime like the
41 // number of lights and their range and intensity parameters as well as the
42 // number of geometries simulated and their material among many others.
44 // The examples uses a HDR2Stage core for managing the mapping of the
45 // accumulated intensities into the feasible region of the final screen
46 // render target. It does use mostly default settings for this stage.
48 // At last the example provides a bezier curve abstraction for generating
49 // the light and object pathes.
51 // See also:
52 // multistandardlight.cpp
53 // multicinemalight.cpp
54 // uniformbufferobject_std140.cpp
55 // shaderstoragebufferobject_std430.cpp
56 // multipropertyubochunk_test.cpp
57 // multipropertyssbochunk_test.cpp
58 // tonemapping.cpp
61 #include <boost/functional/hash.hpp>
62 #include <boost/unordered_set.hpp>
63 #include <boost/foreach.hpp>
64 #include <boost/random.hpp>
65 #include <boost/tuple/tuple.hpp>
66 #include "boost/tuple/tuple_comparison.hpp"
68 #ifdef OSG_BUILD_ACTIVE
69 // Headers
70 #include <OSGGLUT.h>
71 #include <OSGConfig.h>
72 #include <OSGSimpleGeometry.h>
73 #include <OSGGLUTWindow.h>
74 #include <OSGSimpleSceneManager.h>
75 #include <OSGBaseFunctions.h>
76 #include <OSGTransform.h>
77 #include <OSGGroup.h>
79 // new headers:
80 #include <OSGGLEXT.h>
81 #include <OSGTime.h>
82 #include <OSGHDR2Stage.h>
83 #include <OSGInverseTransform.h>
84 #include <OSGShaderProgramChunk.h>
85 #include <OSGShaderProgram.h>
86 #include <OSGShaderVariableOSG.h>
87 #include <OSGChunkMaterial.h>
88 #include <OSGMaterialGroup.h>
89 #include <OSGMaterialChunkOverrideGroup.h>
90 #include <OSGMatrixUtility.h>
91 #include <OSGMultiLightChunk.h>
92 #include <OSGMultiPropertyUBOChunk.h>
93 #include <OSGMultiPropertySSBOChunk.h>
94 #include <OSGPolygonChunk.h>
95 #include <OSGDepthChunk.h>
96 #include <OSGShaderProgramVariableChunk.h>
97 #include <OSGBlendChunk.h>
98 #include <OSGPolygonChunk.h>
99 #include <OSGTwoSidedLightingChunk.h>
101 #else
102 // Headers
103 #include <OpenSG/OSGGLUT.h>
104 #include <OpenSG/OSGConfig.h>
105 #include <OpenSG/OSGSimpleGeometry.h>
106 #include <OpenSG/OSGGLUTWindow.h>
107 #include <OpenSG/OSGSimpleSceneManager.h>
108 #include <OpenSG/OSGBaseFunctions.h>
109 #include <OpenSG/OSGTransform.h>
110 #include <OpenSG/OSGGroup.h>
112 // new headers:
113 #include <OpenSG/OSGGLEXT.h>
114 #include <OpenSG/OSGTime.h>
115 #include <OpenSG/OSGHDR2Stage.h>
116 #include <OpenSG/OSGInverseTransform.h>
117 #include <OpenSG/OSGShaderProgramChunk.h>
118 #include <OpenSG/OSGShaderProgram.h>
119 #include <OpenSG/OSGShaderVariableOSG.h>
120 #include <OpenSG/OSGChunkMaterial.h>
121 #include <OpenSG/OSGMaterialGroup.h>
122 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
123 #include <OpenSG/OSGMatrixUtility.h>
124 #include <OpenSG/OSGMultiLightChunk.h>
125 #include <OpenSG/OSGMultiPropertyUBOChunk.h>
126 #include <OpenSG/OSGMultiPropertySSBOChunk.h>
127 #include <OpenSG/OSGPolygonChunk.h>
128 #include <OpenSG/OSGDepthChunk.h>
129 #include <OpenSG/OSGShaderProgramVariableChunk.h>
130 #include <OpenSG/OSGBlendChunk.h>
131 #include <OpenSG/OSGPolygonChunk.h>
132 #include <OpenSG/OSGTwoSidedLightingChunk.h>
133 #endif
135 // ============================================================================
137 // Part I: Declaration of the example scene and some helpers:
138 // - constants that governs the example
139 // - random number generators
140 // - smooth cubic Bezier spline curve
142 // ============================================================================
144 OSG::SimpleSceneManagerRefPtr mgr;
146 const OSG::Int32 num_geometries = 16;
147 const OSG::Int32 num_grid_boxes = 100;
148 const OSG::Int32 num_curve_knots = 40;
149 const OSG::Int32 num_passes = 4;
150 const std::size_t num_materials = 5000;
151 const OSG::Int32 max_num_lights = 1024;
152 const OSG::Real32 world_size = 10.f;
153 const OSG::Real32 box_factor = 1.5f;
155 OSG::Real32 simulation_delta = 0.0001f;
156 OSG::Real32 elapse_time_limit = 10.f;
158 const OSG::Real32 max_light_power = 10.f;
160 const OSG::Real32 quadraticAttFactor = 1.2f;
161 const OSG::Real32 linearAttFactor = 1.2f;
162 const OSG::Real32 spotExponentFactor = 1.2f;
164 typedef boost::mt19937 RNGType;
165 RNGType rng(time(0));
167 boost::uniform_int<> box_dist(0, num_grid_boxes-1);
168 boost::variate_generator<RNGType, boost::uniform_int<> > box_idx_die(rng, box_dist);
170 boost::uniform_int<> die_dist(1, 6);
171 boost::variate_generator<RNGType, boost::uniform_int<> > classic_die(rng, die_dist);
173 boost::uniform_int<> geom_dist(0, 7);
174 boost::variate_generator<RNGType, boost::uniform_int<> > geom_idx_die(rng, geom_dist);
176 boost::uniform_01<float> unit_distribution;
177 boost::variate_generator< RNGType, boost::uniform_01<float> > unit_die(rng, unit_distribution);
179 boost::uniform_real<float> small_distribution(0.1f, 1.f);
180 boost::variate_generator< RNGType, boost::uniform_real<float> > small_die(rng, small_distribution);
182 boost::uniform_real<float> light_range_distribution(0.2f, 0.7f);
183 boost::variate_generator< RNGType, boost::uniform_real<float> > light_range_die(rng, light_range_distribution);
185 std::vector<OSG::Pnt3f> dice_knots(bool close_curve);
187 OSG::Vec3f dice_unit_vector()
189 OSG::Vec3f v;
191 while (v.length() < OSG::Eps)
192 v.setValues(
193 -1.f + 2.f * unit_die(),
194 -1.f + 2.f * unit_die(),
195 -1.f + 2.f * unit_die());
197 v.normalize();
199 return v;
202 class CubicBezierCurve
204 public:
205 CubicBezierCurve(const OSG::Pnt3f& p0, const OSG::Pnt3f& p1, const OSG::Pnt3f& p2, const OSG::Pnt3f& p3);
206 CubicBezierCurve(const CubicBezierCurve& rhs);
208 CubicBezierCurve& operator=(const CubicBezierCurve& rhs);
210 OSG::Pnt3f operator() (OSG::Real32 t) const;
211 OSG::Vec3f tangent (OSG::Real32 t) const;
212 OSG::Vec3f normal (OSG::Real32 t) const;
213 OSG::Vec3f binormal (OSG::Real32 t) const;
214 OSG::Matrix frame (OSG::Real32 t, bool position_only) const;
215 OSG::Real32 length (OSG::UInt32 numSeg = 10) const;
217 private:
218 OSG::Vec3f fst_derivative (OSG::Real32 t) const;
219 OSG::Vec3f sec_derivative (OSG::Real32 t) const;
220 OSG::Vec3f thr_devivative (OSG::Real32 t) const;
222 private:
223 OSG::Pnt3f p[4];
226 class SmoothCubicBezierSpline
228 public:
229 typedef std::vector<OSG::Pnt3f> points_t;
231 SmoothCubicBezierSpline(const points_t& knots);
232 SmoothCubicBezierSpline(const SmoothCubicBezierSpline& rhs);
234 SmoothCubicBezierSpline& operator=(const SmoothCubicBezierSpline& rhs);
236 OSG::Pnt3f operator() (OSG::Real32 t) const;
237 OSG::Vec3f tangent (OSG::Real32 t) const;
238 OSG::Vec3f normal (OSG::Real32 t) const;
239 OSG::Vec3f binormal (OSG::Real32 t) const;
240 OSG::Matrix frame (OSG::Real32 t, bool position_only = false) const;
241 OSG::Real32 length (OSG::UInt32 numSeg = 10) const;
243 private:
244 void calc_ctrl_pnts (points_t& p1, points_t& p2) const;
245 std::size_t index (OSG::Real32 t) const;
246 OSG::Real32 t_ (OSG::Real32 t, std::size_t idx) const;
248 private:
249 std::vector<OSG::Pnt3f> knots;
250 std::vector<OSG::Real32> intervals;
251 std::vector<CubicBezierCurve> curves;
254 // ============================================================================
256 // Part II: Declaration of
257 // - struct Light and type VecLightsT,
258 // - struct Material and type VecMaterialsT,
259 // - struct GeomState
260 // and corresponding initialization routines.
262 // ============================================================================
265 // simple light data structure
267 struct Light
269 enum Type
271 directional_light = OSG::MultiLight::DIRECTIONAL_LIGHT,
272 point_light = OSG::MultiLight::POINT_LIGHT,
273 spot_light = OSG::MultiLight::SPOT_LIGHT,
274 cinema_light = OSG::MultiLight::CINEMA_LIGHT
277 OSG::MultiLight::Type getType() const { return static_cast<OSG::MultiLight::Type>(type); }
279 explicit Light(Type e);
280 ~Light();
282 static Light create_light(Type e, OSG::UInt32 material_idx);
284 OSG::Pnt3f position; // light position in object space for point and spot lights
285 OSG::Vec3f direction; // direction of directional light or spot light in object space
286 OSG::Vec3f ambientIntensity; // the ambient light intensity
287 OSG::Vec3f diffuseIntensity; // the diffuse light intensity
288 OSG::Vec3f specularIntensity; // the specular light intensity
289 OSG::Real32 constantAttenuation; // the intensity of the light
290 OSG::Real32 linearAttenuation; // the intensity of the light
291 OSG::Real32 quadraticAttenuation; // the intensity of the light
292 OSG::Real32 spotlightAngle; // the cone angle in case of a spot light
293 OSG::Real32 spotExponent; // the spot exponent governs the attenuation of the light
294 OSG::Int32 type; // the type of light: see OSG::MultiLight::LightType
295 bool enabled; // on/off state of the light
297 OSG::NodeRefPtr beacon; // the light beacon that if defined evaluates the position parameter
298 OSG::TransformRefPtr transform; // the beacons transform core
299 SmoothCubicBezierSpline curve; // the path that the light will follow
302 typedef std::vector<Light> VecLightsT; // multiple lights
303 VecLightsT lights; // the lights of the scene
305 Light::Light(Type e)
306 : position(0.f, 0.f, 0.f)
307 , direction(0.f, 0.f, 1.f)
308 , ambientIntensity(1.f,1.f,1.f)
309 , diffuseIntensity(1.f,1.f,1.f)
310 , specularIntensity(1.f,1.f,1.f)
311 , constantAttenuation(1.f)
312 , linearAttenuation(0.0001f)
313 , quadraticAttenuation(0.000001f)
314 , spotlightAngle(20.f)
315 , spotExponent(1.f)
316 , type(e)
317 , enabled(true)
318 , beacon(NULL)
319 , transform(NULL)
320 , curve(dice_knots(true))
323 Light::~Light()
325 beacon = NULL;
326 transform = NULL;
330 // Simple material data structure
332 struct Material
334 Material()
335 : ambient (0.f, 0.f, 0.f)
336 , diffuse (0.f, 0.f, 0.f)
337 , specular(0.f, 0.f, 0.f)
338 , emissive(0.f, 0.f, 0.f)
339 , opacity(1.f)
340 , shininess(100.f)
343 OSG::Color3f ambient;
344 OSG::Color3f diffuse;
345 OSG::Color3f specular;
346 OSG::Color3f emissive;
348 OSG::Real32 opacity;
349 OSG::Real32 shininess;
351 static OSG::UInt32 ambient_id;
352 static OSG::UInt32 diffuse_id;
353 static OSG::UInt32 specular_id;
354 static OSG::UInt32 emissive_id;
355 static OSG::UInt32 opacity_id;
356 static OSG::UInt32 shininess_id;
359 OSG::UInt32 Material:: ambient_id = 0;
360 OSG::UInt32 Material:: diffuse_id = 0;
361 OSG::UInt32 Material:: specular_id = 0;
362 OSG::UInt32 Material:: emissive_id = 0;
363 OSG::UInt32 Material:: opacity_id = 0;
364 OSG::UInt32 Material::shininess_id = 0;
366 typedef std::vector<Material> VecMaterialsT; // multiple materials
368 VecMaterialsT initialize_materials(std::size_t num) // helper to create materials
370 OSG_ASSERT(num > max_num_lights + 1);
372 VecMaterialsT mat(num);
374 for (std::size_t i = max_num_lights+1; i < num; ++i)
376 mat[i].ambient = OSG::Color3f(0.001f, 0.001f, 0.001f);
377 mat[i].diffuse.setRandom();
378 mat[i].specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
379 mat[i].emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
380 mat[i].opacity = 1.f;
381 mat[i].shininess = 320.f * small_die();
383 //int r = classic_die();
384 //if (r <= 3)
385 // mat[i].opacity = small_die();
389 // special grey material for box
391 mat[0].ambient = OSG::Color3f(0.001f, 0.001f, 0.001f);
392 mat[0].diffuse = OSG::Color3f(0.7f, 0.7f, 0.7f);
393 mat[0].specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
394 mat[0].emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
395 mat[0].opacity = 1.f;
396 mat[0].shininess = 100.f;
398 return mat;
401 VecMaterialsT materials = initialize_materials(num_materials); // the material database
404 // we reserve the first max_num_lights + 1 materials for the light simulation and
405 // the grey box.
407 boost::uniform_int<OSG::UInt32> material_dist(max_num_lights+1, num_materials-1);
408 boost::variate_generator<RNGType, boost::uniform_int<OSG::UInt32> > material_idx_die(rng, material_dist);
411 // Simple geometry state data structure
413 struct GeomState
415 GeomState()
416 : material_index(0)
419 OSG::UInt32 material_index;
421 static OSG::UInt32 material_index_id;
424 OSG::UInt32 GeomState::material_index_id = 0;
426 // ============================================================================
428 // Part III: Creation and update of the light state
430 // ============================================================================
432 OSG::MultiLightChunkTransitPtr create_light_state(const VecLightsT& vLights)
434 OSG::MultiLightChunkRefPtr lightChunk = OSG::MultiLightChunk::create();
436 lightChunk->setUsage(GL_DYNAMIC_DRAW);
437 lightChunk->setLayoutType(
438 OSG::MultiLight::OPENGL_LAYOUT |
439 OSG::MultiLight::RANGE_LAYOUT);
440 lightChunk->setAutoCalcRanges(true);
442 BOOST_FOREACH(const Light& light, vLights)
444 OSG::UInt32 idx = lightChunk->addLight(light.getType());
446 lightChunk->setPosition (idx, light.position);
447 lightChunk->setDirection (idx, light.direction);
448 lightChunk->setAmbientIntensity (idx, light.ambientIntensity);
449 lightChunk->setDiffuseIntensity (idx, light.diffuseIntensity);
450 lightChunk->setSpecularIntensity (idx, light.specularIntensity);
451 lightChunk->setAttenuation (idx, OSG::Vec3f(light.constantAttenuation,
452 light.linearAttenuation,
453 light.quadraticAttenuation));
454 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
455 lightChunk->setSpotExponent (idx, light.spotExponent);
456 lightChunk->setEnabled (idx, light.enabled);
457 lightChunk->setType (idx, light.getType());
458 lightChunk->setBeacon (idx, light.beacon);
461 return OSG::MultiLightChunkTransitPtr(lightChunk);
464 void update_light_state(OSG::MultiLightChunk* lightChunk, const VecLightsT& vLights)
466 if (lightChunk)
468 if (lightChunk->numLights() != vLights.size())
470 lightChunk->clearLights();
472 BOOST_FOREACH(const Light& light, vLights)
474 OSG::UInt32 idx = lightChunk->addLight(light.getType());
476 lightChunk->setPosition (idx, light.position);
477 lightChunk->setDirection (idx, light.direction);
478 lightChunk->setAmbientIntensity (idx, light.ambientIntensity);
479 lightChunk->setDiffuseIntensity (idx, light.diffuseIntensity);
480 lightChunk->setSpecularIntensity (idx, light.specularIntensity);
481 lightChunk->setAttenuation (idx, OSG::Vec3f(light.constantAttenuation,
482 light.linearAttenuation,
483 light.quadraticAttenuation));
484 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
485 lightChunk->setSpotExponent (idx, light.spotExponent);
486 lightChunk->setEnabled (idx, light.enabled);
487 lightChunk->setType (idx, light.getType());
488 lightChunk->setBeacon (idx, light.beacon);
491 else
493 for (OSG::UInt32 idx = 0; idx < vLights.size(); ++idx)
495 const Light& light = vLights[idx];
497 lightChunk->setPosition (idx, light.position);
498 lightChunk->setDirection (idx, light.direction);
499 lightChunk->setAmbientIntensity (idx, light.ambientIntensity);
500 lightChunk->setDiffuseIntensity (idx, light.diffuseIntensity);
501 lightChunk->setSpecularIntensity (idx, light.specularIntensity);
502 lightChunk->setAttenuation (idx, OSG::Vec3f(light.constantAttenuation,
503 light.linearAttenuation,
504 light.quadraticAttenuation));
505 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
506 lightChunk->setSpotExponent (idx, light.spotExponent);
507 lightChunk->setEnabled (idx, light.enabled);
508 lightChunk->setType (idx, light.getType());
509 lightChunk->setBeacon (idx, light.beacon);
515 // ============================================================================
517 // Part IV: Some routines for handling of the memory buffer and the the
518 // creation on the MultiPropertySSBOChunk objects:
520 // i) create_material_database_state,
521 // update_material_database_state
523 // ii) create_geometry_material_state,
524 // update_geometry_material_state
526 // ============================================================================
529 // i) the material shader storage buffer object
531 OSG::MultiPropertySSBOChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
533 OSG::MultiPropertySSBOChunkRefPtr materialChunk = OSG::MultiPropertySSBOChunk::create();
535 OSG::UInt32 vec3_id, float_id;
537 vec3_id = materialChunk->addMember(OSG::MultiPropertySSBOChunk:: VEC3_T, 4);
538 float_id = materialChunk->addMember(OSG::MultiPropertySSBOChunk::FLOAT_T, 2);
540 materialChunk->setUsage(GL_STATIC_DRAW);
542 Material:: ambient_id = vec3_id++;
543 Material:: diffuse_id = vec3_id++;
544 Material:: specular_id = vec3_id++;
545 Material:: emissive_id = vec3_id;
547 Material:: opacity_id = float_id++;
548 Material::shininess_id = float_id;
550 BOOST_FOREACH(const Material& mat, vMaterials)
552 OSG::UInt32 idx = materialChunk->addProperty();
554 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
555 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
556 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
557 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
559 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
560 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
563 return OSG::MultiPropertySSBOChunkTransitPtr(materialChunk);
566 void update_material_database_state(OSG::MultiPropertySSBOChunk* materialChunk, const VecMaterialsT& vMaterials)
568 if (materialChunk)
570 if (materialChunk->getNumProperties() != vMaterials.size())
572 materialChunk->clearProperties();
574 BOOST_FOREACH(const Material& mat, vMaterials)
576 OSG::UInt32 idx = materialChunk->addProperty();
578 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
579 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
580 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
581 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
583 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
584 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
587 else
589 for (OSG::UInt32 idx = 0; idx < vMaterials.size(); ++idx)
591 const Material& mat = vMaterials[idx];
593 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
594 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
595 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
596 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
598 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
599 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
606 // ii) the geomertry shader storage buffer object
608 OSG::MultiPropertyUBOChunkTransitPtr create_geometry_material_state(const GeomState& geom_state)
610 OSG::MultiPropertyUBOChunkRefPtr geomStateChunk = OSG::MultiPropertyUBOChunk::create();
612 GeomState::material_index_id = geomStateChunk->addMember(OSG::MultiPropertyUBOChunk::UINT_T, 1);
613 geomStateChunk->setUsage(GL_DYNAMIC_DRAW);
615 OSG::UInt32 idx = geomStateChunk->addProperty();
616 geomStateChunk->setUIntProperty(idx, GeomState::material_index_id, geom_state.material_index);
618 return OSG::MultiPropertyUBOChunkTransitPtr(geomStateChunk);
621 void update_geometry_material_state(OSG::MultiPropertyUBOChunk* geomStateChunk, const GeomState& geom_state)
623 if (geomStateChunk)
625 if (geomStateChunk->getNumProperties() != 1)
627 geomStateChunk->clearProperties();
629 OSG::UInt32 idx = geomStateChunk->addProperty();
630 geomStateChunk->setUIntProperty(idx, GeomState::material_index_id, geom_state.material_index);
632 else
634 geomStateChunk->setUIntProperty( 0, GeomState::material_index_id, geom_state.material_index);
639 // ============================================================================
641 // Part V: The application finally starts here
643 // ============================================================================
646 // vertex shader program.
648 std::string get_vp_program();
651 // fragment shader program for bump mapping in surface local coordinates
653 std::string get_fp_program();
656 // The scene
658 OSG::NodeRefPtr scene_node = NULL;
661 // A HDR stage core
663 OSG::HDR2StageRefPtr hdr_stage = NULL;
664 OSG::NodeRefPtr hdr_node = NULL;
667 // The material database for all visible geometry: objects, lights, stage box
669 OSG::MultiPropertySSBOChunkRefPtr ssbo_material_database = NULL;
672 // The mulit light chunk
674 OSG::MultiLightChunkRefPtr multi_light_chunk = NULL;
677 // The block binding point for the geom state
679 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = NULL;
682 // Shader Storage buffer objects corresponding to transient shader blocks
684 std::vector<OSG::MultiPropertyUBOChunkRefPtr> ubo_geom_states;
687 // A separate transformation for each object and a spline for the trajectory
689 std::vector<OSG::NodeRefPtr> geom_nodes;
690 std::vector<OSG::TransformRefPtr> geom_trafos;
691 std::vector<SmoothCubicBezierSpline> geom_curves;
694 // HDR stage ...
696 void setup_hdr_stage()
698 if (hdr_stage)
700 hdr_stage->setApplyGamma (true);
701 hdr_stage->setAccurateGamma (true);
703 hdr_stage->setAdjustLuminance (false);
705 hdr_stage->setPerformBloom (false);
706 hdr_stage->setBloomBackground (false);
708 hdr_stage->setForceBackground (true);
709 hdr_stage->setUse_ITU_R_BT_709 (true);
710 hdr_stage->setMipmapLevel (-1);
712 hdr_stage->setTarget (OSG::HDR2Stage::COMPOSITE_TEXTURE);
713 hdr_stage->setCarryDepth (true);
715 hdr_stage->setColorBufferInternalFormat (GL_RGBA16F);
716 hdr_stage->setColorBufferPixelFormat (GL_RGBA);
717 hdr_stage->setColorBufferType (GL_FLOAT);
719 hdr_stage->setDepthBufferInternalFormat (GL_DEPTH24_STENCIL8);
720 hdr_stage->setDepthBufferPixelFormat (GL_DEPTH_STENCIL);
721 hdr_stage->setDepthBufferType (GL_UNSIGNED_INT_24_8);
723 hdr_stage->setLumBufferInternalFormat (GL_R32F);
724 hdr_stage->setLumBufferPixelFormat (GL_RED);
725 hdr_stage->setLumBufferType (GL_FLOAT);
727 hdr_stage->setImageBufferInternalFormat (GL_RGB16F);
728 hdr_stage->setImageBufferPixelFormat (GL_RGB);
729 hdr_stage->setImageBufferType (GL_FLOAT);
731 hdr_stage->setNumSamples (0);
733 hdr_stage->setBloomThreshold (2.0f);
734 hdr_stage->setBloomMagnitude (0.0f);
735 hdr_stage->setToneMappingMode (OSG::HDR2Stage::REINHARD_TONE_MAPPING);
736 hdr_stage->setExposure (0.0f);
737 hdr_stage->setKeyValue (0.18f);
738 hdr_stage->setAutoExposureMode (OSG::HDR2Stage::MANUAL);
739 hdr_stage->setWhiteLevel (5.0f);
740 hdr_stage->setFilmicShoulderStrenght (0.15f);
741 hdr_stage->setFilmicLinearStrength (0.5f);
742 hdr_stage->setFilmicLinearAngle (0.1f);
743 hdr_stage->setFilmicToeStrength (0.2f);
744 hdr_stage->setFilmicToeNumerator (0.02f);
745 hdr_stage->setFilmicToeDenominator (0.3f);
746 hdr_stage->setFilmicLinearWhite (11.2f);
747 hdr_stage->setSaturation (1.0f);
748 hdr_stage->setDragoBias (0.85f);
749 hdr_stage->setTau (1.25f);
750 hdr_stage->setNumTaps (4);
751 hdr_stage->setBlurGaussSigma (0.8f);
752 hdr_stage->setUseLinChromCorrection (true);
756 void removeHDRStage()
758 OSG::GroupRefPtr group = OSG::Group::create();
759 hdr_node->setCore(group);
761 hdr_stage = NULL;
764 void createHDRStage()
766 if (!hdr_stage)
768 hdr_stage = OSG::HDR2Stage::create();
769 setup_hdr_stage();
772 if (hdr_node)
773 hdr_node->setCore(hdr_stage);
777 // Lights...
779 void deinitialize_lights()
781 BOOST_FOREACH(const Light& light, lights)
783 scene_node->subChild(light.beacon);
786 lights.clear();
789 void initialize_lights(OSG::UInt32 num) // helper to create lights
791 deinitialize_lights();
793 for (OSG::UInt32 i = 0; i < num; ++i)
796 int n = classic_die();
797 Light::Type type;
798 if (n <= 3)
799 type = Light::point_light;
800 else
801 type = Light::spot_light;
803 lights.push_back(Light::create_light(type, i+1));
804 scene_node->addChild(lights[i].beacon);
808 Light Light::create_light(
809 Type e, // type of the light
810 OSG::UInt32 material_idx) // index in to the material storage for light animation
812 Light l(e);
814 l.beacon = OSG::makeCoredNode<OSG::Transform>(&l.transform);
815 OSG::Matrix m;
817 OSG::Real32 L = box_factor * world_size;
819 l.direction = dice_unit_vector();
821 OSG::Color3f c; c.setRandom();
822 l.ambientIntensity = c;
823 l.diffuseIntensity = c;
824 l.specularIntensity = c;
827 // If we fix the constant factor to 1 we alway get attenuation <= 1
828 // for l,q >= 0.
830 // a = 1/(c + l*d + q*d^2)
833 l.constantAttenuation = 1.f;
834 l.linearAttenuation = OSG::Eps;
835 l.quadraticAttenuation = OSG::Eps;
837 Material mat;
838 mat.emissive = c;
839 materials[material_idx] = mat;
841 switch (e)
843 case point_light:
845 OSG::GeometryRefPtr geometry = OSG::makeSphereGeo(3, 0.1f);
846 OSG::NodeRefPtr node = OSG::makeNodeFor(geometry);
848 GeomState geom; geom.material_index = material_idx; // material index used for light animiation
849 OSG::ChunkMaterialRefPtr geom_state = OSG::ChunkMaterial::create();
850 OSG::MultiPropertyUBOChunkRefPtr ubo_geom_state = create_geometry_material_state(geom);
851 geom_state->addChunk(ubo_geom_state, 3); // buffer binding point 3
852 geom_state->addChunk(shader_var_chunk); // block binding point
854 geometry->setMaterial(geom_state);
856 l.beacon->addChild(node);
858 break;
860 case directional_light:
863 break;
865 case spot_light:
867 l.spotlightAngle = 90.f * small_die();
868 l.spotExponent = 1.f;
870 GeomState geom; geom.material_index = material_idx; // material index used for light animiation
871 OSG::ChunkMaterialRefPtr geom_state = OSG::ChunkMaterial::create();
872 OSG::MultiPropertyUBOChunkRefPtr ubo_geom_state = create_geometry_material_state(geom);
873 geom_state->addChunk(ubo_geom_state, 3); // buffer binding point 3
874 geom_state->addChunk(shader_var_chunk); // block binding point
876 OSG::Real32 r = 0.1f;
877 OSG::Real32 h = r / OSG::osgTan(OSG::osgDegree2Rad(l.spotlightAngle));
878 OSG::GeometryRefPtr geometry = OSG::makeConeGeo(h, r, 24, true, true);
879 geometry->setMaterial(geom_state);
881 OSG::TransformRefPtr cone_trans = OSG::Transform::create();
882 OSG::Matrix spot_mat;
883 bool result = OSG::MatrixLookAt(spot_mat, l.direction, OSG::Pnt3f(0,0,0), OSG::Vec3f(0,1,0));
884 if (result)
885 OSG::MatrixLookAt(spot_mat, l.direction, OSG::Pnt3f(0,0,0), OSG::Vec3f(1,0,0));
886 cone_trans->setMatrix(spot_mat);
888 OSG::Real32 ang = -90.f;
889 OSG::Vec3f rotVec(1,0,0);
891 OSG::TransformRefPtr rot_trans = OSG::Transform::create();
892 OSG::Matrix rot_mat;
893 rot_mat.setRotate(OSG::Quaternion(rotVec, OSG::osgDegree2Rad(ang)));
894 rot_trans->setMatrix(rot_mat);
896 OSG::NodeRefPtr cone_trans_node = OSG::makeNodeFor(cone_trans);
897 OSG::NodeRefPtr rot_trans_node = OSG::makeNodeFor(rot_trans);
898 OSG::NodeRefPtr cone_node = OSG::makeNodeFor(geometry);
900 l.beacon->addChild(cone_trans_node);
902 cone_trans_node->addChild(rot_trans_node);
903 rot_trans_node->addChild(cone_node);
905 //OSG::GeometryRefPtr geometry_test = OSG::makeCylinderGeo(30, .01f, 24, true, true, true );
906 //geometry_test->setMaterial(geom_state);
908 //OSG::TransformRefPtr test_trans = OSG::Transform::create();
909 //OSG::Matrix test_mat;
910 //test_mat.setTranslate(OSG::Vec3f(0,-15,0));
911 //test_trans->setMatrix(test_mat);
913 //OSG::NodeRefPtr test_rot_trans_node = OSG::makeNodeFor(rot_trans);
914 //OSG::NodeRefPtr test_trans_node = OSG::makeNodeFor(test_trans);
915 //OSG::NodeRefPtr test_node = OSG::makeNodeFor(geometry_test);
916 //cone_trans_node->addChild(test_rot_trans_node);
917 //test_rot_trans_node->addChild(test_trans_node);
918 //test_trans_node->addChild(test_node);
920 break;
922 default:
923 break;
926 return l;
929 OSG::NodeTransitPtr createBox()
931 OSG::NodeRefPtr box_root = OSG::makeCoredNode<OSG::Group>();
933 OSG::Real32 L = box_factor * world_size;
934 OSG::GeometryRefPtr box_plane = OSG::makePlaneGeo(2.f*L, 2.f*L, 128, 128);
936 OSG::NodeRefPtr box_bottom = OSG::makeNodeFor(box_plane);
937 OSG::NodeRefPtr box_left = OSG::makeNodeFor(box_plane);
938 OSG::NodeRefPtr box_right = OSG::makeNodeFor(box_plane);
939 OSG::NodeRefPtr box_far = OSG::makeNodeFor(box_plane);
941 OSG::TransformRefPtr box_bottom_trans = OSG::Transform::create();
942 OSG::TransformRefPtr box_left_trans = OSG::Transform::create();
943 OSG::TransformRefPtr box_right_trans = OSG::Transform::create();
944 OSG::TransformRefPtr box_far_trans = OSG::Transform::create();
946 OSG::Matrix mat_bottom, mat_left, mat_right, mat_far;
948 mat_bottom.setTransform(OSG::Vec3f(0.f, -L, 0.f), OSG::Quaternion( OSG::Vec3f(1, 0, 0), OSG::osgDegree2Rad(270.f)));
949 mat_left .setTransform(OSG::Vec3f( -L, 0.f, 0.f), OSG::Quaternion( OSG::Vec3f(0, 1, 0), OSG::osgDegree2Rad(90.f)));
950 mat_right .setTransform(OSG::Vec3f( L, 0.f, 0.f), OSG::Quaternion( OSG::Vec3f(0, 1, 0), OSG::osgDegree2Rad(270.f)));
951 mat_far .setTransform(OSG::Vec3f(0.f, 0.f, -L), OSG::Quaternion( OSG::Vec3f(0, 0, 1), OSG::osgDegree2Rad( 0.f)));
953 box_bottom_trans ->setMatrix(mat_bottom);
954 box_left_trans ->setMatrix(mat_left);
955 box_right_trans ->setMatrix(mat_right);
956 box_far_trans ->setMatrix(mat_far);
958 OSG::NodeRefPtr box_bottom_trans_node = OSG::makeNodeFor(box_bottom_trans);
959 OSG::NodeRefPtr box_left_trans_node = OSG::makeNodeFor(box_left_trans);
960 OSG::NodeRefPtr box_right_trans_node = OSG::makeNodeFor(box_right_trans);
961 OSG::NodeRefPtr box_far_trans_node = OSG::makeNodeFor(box_far_trans);
963 box_bottom_trans_node ->addChild(box_bottom);
964 box_left_trans_node ->addChild(box_left);
965 box_right_trans_node ->addChild(box_right);
966 box_far_trans_node ->addChild(box_far);
968 box_root->addChild(box_bottom_trans_node);
969 box_root->addChild(box_left_trans_node);
970 box_root->addChild(box_right_trans_node);
971 box_root->addChild(box_far_trans_node);
973 GeomState geom; geom.material_index = 0; // grey box material index
974 OSG::ChunkMaterialRefPtr geom_state = OSG::ChunkMaterial::create();
975 OSG::MultiPropertyUBOChunkRefPtr ubo_geom_state = create_geometry_material_state(geom);
976 geom_state->addChunk(ubo_geom_state, 3); // buffer binding point 3
977 geom_state->addChunk(shader_var_chunk); // block binding point
979 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
980 polygonChunk->setFrontMode(GL_SMOOTH);
981 polygonChunk->setBackMode(GL_SMOOTH);
982 polygonChunk->setOffsetFactor(1.f);
983 polygonChunk->setOffsetBias(1.f);
984 polygonChunk->setOffsetFill(true);
985 polygonChunk->setCullFace(GL_NONE);
986 geom_state->addChunk(polygonChunk);
987 geom_state->setTransparencyMode(OSG::Material::TransparencyForceOpaque);
989 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk = OSG::TwoSidedLightingChunk::create();
990 geom_state->addChunk(twoSidedLightingChunk);
992 box_plane->setMaterial(geom_state);
994 return OSG::NodeTransitPtr(box_root);
997 OSG::NodeTransitPtr createGeometry()
999 int idx = geom_idx_die();
1001 OSG::GeometryRefPtr geometry;
1003 switch (idx)
1005 case 0: // cone
1006 geometry = OSG::makeConeGeo(3.f * small_die(), 1.f * small_die(), 24, true, true);
1007 break;
1008 case 1: // box
1009 geometry = OSG::makeBoxGeo(3.f * small_die(), 3.f * small_die(), 3.f * small_die(), 1, 1, 1);
1010 break;
1011 case 2: // cylinder
1012 geometry = OSG::makeCylinderGeo(3.f * small_die(), .3f, 24, true, true, true );
1013 break;
1014 case 3: // sphere
1015 geometry = OSG::makeSphereGeo(6, 3.f * small_die());
1016 break;
1017 case 4: // torus
1018 geometry = OSG::makeTorusGeo(0.6f * small_die(), 2.f * small_die(), 24, 36);
1019 break;
1020 case 5: // ellipsoide
1021 geometry = OSG::makeLatLongEllipsoidGeo(24, 36, 2.f * small_die(), 1.f * small_die());
1022 break;
1023 case 6: // frustum
1024 geometry = OSG::makeConicalFrustumGeo(2.f * small_die(), 2.f * small_die(), 2.f * small_die(), 6, true, true, true);
1025 break;
1026 case 7: // teapot
1027 geometry = OSG::makeTeapotGeo(24, 1.f * small_die());
1028 break;
1031 OSG::NodeRefPtr geomNode = OSG::makeNodeFor(geometry);
1033 OSG::TransformRefPtr trafoCore = OSG::Transform::create();
1034 OSG::NodeRefPtr transNode = OSG::makeNodeFor(trafoCore);
1035 transNode->addChild(geomNode);
1037 GeomState geom; geom.material_index = material_idx_die();
1038 OSG::ChunkMaterialRefPtr geom_state = OSG::ChunkMaterial::create();
1039 OSG::MultiPropertyUBOChunkRefPtr ubo_geom_state = create_geometry_material_state(geom);
1040 geom_state->addChunk(ubo_geom_state, 3); // buffer binding point 3
1041 geom_state->addChunk(shader_var_chunk); // block binding point
1043 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
1044 polygonChunk->setFrontMode(GL_SMOOTH);
1045 polygonChunk->setBackMode(GL_SMOOTH);
1046 polygonChunk->setOffsetFactor(1.f);
1047 polygonChunk->setOffsetBias(1.f);
1048 polygonChunk->setOffsetFill(true);
1050 OSG::Real32 opacity = materials[geom.material_index].opacity;
1051 if (opacity < 1.f)
1053 polygonChunk->setCullFace(GL_NONE);
1055 OSG::BlendChunkRefPtr blendChunk = OSG::BlendChunk::create();
1056 blendChunk->setSrcFactor (GL_SRC_ALPHA);
1057 blendChunk->setDestFactor(GL_ONE_MINUS_SRC_ALPHA);
1058 geom_state->addChunk(blendChunk);
1059 geom_state->setTransparencyMode(OSG::Material::TransparencyForceTransparent);
1061 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk = OSG::TwoSidedLightingChunk::create();
1062 geom_state->addChunk(twoSidedLightingChunk);
1064 } else {
1065 polygonChunk->setCullFace(GL_BACK);
1066 geom_state->setTransparencyMode(OSG::Material::TransparencyForceOpaque);
1069 geom_state->addChunk(polygonChunk);
1071 geometry->setMaterial(geom_state);
1073 geom_nodes.push_back(transNode);
1074 geom_trafos.push_back(trafoCore);
1075 ubo_geom_states.push_back(ubo_geom_state);
1077 geom_curves.push_back(SmoothCubicBezierSpline(dice_knots(true)));
1079 return OSG::NodeTransitPtr(transNode);
1083 // forward declaration so we can have the interesting stuff upfront
1085 int setupGLUT (int *argc, char *argv[]);
1086 void print_help();
1087 void releaseGLUT();
1090 // Initialize GLUT & OpenSG and set up the scene
1092 int main(int argc, char **argv)
1094 // OSG init
1095 OSG::osgInit(argc,argv);
1097 // GLUT init
1098 int winid = setupGLUT(&argc, argv);
1100 print_help();
1102 // open a new scope, because the pointers below should go out of scope
1103 // before entering glutMainLoop.
1104 // Otherwise OpenSG will complain about objects being alive after shutdown.
1106 // the connection between GLUT and OpenSG
1107 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
1108 gwin->setGlutId(winid);
1109 gwin->init();
1111 // create the SimpleSceneManager helper
1112 mgr = OSG::SimpleSceneManager::create();
1113 mgr->setWindow(gwin);
1115 // The scene
1116 hdr_node = OSG::makeCoredNode<OSG::Group>();
1117 scene_node = OSG::makeCoredNode<OSG::Group>();
1119 hdr_node->addChild(scene_node);
1121 mgr->setRoot(hdr_node);
1123 createHDRStage();
1126 // create the shader program
1128 OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
1129 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
1130 OSG::ShaderProgramRefPtr fragShader = OSG::ShaderProgram::createFragmentShader();
1132 vertShader->setProgram(get_vp_program());
1133 fragShader->setProgram(get_fp_program());
1135 fragShader->addOSGVariable("OSGViewMatrix");
1138 // binding the shader storage block to a buffer binding point can be performed
1139 // either by calling the shaders's addShaderStorageBlock method or by
1140 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
1141 // In the following we use both variants for illustration.
1143 fragShader->addShaderStorageBlock("Materials", 1); // block binding point
1144 fragShader->addShaderStorageBlock("Lights", 2); // block binding point
1147 // The following is replaced by adding ShaderProgramVariableChunk objects
1148 // to the chunk material. See below...
1150 // fragShader->addShaderStorageBlock("GeomState", 3); // block binding point
1152 prog_chunk->addShader(vertShader);
1153 prog_chunk->addShader(fragShader);
1156 // The block binding is added to each ChunkMaterial in order to provide the state
1157 // shader uniform block for the geometery shown in the scene
1159 shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
1160 shader_var_chunk->addUniformBlock("GeomState", 3); // block binding point
1163 // Because we animate the lights by simple geometry, the lights initialization must be happens
1164 // after the creation of the 'shader_var_chunk' block binding point.
1165 // Additionally, it must happens before we call 'create_light_state', since here we do need the
1166 // already defined lights.
1168 initialize_lights(1);
1171 // create shader storage buffer objects and corresponding materials
1173 ssbo_material_database = create_material_database_state(materials);
1174 multi_light_chunk = create_light_state(lights);
1176 //multi_light_chunk->setEyeSpace(true);
1178 OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
1179 polygon_chunk->setFrontMode(GL_FILL);
1180 polygon_chunk->setBackMode(GL_FILL);
1181 polygon_chunk->setCullFace(GL_NONE);
1183 OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
1184 depth_chunk->setEnable(true);
1186 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
1187 prog_state->addChunk(ssbo_material_database, 1); // buffer binding point 1
1188 prog_state->addChunk(multi_light_chunk, 2); // buffer binding point 2
1189 prog_state->addChunk(prog_chunk);
1190 prog_state->addChunk(polygon_chunk);
1191 prog_state->addChunk(depth_chunk);
1193 scene_node->addChild(createBox());
1195 for (OSG::Int32 i = 0; i < num_geometries; ++i)
1196 scene_node->addChild(createGeometry());
1198 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
1199 mgrp->setMaterial(prog_state);
1200 scene_node->setCore(mgrp);
1202 OSG::commitChanges();
1204 // show the whole scene
1205 mgr->showAll();
1208 // GLUT main loop
1209 glutMainLoop();
1211 return 0;
1215 // GLUT callback functions
1219 // redraw the window
1221 OSG::TimeStamp time_stamp = 0;
1222 OSG::Real32 simulation_param = 0.f;
1223 bool simulate_geometry = true;
1224 bool simulate_lights = true;
1226 void display(void)
1228 // create the matrix
1229 OSG::Matrix m;
1231 if (time_stamp == 0)
1232 time_stamp = OSG::getTimeStamp();
1234 OSG::Time elapsed = OSG::getTimeStampMsecs(OSG::getTimeStamp() - time_stamp);
1236 if (elapsed > elapse_time_limit)
1238 simulation_param += simulation_delta;
1239 if (simulation_param >= 1.f)
1240 simulation_param = 0.f;
1242 if (simulate_geometry)
1244 std::size_t numCurves = geom_curves.size();
1246 OSG_ASSERT(numCurves == geom_trafos.size());
1248 for (std::size_t i = 0; i < numCurves; ++i)
1250 m = geom_curves[i].frame(simulation_param);
1251 geom_trafos[i]->setMatrix(m);
1255 if (simulate_lights)
1257 BOOST_FOREACH(Light& light, lights)
1259 m = light.curve.frame(simulation_param, true);
1260 light.transform->setMatrix(m);
1264 time_stamp = OSG::getTimeStamp();
1267 OSG::commitChanges();
1269 mgr->redraw();
1273 // react to size changes
1275 void reshape(int w, int h)
1277 mgr->resize(w, h);
1278 glutPostRedisplay();
1282 // react to mouse button presses
1284 void mouse(int button, int state, int x, int y)
1286 if (state)
1287 mgr->mouseButtonRelease(button, x, y);
1288 else
1289 mgr->mouseButtonPress(button, x, y);
1291 glutPostRedisplay();
1295 // react to mouse motions with pressed buttons
1297 void motion(int x, int y)
1299 mgr->mouseMove(x, y);
1300 glutPostRedisplay();
1304 // react to keys
1306 void keyboard(unsigned char k, int x, int y)
1308 switch(k)
1310 case 27: // ESC
1312 // clean up global variables
1313 mgr = NULL;
1315 hdr_stage = NULL;
1316 hdr_node = NULL;
1318 scene_node = NULL;
1320 multi_light_chunk = NULL;
1321 shader_var_chunk = NULL;
1323 geom_nodes.clear();
1324 geom_trafos.clear();
1325 geom_curves.clear();
1327 ubo_geom_states.clear();
1329 materials.clear();
1330 lights.clear();
1332 releaseGLUT();
1334 OSG::osgExit();
1335 exit(0);
1337 break;
1339 case 32: // Space
1341 simulate_geometry = !simulate_geometry;
1343 break;
1345 case 'l':
1347 simulate_lights = !simulate_lights;
1349 break;
1351 case 'o':
1353 elapse_time_limit *= 2.f;
1355 break;
1357 case 'O':
1359 elapse_time_limit /= 2.f;
1361 break;
1363 case 'e':
1365 simulation_delta *= 2.f;
1367 break;
1369 case 'E':
1371 simulation_delta /= 2.f;
1373 break;
1375 case 'r':
1377 initialize_lights(1);
1378 update_light_state(multi_light_chunk, lights);
1379 update_material_database_state(ssbo_material_database, materials);
1381 simulation_delta = 0.0001f;
1382 elapse_time_limit = 10.f;
1384 simulate_geometry = true;
1385 simulate_lights = true;
1387 glutPostRedisplay();
1389 break;
1391 case 'a':
1393 BOOST_FOREACH(Light& light, lights)
1394 light.linearAttenuation *= linearAttFactor;
1396 update_light_state(multi_light_chunk, lights);
1397 glutPostRedisplay();
1399 break;
1401 case 'A':
1403 BOOST_FOREACH(Light& light, lights)
1404 if (light.linearAttenuation / linearAttFactor >= OSG::Eps)
1405 light.linearAttenuation /= linearAttFactor;
1407 update_light_state(multi_light_chunk, lights);
1408 glutPostRedisplay();
1410 break;
1412 case 'q':
1414 BOOST_FOREACH(Light& light, lights)
1415 light.quadraticAttenuation *= quadraticAttFactor;
1417 update_light_state(multi_light_chunk, lights);
1418 glutPostRedisplay();
1420 break;
1422 case 'Q':
1424 BOOST_FOREACH(Light& light, lights)
1425 if (light.quadraticAttenuation / quadraticAttFactor >= OSG::Eps)
1426 light.quadraticAttenuation /= quadraticAttFactor;
1428 update_light_state(multi_light_chunk, lights);
1429 glutPostRedisplay();
1431 break;
1433 case 'x':
1435 BOOST_FOREACH(Light& light, lights)
1436 light.spotExponent *= spotExponentFactor;
1438 update_light_state(multi_light_chunk, lights);
1439 glutPostRedisplay();
1441 break;
1443 case 'X':
1445 BOOST_FOREACH(Light& light, lights)
1446 if (light.spotExponent / spotExponentFactor >= OSG::Eps)
1447 light.spotExponent /= spotExponentFactor;
1449 update_light_state(multi_light_chunk, lights);
1450 glutPostRedisplay();
1452 break;
1454 case '1':
1456 initialize_lights(1);
1457 update_light_state(multi_light_chunk, lights);
1458 update_material_database_state(ssbo_material_database, materials);
1459 glutPostRedisplay();
1461 break;
1463 case '2':
1465 if (lights.size() > 1)
1467 OSG::UInt32 num = static_cast<OSG::UInt32>(lights.size() / 2);
1468 initialize_lights(num);
1469 update_light_state(multi_light_chunk, lights);
1470 update_material_database_state(ssbo_material_database, materials);
1471 glutPostRedisplay();
1474 break;
1476 case '3':
1478 if (lights.size() <= max_num_lights)
1480 OSG::UInt32 num = static_cast<OSG::UInt32>(lights.size() * 2);
1481 initialize_lights(num);
1482 update_light_state(multi_light_chunk, lights);
1483 update_material_database_state(ssbo_material_database, materials);
1484 glutPostRedisplay();
1487 break;
1489 case '4':
1491 if (geom_nodes.size() > 1)
1493 OSG::UInt32 num = static_cast<OSG::UInt32>(geom_nodes.size() / 2);
1495 BOOST_FOREACH(OSG::Node* node, geom_nodes)
1496 scene_node->subChild(node);
1498 geom_nodes.clear();
1499 geom_trafos.clear();
1500 geom_curves.clear();
1501 ubo_geom_states.clear();
1503 for (OSG::UInt32 i = 0; i < num; ++i)
1504 scene_node->addChild(createGeometry());
1506 glutPostRedisplay();
1509 break;
1511 case '5':
1513 if (geom_nodes.size() <= 4.f * num_geometries)
1515 OSG::UInt32 num = static_cast<OSG::UInt32>(geom_nodes.size() * 2);
1517 BOOST_FOREACH(OSG::Node* node, geom_nodes)
1518 scene_node->subChild(node);
1520 geom_nodes.clear();
1521 geom_trafos.clear();
1522 geom_curves.clear();
1523 ubo_geom_states.clear();
1525 for (OSG::UInt32 i = 0; i < num; ++i)
1526 scene_node->addChild(createGeometry());
1528 glutPostRedisplay();
1531 break;
1533 case 'm':
1535 BOOST_FOREACH(OSG::MultiPropertyUBOChunk* ubo_geom_state, ubo_geom_states)
1537 GeomState geom; geom.material_index = material_idx_die();
1538 update_geometry_material_state(ubo_geom_state, geom);
1541 glutPostRedisplay();
1543 break;
1545 case 's':
1547 mgr->setStatistics(!mgr->getStatistics());
1549 break;
1551 case 'h':
1553 OSG::HDR2Stage* core = dynamic_cast<OSG::HDR2Stage*>(hdr_node->getCore());
1554 if (core)
1555 removeHDRStage();
1556 else
1557 createHDRStage();
1559 glutPostRedisplay();
1561 break;
1566 // setup the GLUT library which handles the windows for us
1568 int setupGLUT(int *argc, char *argv[])
1570 glutInit(argc, argv);
1571 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
1572 glutInitWindowSize(1000, 800);
1574 int winid = glutCreateWindow("OpenSG");
1576 glutReshapeFunc(reshape);
1577 glutDisplayFunc(display);
1578 glutMouseFunc(mouse);
1579 glutMotionFunc(motion);
1580 glutKeyboardFunc(keyboard);
1582 // call the redraw function whenever there's nothing else to do
1583 glutIdleFunc(display);
1585 return winid;
1588 void releaseGLUT()
1590 glutReshapeFunc(NULL);
1591 glutDisplayFunc(NULL);
1592 glutMouseFunc(NULL);
1593 glutMotionFunc(NULL);
1594 glutKeyboardFunc(NULL);
1595 glutIdleFunc(NULL);
1598 void print_help()
1600 std::cout << "Esc : quit example" << std::endl;
1601 std::cout << "Space : toogle geometry simulation on/off" << std::endl;
1602 std::cout << "h : toogle HDR stage usage on/off" << std::endl;
1603 std::cout << "l : toogle light simulation on/off" << std::endl;
1604 std::cout << "m : assign new color to geometry" << std::endl;
1605 std::cout << "r : reset the example" << std::endl;
1606 std::cout << "s : toogle statistics on/off" << std::endl;
1607 std::cout << "1 : only one light" << std::endl;
1608 std::cout << "2 : half number of lights" << std::endl;
1609 std::cout << "3 : double number of lights" << std::endl;
1610 std::cout << "4 : half number of geometry objects" << std::endl;
1611 std::cout << "5 : double number of geometry objects" << std::endl;
1612 std::cout << "e/E : speed up/down simulation" << std::endl;
1613 std::cout << "o/O : double/half simulation time interval" << std::endl;
1614 std::cout << "a/A : increase/decrease linear attenuation factor" << std::endl;
1615 std::cout << "q/Q : increase/decrease quadratic attenuation factor" << std::endl;
1616 std::cout << "x/X : increase/decrease spot exponent" << std::endl;
1619 // ============================================================================
1621 // Part VI: Cubic Bezier spline curve implementation
1623 // ============================================================================
1625 CubicBezierCurve::CubicBezierCurve(
1626 const OSG::Pnt3f& p0,
1627 const OSG::Pnt3f& p1,
1628 const OSG::Pnt3f& p2,
1629 const OSG::Pnt3f& p3)
1631 p[0] = p0; p[1] = p1; p[2] = p2; p[3] = p3;
1634 CubicBezierCurve::CubicBezierCurve(const CubicBezierCurve& rhs)
1636 p[0] = rhs.p[0]; p[1] = rhs.p[1]; p[2] = rhs.p[2]; p[3] = rhs.p[3];
1639 CubicBezierCurve& CubicBezierCurve::operator=(const CubicBezierCurve& rhs)
1641 if (this != &rhs)
1643 p[0] = rhs.p[0]; p[1] = rhs.p[1]; p[2] = rhs.p[2]; p[3] = rhs.p[3];
1645 return *this;
1648 OSG::Pnt3f CubicBezierCurve::operator()(OSG::Real32 t) const
1650 OSG_ASSERT(0.f <= t && t <= 1.f);
1652 OSG::Real32 e = 1.f - t;
1653 OSG::Real32 sq_e = e * e;
1654 OSG::Real32 sq_t = t * t;
1656 return e * sq_e * p[0]
1657 + 3.f * t * sq_e * p[1].subZero()
1658 + 3.f * sq_t * e * p[2].subZero()
1659 + t * sq_t * p[3].subZero();
1662 OSG::Vec3f CubicBezierCurve::tangent(OSG::Real32 t) const
1664 OSG::Vec3f tangent = fst_derivative(t);
1665 tangent.normalize();
1667 return tangent;
1670 OSG::Vec3f CubicBezierCurve::normal(OSG::Real32 t) const
1672 OSG::Vec3f normal = binormal(t);
1673 normal.crossThis(tangent(t));
1674 normal.normalize();
1676 return normal;
1679 OSG::Vec3f CubicBezierCurve::binormal(OSG::Real32 t) const
1681 OSG::Vec3f binormal = fst_derivative(t);
1682 binormal.crossThis(sec_derivative(t));
1683 binormal.normalize();
1685 while (OSG::osgAbs(binormal.length() - 1.f) >= OSG::Eps)
1687 if (t + OSG::Eps <= 1.f)
1688 t += OSG::Eps;
1689 else if (t - OSG::Eps >= 0.f)
1690 t -= OSG::Eps;
1691 else
1692 OSG_ASSERT(false);
1694 binormal = fst_derivative(t);
1695 binormal.crossThis(sec_derivative(t));
1696 binormal.normalize();
1699 return binormal;
1702 OSG::Matrix CubicBezierCurve::frame(OSG::Real32 t, bool position_only) const
1704 OSG::Matrix mat;
1705 mat.identity();
1707 OSG::Vec3f P = (*this)(t).subZero();
1709 if (position_only)
1711 mat.setTranslate(P);
1713 else
1715 OSG::Vec3f T = tangent(t);
1716 OSG::Vec3f N = normal(t);
1717 OSG::Vec3f B = binormal(t);
1720 OSG::Real32 lT = T.length();
1721 OSG::Real32 lN = N.length();
1722 OSG::Real32 lB = B.length();
1724 OSG::Real32 v1 = T.dot(N);
1725 OSG::Real32 v2 = T.dot(B);
1726 OSG::Real32 v3 = N.dot(B);
1728 OSG_ASSERT(OSG::osgAbs(T.length() - 1.f) < OSG::Eps);
1729 OSG_ASSERT(OSG::osgAbs(N.length() - 1.f) < OSG::Eps);
1730 OSG_ASSERT(OSG::osgAbs(B.length() - 1.f) < OSG::Eps);
1732 mat.setValue(T,N,B,P);
1735 return mat;
1738 OSG::Real32 CubicBezierCurve::length(OSG::UInt32 numSeg) const
1740 OSG_ASSERT(numSeg >= 2);
1742 OSG::Real32 d = 1.f / numSeg;
1743 OSG::Real32 t = d;
1744 OSG::Real32 l = 0.f;
1746 OSG::Pnt3f p0 = operator()(0.f);
1748 while (t <= 1.f)
1750 OSG::Pnt3f p1 = operator()(t);
1752 l += (p1 - p0).length();
1753 t += d;
1756 return l;
1759 OSG::Vec3f CubicBezierCurve::fst_derivative(OSG::Real32 t) const
1761 OSG::Vec3f v10 = p[1] - p[0];
1762 OSG::Vec3f v21 = p[2] - p[1];
1763 OSG::Vec3f v32 = p[3] - p[2];
1765 OSG::Real32 e = 1.f - t;
1766 OSG::Real32 sq_e = e * e;
1767 OSG::Real32 sq_t = t * t;
1769 return 3.f * sq_e * v10 + 6.f * e * t * v21 + 3.f * sq_t * v32;
1772 OSG::Vec3f CubicBezierCurve::sec_derivative(OSG::Real32 t) const
1774 OSG::Vec3f v210 = p[2] - 2.f * p[1] + p[0].subZero();
1775 OSG::Vec3f v321 = p[3] - 2.f * p[2] + p[1].subZero();
1777 OSG::Real32 e = 1.f - t;
1779 return 6.f * e * v210 + 6.f * t * v321;
1782 OSG::Vec3f CubicBezierCurve::thr_devivative(OSG::Real32 t) const
1784 OSG::Vec3f v21 = p[2] - p[1];
1785 OSG::Vec3f v30 = p[3] - p[0];
1787 return -18.f * v21 + 6.f * v30;
1791 SmoothCubicBezierSpline::SmoothCubicBezierSpline(const std::vector<OSG::Pnt3f>& knots)
1792 : knots(knots)
1794 OSG_ASSERT(knots.size() > 3);
1796 points_t p1, p2;
1798 calc_ctrl_pnts(p1, p2);
1800 std::size_t n = knots.size() - 1;
1802 std::vector<OSG::Real32> lengths(n);
1803 OSG::Real32 L = 0.f;
1805 for (std::size_t i = 0; i < n; ++i)
1807 curves.push_back(CubicBezierCurve(knots[i], p1[i], p2[i], knots[i+1]));
1809 lengths[i] = curves[i].length();
1810 L += lengths[i];
1813 OSG_ASSERT(L > 0.f);
1815 OSG::Real32 d = 1.f / L;
1817 intervals.resize(n);
1819 intervals[0] = d * lengths[0];
1821 for (std::size_t i = 1; i < n-1; ++i)
1823 intervals[i] = intervals[i-1] + d * lengths[i];
1826 intervals[n-1] = 1.f;
1829 SmoothCubicBezierSpline::SmoothCubicBezierSpline(const SmoothCubicBezierSpline& rhs)
1830 : knots(rhs.knots)
1831 , intervals(rhs.intervals)
1832 , curves(rhs.curves)
1836 SmoothCubicBezierSpline& SmoothCubicBezierSpline::operator=(const SmoothCubicBezierSpline& rhs)
1838 if (this != &rhs)
1840 knots = rhs.knots;
1841 intervals = rhs.intervals;
1842 curves = rhs.curves;
1844 return *this;
1847 OSG::Pnt3f SmoothCubicBezierSpline::operator()(OSG::Real32 t) const
1849 std::size_t idx = index(t);
1850 return curves[idx](t_(t, idx));
1853 OSG::Vec3f SmoothCubicBezierSpline::tangent(OSG::Real32 t) const
1855 std::size_t idx = index(t);
1856 return curves[idx].tangent(t_(t, idx));
1859 OSG::Vec3f SmoothCubicBezierSpline::normal(OSG::Real32 t) const
1861 std::size_t idx = index(t);
1862 return curves[idx].normal(t_(t, idx));
1865 OSG::Vec3f SmoothCubicBezierSpline::binormal(OSG::Real32 t) const
1867 std::size_t idx = index(t);
1868 return curves[idx].binormal(t_(t, idx));
1871 OSG::Matrix SmoothCubicBezierSpline::frame(OSG::Real32 t, bool position_only) const
1873 std::size_t idx = index(t);
1874 return curves[idx].frame(t_(t, idx), position_only);
1877 OSG::Real32 SmoothCubicBezierSpline::length(OSG::UInt32 numSeg) const
1879 OSG::Real32 l = 0.f;
1880 BOOST_FOREACH(const CubicBezierCurve& c, curves)
1882 l += c.length(numSeg);
1884 return l;
1887 void SmoothCubicBezierSpline::calc_ctrl_pnts(points_t& p1, points_t& p2) const
1889 namespace tp = boost::tuples;
1890 typedef tp::tuple<OSG::Real32, OSG::Real32, OSG::Real32> tuple_t;
1891 typedef std::vector<tuple_t> tuples_t;
1893 std::size_t n = knots.size()-1;
1895 p1.resize(n);
1896 p2.resize(n);
1898 tuples_t a(n), b(n), c(n), d(n);
1900 a[0] = tp::make_tuple(0.f, 0.f, 0.f);
1901 b[0] = tp::make_tuple(2.f, 2.f, 2.f);
1902 c[0] = tp::make_tuple(1.f, 1.f, 1.f);
1903 d[0] = tp::make_tuple(
1904 knots[0].x() + 2.f * knots[1].x(),
1905 knots[0].y() + 2.f * knots[1].y(),
1906 knots[0].z() + 2.f * knots[1].z());
1908 for (std::size_t i = 1; i < n-1; ++i)
1910 a[i] = tp::make_tuple(1.f, 1.f, 1.f);
1911 b[i] = tp::make_tuple(4.f, 4.f, 4.f);
1912 c[i] = tp::make_tuple(1.f, 1.f, 1.f);
1913 d[i] = tp::make_tuple(
1914 4.f * knots[i].x() + 2.f * knots[i+1].x(),
1915 4.f * knots[i].y() + 2.f * knots[i+1].y(),
1916 4.f * knots[i].z() + 2.f * knots[i+1].z());
1919 a[n-1] = tp::make_tuple(2.f, 2.f, 2.f);
1920 b[n-1] = tp::make_tuple(7.f, 7.f, 7.f);
1921 c[n-1] = tp::make_tuple(0.f, 0.f, 0.f);
1922 d[n-1] = tp::make_tuple(
1923 8.f * knots[n-1].x() + 2.f * knots[n].x(),
1924 8.f * knots[n-1].y() + 2.f * knots[n].y(),
1925 8.f * knots[n-1].z() + 2.f * knots[n].z());
1927 for (std::size_t i = 1; i < n; ++i)
1929 tuple_t m = tp::make_tuple(
1930 a[i].get<0>() / b[i-1].get<0>(),
1931 a[i].get<1>() / b[i-1].get<1>(),
1932 a[i].get<2>() / b[i-1].get<2>());
1934 b[i] = tp::make_tuple(
1935 b[i].get<0>() - m.get<0>() * c[i-1].get<0>(),
1936 b[i].get<1>() - m.get<1>() * c[i-1].get<1>(),
1937 b[i].get<2>() - m.get<2>() * c[i-1].get<2>());
1939 d[i] = tp::make_tuple(
1940 d[i].get<0>() - m.get<0>() * d[i-1].get<0>(),
1941 d[i].get<1>() - m.get<1>() * d[i-1].get<1>(),
1942 d[i].get<2>() - m.get<2>() * d[i-1].get<2>());
1945 p1[n-1].setValues(
1946 d[n-1].get<0>() / b[n-1].get<0>(),
1947 d[n-1].get<1>() / b[n-1].get<1>(),
1948 d[n-1].get<2>() / b[n-1].get<2>());
1950 for (long long i = n-2; i >= 0; --i)
1952 p1[i].setValues(
1953 (d[i].get<0>() - c[i].get<0>() * p1[i+1].x()) / b[i].get<0>(),
1954 (d[i].get<1>() - c[i].get<1>() * p1[i+1].y()) / b[i].get<1>(),
1955 (d[i].get<2>() - c[i].get<2>() * p1[i+1].z()) / b[i].get<2>());
1958 for (std::size_t i = 0; i < n-1; ++i)
1960 p2[i].setValues(
1961 2.f * knots[i+1].x() - p1[i+1].x(),
1962 2.f * knots[i+1].y() - p1[i+1].y(),
1963 2.f * knots[i+1].z() - p1[i+1].z());
1966 p2[n-1].setValues(
1967 0.5f * knots[n].x() - p1[n-1].x(),
1968 0.5f * knots[n].y() - p1[n-1].y(),
1969 0.5f * knots[n].z() - p1[n-1].z());
1972 std::size_t SmoothCubicBezierSpline::index(OSG::Real32 t) const
1974 OSG_ASSERT(0.f <= t && t <= 1.f);
1976 std::vector<OSG::Real32>::const_iterator iter = std::lower_bound(intervals.begin(), intervals.end(), t);
1977 std::size_t r = iter - intervals.begin();
1978 return r;
1981 OSG::Real32 SmoothCubicBezierSpline::t_(OSG::Real32 t, std::size_t idx) const
1983 OSG_ASSERT(idx < intervals.size());
1985 OSG::Real32 t0 = 0.f;
1986 OSG::Real32 t1 = 1.f;
1988 if (idx > 0) t0 = intervals[idx-1];
1989 t1 = intervals[idx];
1991 OSG::Real32 r = (t - t0) / (t1 - t0);
1993 return r;
1996 // ============================================================================
1998 // Part VII: dice_knots helper implementation
2000 // ============================================================================
2002 typedef boost::tuples::tuple<int, int, int> index_t;
2004 struct index_hash_t : public std::unary_function<index_t, std::size_t>
2006 std::size_t operator()(const index_t& v) const
2008 std::size_t seed = 0;
2009 boost::hash_combine(seed, v.get<0>());
2010 boost::hash_combine(seed, v.get<1>());
2011 boost::hash_combine(seed, v.get<2>());
2012 return seed;
2016 std::vector<OSG::Pnt3f> dice_knots(bool close_curve)
2019 // idea: sample a number if different cube boxes from the scene and
2020 // take randomly one point from each cube. That guarantees that
2021 // the knot points do not clump and that they are all unequal.
2023 namespace tp = boost::tuples;
2025 boost::unordered_set<index_t, index_hash_t> indices;
2027 while (indices.size() < num_curve_knots)
2029 indices.insert(tp::make_tuple(box_idx_die(), box_idx_die(), box_idx_die()));
2032 OSG::Real32 l = 2 * world_size / num_grid_boxes;
2034 std::vector<OSG::Pnt3f> knots;
2036 BOOST_FOREACH(const index_t& idx, indices)
2038 OSG::Pnt3f p;
2039 p[0] = -world_size + idx.get<0>() * l + unit_die() * l;
2040 p[1] = -world_size + idx.get<1>() * l + unit_die() * l;
2041 p[2] = -world_size + idx.get<2>() * l + unit_die() * l;
2043 knots.push_back(p);
2046 if (close_curve)
2047 knots.push_back(knots.front());
2049 return knots;
2052 // ============================================================================
2054 // Part VIII: The shader programs
2056 // ============================================================================
2059 // vertex shader program.
2061 std::string get_vp_program()
2063 using namespace std;
2065 stringstream ost;
2067 ost << "#version 440 compatibility"
2068 << endl << ""
2069 << endl << "#extension GL_ARB_separate_shader_objects: enable"
2070 << endl << "#extension GL_ARB_shader_storage_buffer_object: enable"
2071 << endl << ""
2072 << endl << "smooth out vec3 vNormalES; // eye space normal"
2073 << endl << "smooth out vec3 vPositionES; // eye space position"
2074 << endl << ""
2075 << endl << "void main()"
2076 << endl << "{"
2077 << endl << " //"
2078 << endl << " // multiply the object space vertex position with the modelview matrix "
2079 << endl << " // to get the eye space vertex position"
2080 << endl << " //"
2081 << endl << " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;"
2082 << endl << ""
2083 << endl << " //"
2084 << endl << " // multiply the object space normal with the normal matrix (transpose of the inverse "
2085 << endl << " // model view matrix) to get the eye space normal"
2086 << endl << " //"
2087 << endl << " vNormalES = gl_NormalMatrix * gl_Normal;"
2088 << endl << ""
2089 << endl << " //"
2090 << endl << " // multiply the combiend modelview projection matrix with the object space vertex"
2091 << endl << " // position to get the clip space position"
2092 << endl << " //"
2093 << endl << " gl_Position = ftransform();"
2094 << endl << "}"
2095 << endl << ""
2096 << endl;
2098 return ost.str();
2102 // fragment shader program for bump mapping in surface local coordinates
2104 std::string get_fp_program()
2106 using namespace std;
2108 stringstream ost;
2110 ost << "#version 440 compatibility"
2111 << endl << ""
2112 << endl << "#extension GL_ARB_separate_shader_objects: enable"
2113 << endl << "#extension GL_ARB_shader_storage_buffer_object: enable"
2114 << endl << ""
2115 << endl << "smooth in vec3 vNormalES; // eye space normal"
2116 << endl << "smooth in vec3 vPositionES; // eye space position"
2117 << endl << ""
2118 << endl << "const int num_materials = 5000;"
2119 << endl << ""
2120 << endl << "const int POINT_LIGHT = 1; // defined in OSGMultiLightChunk.h"
2121 << endl << "const int DIRECTIONAL_LIGHT = 2;"
2122 << endl << "const int SPOT_LIGHT = 3;"
2123 << endl << "const int CINEMA_LIGHT = 4;"
2124 << endl << ""
2125 << endl << "uniform mat4 OSGViewMatrix;"
2126 << endl << ""
2127 << endl << "struct Light"
2128 << endl << "{"
2129 << endl << " vec3 position; // in world space"
2130 << endl << " vec3 direction; // in world space"
2131 << endl << " vec3 Ia;"
2132 << endl << " vec3 Id;"
2133 << endl << " vec3 Is;"
2134 << endl << " float const_attenuation;"
2135 << endl << " float linear_attenuation;"
2136 << endl << " float quadratic_attenuation;"
2137 << endl << " float rangeCutOn;"
2138 << endl << " float rangeCutOff;"
2139 << endl << " float cosSpotlightAngle;"
2140 << endl << " float spotExponent;"
2141 << endl << " int type; // specific type of light: POINT_LIGHT, DIRECTIONAL_LIGHT, SPOT_LIGHT or CINEMA_LIGHT"
2142 << endl << " bool enabled; // on/off state of light"
2143 << endl << "};"
2144 << endl << ""
2145 << endl << "layout (std430) buffer Lights"
2146 << endl << "{"
2147 << endl << " Light light[];"
2148 << endl << "} lights;"
2149 << endl << ""
2150 << endl << "struct Material"
2151 << endl << "{"
2152 << endl << " vec3 ambient;"
2153 << endl << " vec3 diffuse;"
2154 << endl << " vec3 specular;"
2155 << endl << " vec3 emissive;"
2156 << endl << ""
2157 << endl << " float opacity;"
2158 << endl << " float shininess;"
2159 << endl << "};"
2160 << endl << ""
2161 << endl << "layout (std430) buffer Materials"
2162 << endl << "{"
2163 << endl << " Material material[num_materials];"
2164 << endl << "} materials;"
2165 << endl << ""
2166 << endl << ""
2167 << endl << "layout (std140) uniform GeomState"
2168 << endl << "{"
2169 << endl << " int material_index;"
2170 << endl << "} geom_state;"
2171 << endl << ""
2172 << endl << "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!"
2173 << endl << ""
2174 << endl << "layout(location = 0) out vec4 vFragColor;"
2175 << endl << ""
2176 << endl << "//"
2177 << endl << "// Calculate the attenuation of the light based on its"
2178 << endl << "// constant, linear and quadratic attenuation factors"
2179 << endl << "// and the distance d of the light to the current point."
2180 << endl << "//"
2181 << endl << "float calcAttenuation(in float c, in float l, in float q, in float d)"
2182 << endl << "{"
2183 << endl << " return 1.0 / (c + l*d + q*d*d);"
2184 << endl << "}"
2185 << endl << ""
2186 << endl << "//"
2187 << endl << "// Calculate the attenuation with respect to the spot light cone."
2188 << endl << "// Parameters:"
2189 << endl << "// cutoff : cosine of the spot cutoff angle"
2190 << endl << "// exponent : the spot exponent"
2191 << endl << "// l : normalized direction between fragment and light position"
2192 << endl << "// s : normalized light direction"
2193 << endl << "//"
2194 << endl << "float spotAttenuation(in float cutoff, in float exponent, in vec3 l, in vec3 s)"
2195 << endl << "{"
2196 << endl << " float attenuation = 0.0;"
2197 << endl << " float l_dot_s = dot(-l, s);"
2198 << endl << " if (l_dot_s >= cutoff)"
2199 << endl << " attenuation = pow(l_dot_s, exponent);"
2200 << endl << " return attenuation;"
2201 << endl << "}"
2202 << endl << ""
2203 << endl << "//"
2204 << endl << "// directional light contribution"
2205 << endl << "//"
2206 << endl << "vec3 directionalLight("
2207 << endl << " in int i, // light identifier, i.e. current light"
2208 << endl << " in int j, // material identifier"
2209 << endl << " in vec3 n, // vertex normal in eye space"
2210 << endl << " in vec3 v) // view direction in eye space"
2211 << endl << "{"
2212 << endl << " if (!lights.light[i].enabled)"
2213 << endl << " return vec3(0.0, 0.0, 0.0);"
2214 << endl << ""
2215 << endl << " //"
2216 << endl << " // the light direction in eye space"
2217 << endl << " //"
2218 << endl << " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
2219 << endl << " vec3 l = -direction.xyz;"
2220 << endl << ""
2221 << endl << " //"
2222 << endl << " // the half vector"
2223 << endl << " //"
2224 << endl << " vec3 h = normalize(l+v);"
2225 << endl << ""
2226 << endl << " float n_dot_l = max(0.0, dot(n, l));"
2227 << endl << " float n_dot_h = max(0.0, dot(n, h));"
2228 << endl << ""
2229 << endl << " float m = materials.material[j].shininess;"
2230 << endl << ""
2231 << endl << " float pf; // power factor"
2232 << endl << ""
2233 << endl << " if (n_dot_l == 0.0)"
2234 << endl << " pf = 0.0;"
2235 << endl << " else"
2236 << endl << " pf = pow(n_dot_h, m);"
2237 << endl << ""
2238 << endl << " return materials.material[j].emissive"
2239 << endl << " + lights.light[i].Ia * materials.material[j].ambient"
2240 << endl << " + lights.light[i].Id * materials.material[j].diffuse * n_dot_l"
2241 << endl << " + lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf;"
2242 << endl << "}"
2243 << endl << ""
2244 << endl << "//"
2245 << endl << "// point light contribution"
2246 << endl << "//"
2247 << endl << "vec3 pointLight("
2248 << endl << " in int i, // light identifier, i.e. current light"
2249 << endl << " in int j, // material identifier"
2250 << endl << " in vec3 n, // vertex normal in eye space"
2251 << endl << " in vec3 v, // view direction in eye space"
2252 << endl << " in vec3 p) // vertex position in eye space"
2253 << endl << "{"
2254 << endl << " if (!lights.light[i].enabled)"
2255 << endl << " return vec3(0.0, 0.0, 0.0);"
2256 << endl << ""
2257 << endl << " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
2258 << endl << " vec3 l = position.xyz - p; // dir from surface to light position"
2259 << endl << " float d = length(l); // dist from surface to light source"
2260 << endl << ""
2261 << endl << " if (lights.light[i].rangeCutOff < d)"
2262 << endl << " return vec3(0.0, 0.0, 0.0);"
2263 << endl << ""
2264 << endl << " l = normalize(l); // norm direction from surf to light"
2265 << endl << ""
2266 << endl << " //"
2267 << endl << " // the half vector"
2268 << endl << " //"
2269 << endl << " vec3 h = normalize(l+v);"
2270 << endl << ""
2271 << endl << " float n_dot_l = max(0.0, dot(n, l));"
2272 << endl << " float n_dot_h = max(0.0, dot(n, h));"
2273 << endl << ""
2274 << endl << " float m = materials.material[j].shininess;"
2275 << endl << ""
2276 << endl << " float pf; // power factor"
2277 << endl << ""
2278 << endl << " if (n_dot_l == 0.0)"
2279 << endl << " pf = 0.0;"
2280 << endl << " else"
2281 << endl << " pf = pow(n_dot_h, m);"
2282 << endl << ""
2283 << endl << " float attenuation = calcAttenuation("
2284 << endl << " lights.light[i].const_attenuation,"
2285 << endl << " lights.light[i].linear_attenuation,"
2286 << endl << " lights.light[i].quadratic_attenuation,"
2287 << endl << " d);"
2288 << endl << ""
2289 << endl << " return materials.material[j].emissive"
2290 << endl << " + attenuation * lights.light[i].Ia * materials.material[j].ambient"
2291 << endl << " + attenuation * lights.light[i].Id * materials.material[j].diffuse * n_dot_l"
2292 << endl << " + attenuation * lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf;"
2293 << endl << "}"
2294 << endl << ""
2295 << endl << "//"
2296 << endl << "// spot light contribution"
2297 << endl << "//"
2298 << endl << "vec3 spotLight("
2299 << endl << " in int i, // light identifier, i.e. current light"
2300 << endl << " in int j, // material identifier"
2301 << endl << " in vec3 n, // vertex normal in eye space"
2302 << endl << " in vec3 v, // view direction in eye space"
2303 << endl << " in vec3 p) // vertex position in eye space"
2304 << endl << "{"
2305 << endl << " if (!lights.light[i].enabled)"
2306 << endl << " return vec3(0.0, 0.0, 0.0);"
2307 << endl << ""
2308 << endl << " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
2309 << endl << " vec3 l = position.xyz - p; // dir from surface to light position"
2310 << endl << " float d = length(l); // dist from surface to light source"
2311 << endl << ""
2312 << endl << " if (lights.light[i].rangeCutOff < d)"
2313 << endl << " return vec3(0.0, 0.0, 0.0);"
2314 << endl << ""
2315 << endl << " l = normalize(l); // norm dir from surface to light"
2316 << endl << " "
2317 << endl << " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
2318 << endl << " vec3 s = direction.xyz;"
2319 << endl << " s = normalize(s);"
2320 << endl << ""
2321 << endl << " //"
2322 << endl << " // the half vector"
2323 << endl << " //"
2324 << endl << " vec3 h = normalize(l+v);"
2325 << endl << ""
2326 << endl << " float n_dot_l = max(0.0, dot(n, l));"
2327 << endl << " float n_dot_h = max(0.0, dot(n, h));"
2328 << endl << ""
2329 << endl << " float m = materials.material[j].shininess;"
2330 << endl << ""
2331 << endl << " float pf; // power factor"
2332 << endl << ""
2333 << endl << " if (n_dot_l == 0.0)"
2334 << endl << " pf = 0.0;"
2335 << endl << " else"
2336 << endl << " pf = pow(n_dot_h, m);"
2337 << endl << ""
2338 << endl << " float attenuation = calcAttenuation("
2339 << endl << " lights.light[i].const_attenuation,"
2340 << endl << " lights.light[i].linear_attenuation,"
2341 << endl << " lights.light[i].quadratic_attenuation,"
2342 << endl << " d);"
2343 << endl << ""
2344 << endl << " attenuation *= spotAttenuation(lights.light[i].cosSpotlightAngle, lights.light[i].spotExponent, l, s);"
2345 << endl << ""
2346 << endl << " return materials.material[j].emissive"
2347 << endl << " + attenuation * lights.light[i].Ia * materials.material[j].ambient"
2348 << endl << " + attenuation * lights.light[i].Id * materials.material[j].diffuse * n_dot_l"
2349 << endl << " + attenuation * lights.light[i].Is * materials.material[j].specular * (m+8)*0.0125 * pf;"
2350 << endl << "}"
2351 << endl << ""
2352 << endl << "void main()"
2353 << endl << "{"
2354 << endl << " //"
2355 << endl << " // normalize the eye space normal"
2356 << endl << " //"
2357 << endl << " int frontCond = -(1 - int(gl_FrontFacing)*2);"
2358 << endl << " vec3 N = frontCond * normalize(vNormalES);"
2359 << endl << ""
2360 << endl << " //"
2361 << endl << " // get the view vector and normalize it"
2362 << endl << " //"
2363 << endl << " vec3 V = normalize(cCameraPositionES - vPositionES);"
2364 << endl << ""
2365 << endl << " //"
2366 << endl << " // Integrate over all lights: Any unused light does not contribute and each light"
2367 << endl << " // contribute either from the directional light, the point light or the spot light."
2368 << endl << " //"
2369 << endl << " vec3 color = vec3(0.0, 0.0, 0.0);"
2370 << endl << ""
2371 << endl << " int num_lights = lights.light.length();"
2372 << endl << ""
2373 << endl << " for (int i = 0; i < num_lights; ++i)"
2374 << endl << " {"
2375 << endl << " switch (lights.light[i].type)"
2376 << endl << " {"
2377 << endl << " case POINT_LIGHT: color += pointLight(i, geom_state.material_index, N, V, vPositionES); break;"
2378 << endl << " case DIRECTIONAL_LIGHT: color += directionalLight(i, geom_state.material_index, N, V); break;"
2379 << endl << " case SPOT_LIGHT: color += spotLight(i, geom_state.material_index, N, V, vPositionES); break;"
2380 << endl << " }"
2381 << endl << " }"
2382 << endl << " vFragColor = vec4(color, materials.material[geom_state.material_index].opacity);"
2383 << endl << ""
2384 << endl << "}"
2385 << endl << ""
2386 << endl;
2388 return ost.str();