fixed: compile issue
[opensg.git] / Examples / Simple / multirangelight.cpp
blob435d6e42bf0136201f31ce53d7282b05e066b26f
1 // OpenSG Tutorial Example: MultiRangeLight
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 a simple light abstraction with only a single light
17 // color and one intensity value. Additionally, it provides a range attribute
18 // that models the attenuation behavior of the light. Of course the shader
19 // code's responsibilty is to make usage of the provided light data attrubutes,
20 // and the writer of the shader can implement whatever light model he likes
21 // on the given light buffer layout.
23 // The MultiPropertyUBOChunk and MultiPropertySSBOChunk do also provides means
24 // to conviently create shader buffer data. They are, however, not as
25 // specialized as the MultiLightChunk.
26 // They have a simple interface for the data layout preparation but allows only
27 // a restricted subset of layout structure that the std140 uniform buffer block
28 // repspectively the std430 shader storage buffer block specifications allows.
30 // In this example a MultiPropertySSBOChunk is used to model a material database
31 // with the simple basic material properties. The material database shader
32 // buffer is shared by all geometry that is rendered by the example.
34 // The MultiPropertyUBOChunk is used to provide geometry state data to the
35 // fragment shader. That is, each geometry gets its own chunk, but for the
36 // purpose of the example only the material index to be used for the particular
37 // geometry is added to chunk.
39 // Additionally, the example runs riot with boost random number generators.
40 // Hopefully, that does not distract the reader.
42 // Different aspects of the example can be manipulated at runtime like the
43 // number of lights and their range and intensity parameters as well as the
44 // number of geometries simulated and their material among many others.
46 // The examples uses a HDR2Stage core for managing the mapping of the
47 // accumulated intensities into the feasible region of the final screen
48 // render target. It does use mostly default settings for this stage.
50 // At last the example provides a bezier curve abstraction for generating
51 // the light and object pathes.
53 // See also:
54 // multirangelight.cpp
55 // multicinemalight.cpp
56 // uniformbufferobject_std140.cpp
57 // shaderstoragebufferobject_std430.cpp
58 // multipropertyubochunk_test.cpp
59 // multipropertyssbochunk_test.cpp
60 // tonemapping.cpp
63 #include <boost/functional/hash.hpp>
64 #include <boost/unordered_set.hpp>
65 #include <boost/foreach.hpp>
66 #include <boost/random.hpp>
67 #include <boost/tuple/tuple.hpp>
68 #include "boost/tuple/tuple_comparison.hpp"
70 #ifdef OSG_BUILD_ACTIVE
71 // Headers
72 #include <OSGGLUT.h>
73 #include <OSGConfig.h>
74 #include <OSGSimpleGeometry.h>
75 #include <OSGGLUTWindow.h>
76 #include <OSGSimpleSceneManager.h>
77 #include <OSGBaseFunctions.h>
78 #include <OSGTransform.h>
79 #include <OSGGroup.h>
81 // new headers:
82 #include <OSGGLEXT.h>
83 #include <OSGTime.h>
84 #include <OSGHDR2Stage.h>
85 #include <OSGInverseTransform.h>
86 #include <OSGShaderProgramChunk.h>
87 #include <OSGShaderProgram.h>
88 #include <OSGShaderVariableOSG.h>
89 #include <OSGChunkMaterial.h>
90 #include <OSGMaterialGroup.h>
91 #include <OSGMaterialChunkOverrideGroup.h>
92 #include <OSGMatrixUtility.h>
93 #include <OSGMultiLightChunk.h>
94 #include <OSGMultiPropertyUBOChunk.h>
95 #include <OSGMultiPropertySSBOChunk.h>
96 #include <OSGPolygonChunk.h>
97 #include <OSGDepthChunk.h>
98 #include <OSGShaderProgramVariableChunk.h>
99 #include <OSGBlendChunk.h>
100 #include <OSGPolygonChunk.h>
101 #include <OSGTwoSidedLightingChunk.h>
103 #else
104 // Headers
105 #include <OpenSG/OSGGLUT.h>
106 #include <OpenSG/OSGConfig.h>
107 #include <OpenSG/OSGSimpleGeometry.h>
108 #include <OpenSG/OSGGLUTWindow.h>
109 #include <OpenSG/OSGSimpleSceneManager.h>
110 #include <OpenSG/OSGBaseFunctions.h>
111 #include <OpenSG/OSGTransform.h>
112 #include <OpenSG/OSGGroup.h>
114 // new headers:
115 #include <OpenSG/OSGGLEXT.h>
116 #include <OpenSG/OSGTime.h>
117 #include <OpenSG/OSGHDR2Stage.h>
118 #include <OpenSG/OSGInverseTransform.h>
119 #include <OpenSG/OSGShaderProgramChunk.h>
120 #include <OpenSG/OSGShaderProgram.h>
121 #include <OpenSG/OSGShaderVariableOSG.h>
122 #include <OpenSG/OSGChunkMaterial.h>
123 #include <OpenSG/OSGMaterialGroup.h>
124 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
125 #include <OpenSG/OSGMatrixUtility.h>
126 #include <OpenSG/OSGMultiLightChunk.h>
127 #include <OpenSG/OSGMultiPropertyUBOChunk.h>
128 #include <OpenSG/OSGMultiPropertySSBOChunk.h>
129 #include <OpenSG/OSGPolygonChunk.h>
130 #include <OpenSG/OSGDepthChunk.h>
131 #include <OpenSG/OSGShaderProgramVariableChunk.h>
132 #include <OpenSG/OSGBlendChunk.h>
133 #include <OpenSG/OSGPolygonChunk.h>
134 #include <OpenSG/OSGTwoSidedLightingChunk.h>
135 #endif
137 // ============================================================================
139 // Part I: Declaration of the example scene and some helpers:
140 // - constants that governs the example
141 // - random number generators
142 // - smooth cubic Bezier spline curve
144 // ============================================================================
146 OSG::SimpleSceneManagerRefPtr mgr;
148 const OSG::Int32 num_geometries = 16;
149 const OSG::Int32 num_grid_boxes = 100;
150 const OSG::Int32 num_curve_knots = 40;
151 const OSG::Int32 num_passes = 4;
152 const std::size_t num_materials = 5000;
153 const OSG::Int32 max_num_lights = 1024;
154 const OSG::Real32 world_size = 10.f;
155 const OSG::Real32 box_factor = 1.5f;
157 OSG::Real32 simulation_delta = 0.0001f;
158 OSG::Real32 elapse_time_limit = 10.f;
160 const OSG::Real32 max_light_power = 10.f;
162 const OSG::Real32 rangeFactor = 1.05f;
163 const OSG::Real32 intensityFactor = 1.2f;
165 typedef boost::mt19937 RNGType;
166 RNGType rng(time(0));
168 boost::uniform_int<> box_dist(0, num_grid_boxes-1);
169 boost::variate_generator<RNGType, boost::uniform_int<> > box_idx_die(rng, box_dist);
171 boost::uniform_int<> die_dist(1, 6);
172 boost::variate_generator<RNGType, boost::uniform_int<> > classic_die(rng, die_dist);
174 boost::uniform_int<> geom_dist(0, 7);
175 boost::variate_generator<RNGType, boost::uniform_int<> > geom_idx_die(rng, geom_dist);
177 boost::uniform_01<float> unit_distribution;
178 boost::variate_generator< RNGType, boost::uniform_01<float> > unit_die(rng, unit_distribution);
180 boost::uniform_real<float> small_distribution(0.1f, 1.f);
181 boost::variate_generator< RNGType, boost::uniform_real<float> > small_die(rng, small_distribution);
183 boost::uniform_real<float> light_range_distribution(0.2f, 0.7f);
184 boost::variate_generator< RNGType, boost::uniform_real<float> > light_range_die(rng, light_range_distribution);
186 std::vector<OSG::Pnt3f> dice_knots(bool close_curve);
188 OSG::Vec3f dice_unit_vector()
190 OSG::Vec3f v;
192 while (v.length() < OSG::Eps)
193 v.setValues(
194 -1.f + 2.f * unit_die(),
195 -1.f + 2.f * unit_die(),
196 -1.f + 2.f * unit_die());
198 v.normalize();
200 return v;
203 class CubicBezierCurve
205 public:
206 CubicBezierCurve(const OSG::Pnt3f& p0, const OSG::Pnt3f& p1, const OSG::Pnt3f& p2, const OSG::Pnt3f& p3);
207 CubicBezierCurve(const CubicBezierCurve& rhs);
209 CubicBezierCurve& operator=(const CubicBezierCurve& rhs);
211 OSG::Pnt3f operator() (OSG::Real32 t) const;
212 OSG::Vec3f tangent (OSG::Real32 t) const;
213 OSG::Vec3f normal (OSG::Real32 t) const;
214 OSG::Vec3f binormal (OSG::Real32 t) const;
215 OSG::Matrix frame (OSG::Real32 t, bool position_only) const;
216 OSG::Real32 length (OSG::UInt32 numSeg = 10) const;
218 private:
219 OSG::Vec3f fst_derivative (OSG::Real32 t) const;
220 OSG::Vec3f sec_derivative (OSG::Real32 t) const;
221 OSG::Vec3f thr_devivative (OSG::Real32 t) const;
223 private:
224 OSG::Pnt3f p[4];
227 class SmoothCubicBezierSpline
229 public:
230 typedef std::vector<OSG::Pnt3f> points_t;
232 SmoothCubicBezierSpline(const points_t& knots);
233 SmoothCubicBezierSpline(const SmoothCubicBezierSpline& rhs);
235 SmoothCubicBezierSpline& operator=(const SmoothCubicBezierSpline& rhs);
237 OSG::Pnt3f operator() (OSG::Real32 t) const;
238 OSG::Vec3f tangent (OSG::Real32 t) const;
239 OSG::Vec3f normal (OSG::Real32 t) const;
240 OSG::Vec3f binormal (OSG::Real32 t) const;
241 OSG::Matrix frame (OSG::Real32 t, bool position_only = false) const;
242 OSG::Real32 length (OSG::UInt32 numSeg = 10) const;
244 private:
245 void calc_ctrl_pnts (points_t& p1, points_t& p2) const;
246 std::size_t index (OSG::Real32 t) const;
247 OSG::Real32 t_ (OSG::Real32 t, std::size_t idx) const;
249 private:
250 std::vector<OSG::Pnt3f> knots;
251 std::vector<OSG::Real32> intervals;
252 std::vector<CubicBezierCurve> curves;
255 // ============================================================================
257 // Part II: Declaration of
258 // - struct Light and type VecLightsT,
259 // - struct Material and type VecMaterialsT,
260 // - struct GeomState
261 // and corresponding initialization routines.
263 // ============================================================================
266 // simple light data structure
268 struct Light
270 enum Type
272 directional_light = OSG::MultiLight::DIRECTIONAL_LIGHT,
273 point_light = OSG::MultiLight::POINT_LIGHT,
274 spot_light = OSG::MultiLight::SPOT_LIGHT,
275 cinema_light = OSG::MultiLight::CINEMA_LIGHT
278 OSG::MultiLight::Type getType() const { return static_cast<OSG::MultiLight::Type>(type); }
280 explicit Light(Type e);
281 ~Light();
283 static Light create_light(Type e, OSG::UInt32 material_idx);
285 OSG::Pnt3f position; // light position in object space for point and spot lights
286 OSG::Vec3f direction; // direction of directional light or spot light in object space
287 OSG::Color3f color; // the color of the light
288 OSG::Real32 intensity; // the intensity of the light
289 OSG::Real32 range; // the range of the light, i.e. the light sphere radius of influence
290 OSG::Real32 spotlightAngle; // the cone angle in case of a spot light
291 OSG::Int32 type; // the type of light: see OSG::MultiLight::LightType
292 bool enabled; // on/off state of the light
294 OSG::NodeRefPtr beacon; // the light beacon that if defined evaluates the position parameter
295 OSG::TransformRefPtr transform; // the beacons transform core
296 SmoothCubicBezierSpline curve; // the path that the light will follow
299 typedef std::vector<Light> VecLightsT; // multiple lights
300 VecLightsT lights; // the lights of the scene
302 Light::Light(Type e)
303 : position(0.f, 0.f, 0.f)
304 , direction(0.f, 0.f, 1.f)
305 , color(1.f,1.f,1.f)
306 , intensity(1.f)
307 , range(1.f)
308 , spotlightAngle(20.f)
309 , type(e)
310 , enabled(true)
311 , beacon(NULL)
312 , transform(NULL)
313 , curve(dice_knots(true))
316 Light::~Light()
318 beacon = NULL;
319 transform = NULL;
323 // Simple material data structure
325 struct Material
327 Material()
328 : ambient (0.f, 0.f, 0.f)
329 , diffuse (0.f, 0.f, 0.f)
330 , specular(0.f, 0.f, 0.f)
331 , emissive(0.f, 0.f, 0.f)
332 , opacity(1.f)
333 , shininess(100.f)
336 OSG::Color3f ambient;
337 OSG::Color3f diffuse;
338 OSG::Color3f specular;
339 OSG::Color3f emissive;
341 OSG::Real32 opacity;
342 OSG::Real32 shininess;
344 static OSG::UInt32 ambient_id;
345 static OSG::UInt32 diffuse_id;
346 static OSG::UInt32 specular_id;
347 static OSG::UInt32 emissive_id;
348 static OSG::UInt32 opacity_id;
349 static OSG::UInt32 shininess_id;
352 OSG::UInt32 Material:: ambient_id = 0;
353 OSG::UInt32 Material:: diffuse_id = 0;
354 OSG::UInt32 Material:: specular_id = 0;
355 OSG::UInt32 Material:: emissive_id = 0;
356 OSG::UInt32 Material:: opacity_id = 0;
357 OSG::UInt32 Material::shininess_id = 0;
359 typedef std::vector<Material> VecMaterialsT; // multiple materials
361 VecMaterialsT initialize_materials(std::size_t num) // helper to create materials
363 OSG_ASSERT(num > max_num_lights + 1);
365 VecMaterialsT mat(num);
367 for (std::size_t i = max_num_lights+1; i < num; ++i)
369 mat[i].ambient = OSG::Color3f(0.001f, 0.001f, 0.001f);
370 mat[i].diffuse.setRandom();
371 mat[i].specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
372 mat[i].emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
373 mat[i].opacity = 1.f;
374 mat[i].shininess = 320.f * small_die();
376 //int r = classic_die();
377 //if (r <= 3)
378 // mat[i].opacity = small_die();
382 // special grey material for box
384 mat[0].ambient = OSG::Color3f(0.001f, 0.001f, 0.001f);
385 mat[0].diffuse = OSG::Color3f(0.7f, 0.7f, 0.7f);
386 mat[0].specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
387 mat[0].emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
388 mat[0].opacity = 1.f;
389 mat[0].shininess = 100.f;
391 return mat;
394 VecMaterialsT materials = initialize_materials(num_materials); // the material database
397 // we reserve the first max_num_lights + 1 materials for the light simulation and
398 // the grey box.
400 boost::uniform_int<OSG::UInt32> material_dist(max_num_lights+1, num_materials-1);
401 boost::variate_generator<RNGType, boost::uniform_int<OSG::UInt32> > material_idx_die(rng, material_dist);
404 // Simple geometry state data structure
406 struct GeomState
408 GeomState()
409 : material_index(0)
412 OSG::UInt32 material_index;
414 static OSG::UInt32 material_index_id;
417 OSG::UInt32 GeomState::material_index_id = 0;
419 // ============================================================================
421 // Part III: Creation and update of the light state
423 // ============================================================================
425 OSG::MultiLightChunkTransitPtr create_light_state(const VecLightsT& vLights)
427 OSG::MultiLightChunkRefPtr lightChunk = OSG::MultiLightChunk::create();
429 lightChunk->setUsage(GL_DYNAMIC_DRAW);
430 lightChunk->setLayoutType(OSG::MultiLight::SIMPLE_LAYOUT);
432 BOOST_FOREACH(const Light& light, vLights)
434 OSG::UInt32 idx = lightChunk->addLight(light.getType());
436 lightChunk->setPosition (idx, light.position);
437 lightChunk->setDirection (idx, light.direction);
438 lightChunk->setColor (idx, light.color);
439 lightChunk->setIntensity (idx, light.intensity);
440 lightChunk->setRange (idx, light.range);
441 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
442 lightChunk->setEnabled (idx, light.enabled);
443 lightChunk->setType (idx, light.getType());
444 lightChunk->setBeacon (idx, light.beacon);
447 return OSG::MultiLightChunkTransitPtr(lightChunk);
450 void update_light_state(OSG::MultiLightChunk* lightChunk, const VecLightsT& vLights)
452 if (lightChunk)
454 if (lightChunk->numLights() != vLights.size())
456 lightChunk->clearLights();
458 BOOST_FOREACH(const Light& light, vLights)
460 OSG::UInt32 idx = lightChunk->addLight(light.getType());
462 lightChunk->setPosition (idx, light.position);
463 lightChunk->setDirection (idx, light.direction);
464 lightChunk->setColor (idx, light.color);
465 lightChunk->setIntensity (idx, light.intensity);
466 lightChunk->setRange (idx, light.range);
467 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
468 lightChunk->setEnabled (idx, light.enabled);
469 lightChunk->setType (idx, light.getType());
470 lightChunk->setBeacon (idx, light.beacon);
473 else
475 for (OSG::UInt32 idx = 0; idx < vLights.size(); ++idx)
477 const Light& light = vLights[idx];
479 lightChunk->setPosition (idx, light.position);
480 lightChunk->setDirection (idx, light.direction);
481 lightChunk->setColor (idx, light.color);
482 lightChunk->setIntensity (idx, light.intensity);
483 lightChunk->setRange (idx, light.range);
484 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
485 lightChunk->setType (idx, light.getType());
486 lightChunk->setEnabled (idx, light.enabled);
487 lightChunk->setBeacon (idx, light.beacon);
493 // ============================================================================
495 // Part IV: Some routines for handling of the memory buffer and the the
496 // creation on the MultiPropertySSBOChunk objects:
498 // i) create_material_database_state,
499 // update_material_database_state
501 // ii) create_geometry_material_state,
502 // update_geometry_material_state
504 // ============================================================================
507 // i) the material shader storage buffer object
509 OSG::MultiPropertySSBOChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
511 OSG::MultiPropertySSBOChunkRefPtr materialChunk = OSG::MultiPropertySSBOChunk::create();
513 OSG::UInt32 vec3_id, float_id;
515 vec3_id = materialChunk->addMember(OSG::MultiPropertySSBOChunk:: VEC3_T, 4);
516 float_id = materialChunk->addMember(OSG::MultiPropertySSBOChunk::FLOAT_T, 2);
518 materialChunk->setUsage(GL_STATIC_DRAW);
520 Material:: ambient_id = vec3_id++;
521 Material:: diffuse_id = vec3_id++;
522 Material:: specular_id = vec3_id++;
523 Material:: emissive_id = vec3_id;
525 Material:: opacity_id = float_id++;
526 Material::shininess_id = float_id;
528 BOOST_FOREACH(const Material& mat, vMaterials)
530 OSG::UInt32 idx = materialChunk->addProperty();
532 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
533 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
534 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
535 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
537 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
538 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
541 return OSG::MultiPropertySSBOChunkTransitPtr(materialChunk);
544 void update_material_database_state(OSG::MultiPropertySSBOChunk* materialChunk, const VecMaterialsT& vMaterials)
546 if (materialChunk)
548 if (materialChunk->getNumProperties() != vMaterials.size())
550 materialChunk->clearProperties();
552 BOOST_FOREACH(const Material& mat, vMaterials)
554 OSG::UInt32 idx = materialChunk->addProperty();
556 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
557 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
558 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
559 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
561 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
562 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
565 else
567 for (OSG::UInt32 idx = 0; idx < vMaterials.size(); ++idx)
569 const Material& mat = vMaterials[idx];
571 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
572 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
573 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
574 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
576 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
577 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
584 // ii) the geomertry shader storage buffer object
586 OSG::MultiPropertyUBOChunkTransitPtr create_geometry_material_state(const GeomState& geom_state)
588 OSG::MultiPropertyUBOChunkRefPtr geomStateChunk = OSG::MultiPropertyUBOChunk::create();
590 GeomState::material_index_id = geomStateChunk->addMember(OSG::MultiPropertyUBOChunk::UINT_T, 1);
591 geomStateChunk->setUsage(GL_DYNAMIC_DRAW);
593 OSG::UInt32 idx = geomStateChunk->addProperty();
594 geomStateChunk->setUIntProperty(idx, GeomState::material_index_id, geom_state.material_index);
596 return OSG::MultiPropertyUBOChunkTransitPtr(geomStateChunk);
599 void update_geometry_material_state(OSG::MultiPropertyUBOChunk* geomStateChunk, const GeomState& geom_state)
601 if (geomStateChunk)
603 if (geomStateChunk->getNumProperties() != 1)
605 geomStateChunk->clearProperties();
607 OSG::UInt32 idx = geomStateChunk->addProperty();
608 geomStateChunk->setUIntProperty(idx, GeomState::material_index_id, geom_state.material_index);
610 else
612 geomStateChunk->setUIntProperty( 0, GeomState::material_index_id, geom_state.material_index);
617 // ============================================================================
619 // Part V: The application finally starts here
621 // ============================================================================
624 // vertex shader program.
626 std::string get_vp_program();
629 // fragment shader program for bump mapping in surface local coordinates
631 std::string get_fp_program();
634 // The scene
636 OSG::NodeRefPtr scene_node = NULL;
639 // A HDR stage core
641 OSG::HDR2StageRefPtr hdr_stage = NULL;
642 OSG::NodeRefPtr hdr_node = NULL;
645 // The material database for all visible geometry: objects, lights, stage box
647 OSG::MultiPropertySSBOChunkRefPtr ssbo_material_database = NULL;
650 // The mulit light chunk
652 OSG::MultiLightChunkRefPtr multi_light_chunk = NULL;
655 // The block binding point for the geom state
657 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = NULL;
660 // Shader Storage buffer objects corresponding to transient shader blocks
662 std::vector<OSG::MultiPropertyUBOChunkRefPtr> ubo_geom_states;
665 // A separate transformation for each object and a spline for the trajectory
667 std::vector<OSG::NodeRefPtr> geom_nodes;
668 std::vector<OSG::TransformRefPtr> geom_trafos;
669 std::vector<SmoothCubicBezierSpline> geom_curves;
672 // HDR stage ...
674 void setup_hdr_stage()
676 if (hdr_stage)
678 hdr_stage->setApplyGamma (true);
679 hdr_stage->setAccurateGamma (true);
681 hdr_stage->setAdjustLuminance (false);
683 hdr_stage->setPerformBloom (false);
684 hdr_stage->setBloomBackground (false);
686 hdr_stage->setForceBackground (true);
687 hdr_stage->setUse_ITU_R_BT_709 (true);
688 hdr_stage->setMipmapLevel (-1);
690 hdr_stage->setTarget (OSG::HDR2Stage::COMPOSITE_TEXTURE);
691 hdr_stage->setCarryDepth (true);
693 hdr_stage->setColorBufferInternalFormat (GL_RGBA16F);
694 hdr_stage->setColorBufferPixelFormat (GL_RGBA);
695 hdr_stage->setColorBufferType (GL_FLOAT);
697 hdr_stage->setDepthBufferInternalFormat (GL_DEPTH24_STENCIL8);
698 hdr_stage->setDepthBufferPixelFormat (GL_DEPTH_STENCIL);
699 hdr_stage->setDepthBufferType (GL_UNSIGNED_INT_24_8);
701 hdr_stage->setLumBufferInternalFormat (GL_R32F);
702 hdr_stage->setLumBufferPixelFormat (GL_RED);
703 hdr_stage->setLumBufferType (GL_FLOAT);
705 hdr_stage->setImageBufferInternalFormat (GL_RGB16F);
706 hdr_stage->setImageBufferPixelFormat (GL_RGB);
707 hdr_stage->setImageBufferType (GL_FLOAT);
709 hdr_stage->setNumSamples (0);
711 hdr_stage->setBloomThreshold (2.0f);
712 hdr_stage->setBloomMagnitude (0.0f);
713 hdr_stage->setToneMappingMode (OSG::HDR2Stage::REINHARD_TONE_MAPPING);
714 hdr_stage->setExposure (0.0f);
715 hdr_stage->setKeyValue (0.18f);
716 hdr_stage->setAutoExposureMode (OSG::HDR2Stage::MANUAL);
717 hdr_stage->setWhiteLevel (5.0f);
718 hdr_stage->setFilmicShoulderStrenght (0.15f);
719 hdr_stage->setFilmicLinearStrength (0.5f);
720 hdr_stage->setFilmicLinearAngle (0.1f);
721 hdr_stage->setFilmicToeStrength (0.2f);
722 hdr_stage->setFilmicToeNumerator (0.02f);
723 hdr_stage->setFilmicToeDenominator (0.3f);
724 hdr_stage->setFilmicLinearWhite (11.2f);
725 hdr_stage->setSaturation (1.0f);
726 hdr_stage->setDragoBias (0.85f);
727 hdr_stage->setTau (1.25f);
728 hdr_stage->setNumTaps (4);
729 hdr_stage->setBlurGaussSigma (0.8f);
730 hdr_stage->setUseLinChromCorrection (true);
734 void removeHDRStage()
736 OSG::GroupRefPtr group = OSG::Group::create();
737 hdr_node->setCore(group);
739 hdr_stage = NULL;
742 void createHDRStage()
744 if (!hdr_stage)
746 hdr_stage = OSG::HDR2Stage::create();
747 setup_hdr_stage();
750 if (hdr_node)
751 hdr_node->setCore(hdr_stage);
755 // Lights...
757 void deinitialize_lights()
759 BOOST_FOREACH(const Light& light, lights)
761 scene_node->subChild(light.beacon);
764 lights.clear();
767 void initialize_lights(OSG::UInt32 num) // helper to create lights
769 deinitialize_lights();
771 for (OSG::UInt32 i = 0; i < num; ++i)
774 int n = classic_die();
775 Light::Type type;
776 if (n <= 3)
777 type = Light::point_light;
778 else
779 type = Light::spot_light;
781 lights.push_back(Light::create_light(type, i+1));
782 scene_node->addChild(lights[i].beacon);
786 Light Light::create_light(
787 Type e, // type of the light
788 OSG::UInt32 material_idx) // index in to the material storage for light animation
790 Light l(e);
792 l.beacon = OSG::makeCoredNode<OSG::Transform>(&l.transform);
793 OSG::Matrix m;
795 OSG::Real32 L = box_factor * world_size;
797 l.direction = dice_unit_vector();
799 l.color.setRandom();
800 l.intensity = max_light_power * small_die();
801 l.range = L * light_range_die();
803 Material mat;
804 mat.emissive = l.color;
805 materials[material_idx] = mat;
807 switch (e)
809 case point_light:
811 OSG::GeometryRefPtr geometry = OSG::makeSphereGeo(3, 0.1f);
812 OSG::NodeRefPtr node = OSG::makeNodeFor(geometry);
814 GeomState geom; geom.material_index = material_idx; // material index used for light animiation
815 OSG::ChunkMaterialRefPtr geom_state = OSG::ChunkMaterial::create();
816 OSG::MultiPropertyUBOChunkRefPtr ubo_geom_state = create_geometry_material_state(geom);
817 geom_state->addChunk(ubo_geom_state, 3); // buffer binding point 3
818 geom_state->addChunk(shader_var_chunk); // block binding point
820 geometry->setMaterial(geom_state);
822 l.beacon->addChild(node);
824 break;
826 case directional_light:
829 break;
831 case spot_light:
833 l.spotlightAngle = 90.f * small_die();
835 GeomState geom; geom.material_index = material_idx; // material index used for light animiation
836 OSG::ChunkMaterialRefPtr geom_state = OSG::ChunkMaterial::create();
837 OSG::MultiPropertyUBOChunkRefPtr ubo_geom_state = create_geometry_material_state(geom);
838 geom_state->addChunk(ubo_geom_state, 3); // buffer binding point 3
839 geom_state->addChunk(shader_var_chunk); // block binding point
841 OSG::Real32 r = 0.1f;
842 OSG::Real32 h = r / OSG::osgTan(OSG::osgDegree2Rad(l.spotlightAngle));
843 OSG::GeometryRefPtr geometry = OSG::makeConeGeo(h, r, 24, true, true);
844 geometry->setMaterial(geom_state);
846 OSG::TransformRefPtr cone_trans = OSG::Transform::create();
847 OSG::Matrix spot_mat;
848 bool result = OSG::MatrixLookAt(spot_mat, l.direction, OSG::Pnt3f(0,0,0), OSG::Vec3f(0,1,0));
849 if (result)
850 OSG::MatrixLookAt(spot_mat, l.direction, OSG::Pnt3f(0,0,0), OSG::Vec3f(1,0,0));
851 cone_trans->setMatrix(spot_mat);
853 OSG::Real32 ang = -90.f;
854 OSG::Vec3f rotVec(1,0,0);
856 OSG::TransformRefPtr rot_trans = OSG::Transform::create();
857 OSG::Matrix rot_mat;
858 rot_mat.setRotate(OSG::Quaternion(rotVec, OSG::osgDegree2Rad(ang)));
859 rot_trans->setMatrix(rot_mat);
861 OSG::NodeRefPtr cone_trans_node = OSG::makeNodeFor(cone_trans);
862 OSG::NodeRefPtr rot_trans_node = OSG::makeNodeFor(rot_trans);
863 OSG::NodeRefPtr cone_node = OSG::makeNodeFor(geometry);
865 l.beacon->addChild(cone_trans_node);
867 cone_trans_node->addChild(rot_trans_node);
868 rot_trans_node->addChild(cone_node);
870 //OSG::GeometryRefPtr geometry_test = OSG::makeCylinderGeo(30, .01f, 24, true, true, true );
871 //geometry_test->setMaterial(geom_state);
873 //OSG::TransformRefPtr test_trans = OSG::Transform::create();
874 //OSG::Matrix test_mat;
875 //test_mat.setTranslate(OSG::Vec3f(0,-15,0));
876 //test_trans->setMatrix(test_mat);
878 //OSG::NodeRefPtr test_rot_trans_node = OSG::makeNodeFor(rot_trans);
879 //OSG::NodeRefPtr test_trans_node = OSG::makeNodeFor(test_trans);
880 //OSG::NodeRefPtr test_node = OSG::makeNodeFor(geometry_test);
881 //cone_trans_node->addChild(test_rot_trans_node);
882 //test_rot_trans_node->addChild(test_trans_node);
883 //test_trans_node->addChild(test_node);
885 break;
887 default:
888 break;
891 return l;
894 OSG::NodeTransitPtr createBox()
896 OSG::NodeRefPtr box_root = OSG::makeCoredNode<OSG::Group>();
898 OSG::Real32 L = box_factor * world_size;
899 OSG::GeometryRefPtr box_plane = OSG::makePlaneGeo(2.f*L, 2.f*L, 128, 128);
901 OSG::NodeRefPtr box_bottom = OSG::makeNodeFor(box_plane);
902 OSG::NodeRefPtr box_left = OSG::makeNodeFor(box_plane);
903 OSG::NodeRefPtr box_right = OSG::makeNodeFor(box_plane);
904 OSG::NodeRefPtr box_far = OSG::makeNodeFor(box_plane);
906 OSG::TransformRefPtr box_bottom_trans = OSG::Transform::create();
907 OSG::TransformRefPtr box_left_trans = OSG::Transform::create();
908 OSG::TransformRefPtr box_right_trans = OSG::Transform::create();
909 OSG::TransformRefPtr box_far_trans = OSG::Transform::create();
911 OSG::Matrix mat_bottom, mat_left, mat_right, mat_far;
913 mat_bottom.setTransform(OSG::Vec3f(0.f, -L, 0.f), OSG::Quaternion( OSG::Vec3f(1, 0, 0), OSG::osgDegree2Rad(270.f)));
914 mat_left .setTransform(OSG::Vec3f( -L, 0.f, 0.f), OSG::Quaternion( OSG::Vec3f(0, 1, 0), OSG::osgDegree2Rad(90.f)));
915 mat_right .setTransform(OSG::Vec3f( L, 0.f, 0.f), OSG::Quaternion( OSG::Vec3f(0, 1, 0), OSG::osgDegree2Rad(270.f)));
916 mat_far .setTransform(OSG::Vec3f(0.f, 0.f, -L), OSG::Quaternion( OSG::Vec3f(0, 0, 1), OSG::osgDegree2Rad( 0.f)));
918 box_bottom_trans ->setMatrix(mat_bottom);
919 box_left_trans ->setMatrix(mat_left);
920 box_right_trans ->setMatrix(mat_right);
921 box_far_trans ->setMatrix(mat_far);
923 OSG::NodeRefPtr box_bottom_trans_node = OSG::makeNodeFor(box_bottom_trans);
924 OSG::NodeRefPtr box_left_trans_node = OSG::makeNodeFor(box_left_trans);
925 OSG::NodeRefPtr box_right_trans_node = OSG::makeNodeFor(box_right_trans);
926 OSG::NodeRefPtr box_far_trans_node = OSG::makeNodeFor(box_far_trans);
928 box_bottom_trans_node ->addChild(box_bottom);
929 box_left_trans_node ->addChild(box_left);
930 box_right_trans_node ->addChild(box_right);
931 box_far_trans_node ->addChild(box_far);
933 box_root->addChild(box_bottom_trans_node);
934 box_root->addChild(box_left_trans_node);
935 box_root->addChild(box_right_trans_node);
936 box_root->addChild(box_far_trans_node);
938 GeomState geom; geom.material_index = 0; // grey box material index
939 OSG::ChunkMaterialRefPtr geom_state = OSG::ChunkMaterial::create();
940 OSG::MultiPropertyUBOChunkRefPtr ubo_geom_state = create_geometry_material_state(geom);
941 geom_state->addChunk(ubo_geom_state, 3); // buffer binding point 3
942 geom_state->addChunk(shader_var_chunk); // block binding point
944 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
945 polygonChunk->setFrontMode(GL_SMOOTH);
946 polygonChunk->setBackMode(GL_SMOOTH);
947 polygonChunk->setOffsetFactor(1.f);
948 polygonChunk->setOffsetBias(1.f);
949 polygonChunk->setOffsetFill(true);
950 polygonChunk->setCullFace(GL_NONE);
951 geom_state->addChunk(polygonChunk);
952 geom_state->setTransparencyMode(OSG::Material::TransparencyForceOpaque);
954 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk = OSG::TwoSidedLightingChunk::create();
955 geom_state->addChunk(twoSidedLightingChunk);
957 box_plane->setMaterial(geom_state);
959 return OSG::NodeTransitPtr(box_root);
962 OSG::NodeTransitPtr createGeometry()
964 int idx = geom_idx_die();
966 OSG::GeometryRefPtr geometry;
968 switch (idx)
970 case 0: // cone
971 geometry = OSG::makeConeGeo(3.f * small_die(), 1.f * small_die(), 24, true, true);
972 break;
973 case 1: // box
974 geometry = OSG::makeBoxGeo(3.f * small_die(), 3.f * small_die(), 3.f * small_die(), 1, 1, 1);
975 break;
976 case 2: // cylinder
977 geometry = OSG::makeCylinderGeo(3.f * small_die(), .3f, 24, true, true, true );
978 break;
979 case 3: // sphere
980 geometry = OSG::makeSphereGeo(6, 3.f * small_die());
981 break;
982 case 4: // torus
983 geometry = OSG::makeTorusGeo(0.6f * small_die(), 2.f * small_die(), 24, 36);
984 break;
985 case 5: // ellipsoide
986 geometry = OSG::makeLatLongEllipsoidGeo(24, 36, 2.f * small_die(), 1.f * small_die());
987 break;
988 case 6: // frustum
989 geometry = OSG::makeConicalFrustumGeo(2.f * small_die(), 2.f * small_die(), 2.f * small_die(), 6, true, true, true);
990 break;
991 case 7: // teapot
992 geometry = OSG::makeTeapotGeo(24, 1.f * small_die());
993 break;
996 OSG::NodeRefPtr geomNode = OSG::makeNodeFor(geometry);
998 OSG::TransformRefPtr trafoCore = OSG::Transform::create();
999 OSG::NodeRefPtr transNode = OSG::makeNodeFor(trafoCore);
1000 transNode->addChild(geomNode);
1002 GeomState geom; geom.material_index = material_idx_die();
1003 OSG::ChunkMaterialRefPtr geom_state = OSG::ChunkMaterial::create();
1004 OSG::MultiPropertyUBOChunkRefPtr ubo_geom_state = create_geometry_material_state(geom);
1005 geom_state->addChunk(ubo_geom_state, 3); // buffer binding point 3
1006 geom_state->addChunk(shader_var_chunk); // block binding point
1008 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
1009 polygonChunk->setFrontMode(GL_SMOOTH);
1010 polygonChunk->setBackMode(GL_SMOOTH);
1011 polygonChunk->setOffsetFactor(1.f);
1012 polygonChunk->setOffsetBias(1.f);
1013 polygonChunk->setOffsetFill(true);
1015 OSG::Real32 opacity = materials[geom.material_index].opacity;
1016 if (opacity < 1.f)
1018 polygonChunk->setCullFace(GL_NONE);
1020 OSG::BlendChunkRefPtr blendChunk = OSG::BlendChunk::create();
1021 blendChunk->setSrcFactor (GL_SRC_ALPHA);
1022 blendChunk->setDestFactor(GL_ONE_MINUS_SRC_ALPHA);
1023 geom_state->addChunk(blendChunk);
1024 geom_state->setTransparencyMode(OSG::Material::TransparencyForceTransparent);
1026 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk = OSG::TwoSidedLightingChunk::create();
1027 geom_state->addChunk(twoSidedLightingChunk);
1029 } else {
1030 polygonChunk->setCullFace(GL_BACK);
1031 geom_state->setTransparencyMode(OSG::Material::TransparencyForceOpaque);
1034 geom_state->addChunk(polygonChunk);
1036 geometry->setMaterial(geom_state);
1038 geom_nodes.push_back(transNode);
1039 geom_trafos.push_back(trafoCore);
1040 ubo_geom_states.push_back(ubo_geom_state);
1042 geom_curves.push_back(SmoothCubicBezierSpline(dice_knots(true)));
1044 return OSG::NodeTransitPtr(transNode);
1048 // forward declaration so we can have the interesting stuff upfront
1050 int setupGLUT (int *argc, char *argv[]);
1051 void print_help();
1052 void releaseGLUT();
1055 // Initialize GLUT & OpenSG and set up the scene
1057 int main(int argc, char **argv)
1059 // OSG init
1060 OSG::osgInit(argc,argv);
1062 // GLUT init
1063 int winid = setupGLUT(&argc, argv);
1065 print_help();
1067 // open a new scope, because the pointers below should go out of scope
1068 // before entering glutMainLoop.
1069 // Otherwise OpenSG will complain about objects being alive after shutdown.
1071 // the connection between GLUT and OpenSG
1072 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
1073 gwin->setGlutId(winid);
1074 gwin->init();
1076 // create the SimpleSceneManager helper
1077 mgr = OSG::SimpleSceneManager::create();
1078 mgr->setWindow(gwin);
1080 // The scene
1081 hdr_node = OSG::makeCoredNode<OSG::Group>();
1082 scene_node = OSG::makeCoredNode<OSG::Group>();
1084 hdr_node->addChild(scene_node);
1086 mgr->setRoot(hdr_node);
1088 createHDRStage();
1091 // create the shader program
1093 OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
1094 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
1095 OSG::ShaderProgramRefPtr fragShader = OSG::ShaderProgram::createFragmentShader();
1097 vertShader->setProgram(get_vp_program());
1098 fragShader->setProgram(get_fp_program());
1100 fragShader->addOSGVariable("OSGViewMatrix");
1103 // binding the shader storage block to a buffer binding point can be performed
1104 // either by calling the shaders's addShaderStorageBlock method or by
1105 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
1106 // In the following we use both variants for illustration.
1108 fragShader->addShaderStorageBlock("Materials", 1); // block binding point
1109 fragShader->addShaderStorageBlock("Lights", 2); // block binding point
1112 // The following is replaced by adding ShaderProgramVariableChunk objects
1113 // to the chunk material. See below...
1115 // fragShader->addShaderStorageBlock("GeomState", 3); // block binding point
1117 prog_chunk->addShader(vertShader);
1118 prog_chunk->addShader(fragShader);
1121 // The block binding is added to each ChunkMaterial in order to provide the state
1122 // shader uniform block for the geometery shown in the scene
1124 shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
1125 shader_var_chunk->addUniformBlock("GeomState", 3); // block binding point
1128 // Because we animate the lights by simple geometry, the lights initialization must be happens
1129 // after the creation of the 'shader_var_chunk' block binding point.
1130 // Additionally, it must happens before we call 'create_light_state', since here we do need the
1131 // already defined lights.
1133 initialize_lights(1);
1136 // create shader storage buffer objects and corresponding materials
1138 ssbo_material_database = create_material_database_state(materials);
1139 multi_light_chunk = create_light_state(lights);
1141 //multi_light_chunk->setEyeSpace(true);
1143 OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
1144 polygon_chunk->setFrontMode(GL_FILL);
1145 polygon_chunk->setBackMode(GL_FILL);
1146 polygon_chunk->setCullFace(GL_NONE);
1148 OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
1149 depth_chunk->setEnable(true);
1151 OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
1152 prog_state->addChunk(ssbo_material_database, 1); // buffer binding point 1
1153 prog_state->addChunk(multi_light_chunk, 2); // buffer binding point 2
1154 prog_state->addChunk(prog_chunk);
1155 prog_state->addChunk(polygon_chunk);
1156 prog_state->addChunk(depth_chunk);
1158 scene_node->addChild(createBox());
1160 for (OSG::Int32 i = 0; i < num_geometries; ++i)
1161 scene_node->addChild(createGeometry());
1163 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
1164 mgrp->setMaterial(prog_state);
1165 scene_node->setCore(mgrp);
1167 OSG::commitChanges();
1169 // show the whole scene
1170 mgr->showAll();
1173 // GLUT main loop
1174 glutMainLoop();
1176 return 0;
1180 // GLUT callback functions
1184 // redraw the window
1186 OSG::TimeStamp time_stamp = 0;
1187 OSG::Real32 simulation_param = 0.f;
1188 bool simulate_geometry = true;
1189 bool simulate_lights = true;
1191 void display(void)
1193 // create the matrix
1194 OSG::Matrix m;
1196 if (time_stamp == 0)
1197 time_stamp = OSG::getTimeStamp();
1199 OSG::Time elapsed = OSG::getTimeStampMsecs(OSG::getTimeStamp() - time_stamp);
1201 if (elapsed > elapse_time_limit)
1203 simulation_param += simulation_delta;
1204 if (simulation_param >= 1.f)
1205 simulation_param = 0.f;
1207 if (simulate_geometry)
1209 std::size_t numCurves = geom_curves.size();
1211 OSG_ASSERT(numCurves == geom_trafos.size());
1213 for (std::size_t i = 0; i < numCurves; ++i)
1215 m = geom_curves[i].frame(simulation_param);
1216 geom_trafos[i]->setMatrix(m);
1220 if (simulate_lights)
1222 BOOST_FOREACH(Light& light, lights)
1224 m = light.curve.frame(simulation_param, true);
1225 light.transform->setMatrix(m);
1230 time_stamp = OSG::getTimeStamp();
1233 OSG::commitChanges();
1235 mgr->redraw();
1239 // react to size changes
1241 void reshape(int w, int h)
1243 mgr->resize(w, h);
1244 glutPostRedisplay();
1248 // react to mouse button presses
1250 void mouse(int button, int state, int x, int y)
1252 if (state)
1253 mgr->mouseButtonRelease(button, x, y);
1254 else
1255 mgr->mouseButtonPress(button, x, y);
1257 glutPostRedisplay();
1261 // react to mouse motions with pressed buttons
1263 void motion(int x, int y)
1265 mgr->mouseMove(x, y);
1266 glutPostRedisplay();
1270 // react to keys
1272 void keyboard(unsigned char k, int x, int y)
1274 switch(k)
1276 case 27: // ESC
1278 // clean up global variables
1279 mgr = NULL;
1281 hdr_stage = NULL;
1282 hdr_node = NULL;
1284 scene_node = NULL;
1286 multi_light_chunk = NULL;
1287 shader_var_chunk = NULL;
1289 geom_nodes.clear();
1290 geom_trafos.clear();
1291 geom_curves.clear();
1293 ubo_geom_states.clear();
1295 materials.clear();
1296 lights.clear();
1298 releaseGLUT();
1300 OSG::osgExit();
1301 exit(0);
1303 break;
1305 case 32: // Space
1307 simulate_geometry = !simulate_geometry;
1309 break;
1311 case 'l':
1313 simulate_lights = !simulate_lights;
1315 break;
1317 case 'o':
1319 elapse_time_limit *= 2.f;
1321 break;
1323 case 'O':
1325 elapse_time_limit /= 2.f;
1327 break;
1329 case 'e':
1331 simulation_delta *= 2.f;
1333 break;
1335 case 'E':
1337 simulation_delta /= 2.f;
1339 break;
1341 case 'r':
1343 initialize_lights(1);
1344 update_light_state(multi_light_chunk, lights);
1345 update_material_database_state(ssbo_material_database, materials);
1347 simulation_delta = 0.0001f;
1348 elapse_time_limit = 10.f;
1350 simulate_geometry = true;
1351 simulate_lights = true;
1353 glutPostRedisplay();
1355 break;
1357 case 'p':
1359 BOOST_FOREACH(Light& light, lights)
1360 light.range *= rangeFactor;
1362 update_light_state(multi_light_chunk, lights);
1363 glutPostRedisplay();
1365 break;
1367 case 'P':
1369 BOOST_FOREACH(Light& light, lights)
1370 if (light.range / rangeFactor >= OSG::Eps)
1371 light.range /= rangeFactor;
1373 update_light_state(multi_light_chunk, lights);
1374 glutPostRedisplay();
1376 break;
1378 case 'i':
1380 BOOST_FOREACH(Light& light, lights)
1381 light.intensity *= 1.2f;
1383 update_light_state(multi_light_chunk, lights);
1384 glutPostRedisplay();
1386 break;
1388 case 'I':
1390 BOOST_FOREACH(Light& light, lights)
1391 if (light.range / intensityFactor >= OSG::Eps)
1392 light.intensity /= intensityFactor;
1394 update_light_state(multi_light_chunk, lights);
1395 glutPostRedisplay();
1397 break;
1399 case '1':
1401 initialize_lights(1);
1402 update_light_state(multi_light_chunk, lights);
1403 update_material_database_state(ssbo_material_database, materials);
1404 glutPostRedisplay();
1406 break;
1408 case '2':
1410 if (lights.size() > 1)
1412 OSG::UInt32 num = static_cast<OSG::UInt32>(lights.size() / 2);
1413 initialize_lights(num);
1414 update_light_state(multi_light_chunk, lights);
1415 update_material_database_state(ssbo_material_database, materials);
1416 glutPostRedisplay();
1419 break;
1421 case '3':
1423 if (lights.size() <= max_num_lights)
1425 OSG::UInt32 num = static_cast<OSG::UInt32>(lights.size() * 2);
1426 initialize_lights(num);
1427 update_light_state(multi_light_chunk, lights);
1428 update_material_database_state(ssbo_material_database, materials);
1429 glutPostRedisplay();
1432 break;
1434 case '4':
1436 if (geom_nodes.size() > 1)
1438 OSG::UInt32 num = static_cast<OSG::UInt32>(geom_nodes.size() / 2);
1440 BOOST_FOREACH(OSG::Node* node, geom_nodes)
1441 scene_node->subChild(node);
1443 geom_nodes.clear();
1444 geom_trafos.clear();
1445 geom_curves.clear();
1446 ubo_geom_states.clear();
1448 for (OSG::UInt32 i = 0; i < num; ++i)
1449 scene_node->addChild(createGeometry());
1451 glutPostRedisplay();
1454 break;
1456 case '5':
1458 if (geom_nodes.size() <= 4.f * num_geometries)
1460 OSG::UInt32 num = static_cast<OSG::UInt32>(geom_nodes.size() * 2);
1462 BOOST_FOREACH(OSG::Node* node, geom_nodes)
1463 scene_node->subChild(node);
1465 geom_nodes.clear();
1466 geom_trafos.clear();
1467 geom_curves.clear();
1468 ubo_geom_states.clear();
1470 for (OSG::UInt32 i = 0; i < num; ++i)
1471 scene_node->addChild(createGeometry());
1473 glutPostRedisplay();
1476 break;
1478 case 'm':
1480 BOOST_FOREACH(OSG::MultiPropertyUBOChunk* ubo_geom_state, ubo_geom_states)
1482 GeomState geom; geom.material_index = material_idx_die();
1483 update_geometry_material_state(ubo_geom_state, geom);
1486 glutPostRedisplay();
1488 break;
1490 case 's':
1492 mgr->setStatistics(!mgr->getStatistics());
1494 break;
1496 case 'h':
1498 OSG::HDR2Stage* core = dynamic_cast<OSG::HDR2Stage*>(hdr_node->getCore());
1499 if (core)
1500 removeHDRStage();
1501 else
1502 createHDRStage();
1504 glutPostRedisplay();
1506 break;
1511 // setup the GLUT library which handles the windows for us
1513 int setupGLUT(int *argc, char *argv[])
1515 glutInit(argc, argv);
1516 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
1517 glutInitWindowSize(1000, 800);
1519 int winid = glutCreateWindow("OpenSG");
1521 glutReshapeFunc(reshape);
1522 glutDisplayFunc(display);
1523 glutMouseFunc(mouse);
1524 glutMotionFunc(motion);
1525 glutKeyboardFunc(keyboard);
1527 // call the redraw function whenever there's nothing else to do
1528 glutIdleFunc(display);
1530 return winid;
1533 void releaseGLUT()
1535 glutReshapeFunc(NULL);
1536 glutDisplayFunc(NULL);
1537 glutMouseFunc(NULL);
1538 glutMotionFunc(NULL);
1539 glutKeyboardFunc(NULL);
1540 glutIdleFunc(NULL);
1543 void print_help()
1545 std::cout << "Esc : quit example" << std::endl;
1546 std::cout << "Space : toogle geometry simulation on/off" << std::endl;
1547 std::cout << "h : toogle HDR stage usage on/off" << std::endl;
1548 std::cout << "l : toogle light simulation on/off" << std::endl;
1549 std::cout << "m : assign new color to geometry" << std::endl;
1550 std::cout << "r : reset the example" << std::endl;
1551 std::cout << "s : toogle statistics on/off" << std::endl;
1552 std::cout << "1 : only one light" << std::endl;
1553 std::cout << "2 : half number of lights" << std::endl;
1554 std::cout << "3 : double number of lights" << std::endl;
1555 std::cout << "4 : half number of geometry objects" << std::endl;
1556 std::cout << "5 : double number of geometry objects" << std::endl;
1557 std::cout << "e/E : speed up/down simulation" << std::endl;
1558 std::cout << "o/O : double/half simulation time interval" << std::endl;
1559 std::cout << "i/I : increase/decrease light intensity" << std::endl;
1560 std::cout << "p/P : increase/decrease light range" << std::endl;
1564 // ============================================================================
1566 // Part VI: Cubic Bezier spline curve implementation
1568 // ============================================================================
1570 CubicBezierCurve::CubicBezierCurve(
1571 const OSG::Pnt3f& p0,
1572 const OSG::Pnt3f& p1,
1573 const OSG::Pnt3f& p2,
1574 const OSG::Pnt3f& p3)
1576 p[0] = p0; p[1] = p1; p[2] = p2; p[3] = p3;
1579 CubicBezierCurve::CubicBezierCurve(const CubicBezierCurve& rhs)
1581 p[0] = rhs.p[0]; p[1] = rhs.p[1]; p[2] = rhs.p[2]; p[3] = rhs.p[3];
1584 CubicBezierCurve& CubicBezierCurve::operator=(const CubicBezierCurve& rhs)
1586 if (this != &rhs)
1588 p[0] = rhs.p[0]; p[1] = rhs.p[1]; p[2] = rhs.p[2]; p[3] = rhs.p[3];
1590 return *this;
1593 OSG::Pnt3f CubicBezierCurve::operator()(OSG::Real32 t) const
1595 OSG_ASSERT(0.f <= t && t <= 1.f);
1597 OSG::Real32 e = 1.f - t;
1598 OSG::Real32 sq_e = e * e;
1599 OSG::Real32 sq_t = t * t;
1601 return e * sq_e * p[0]
1602 + 3.f * t * sq_e * p[1].subZero()
1603 + 3.f * sq_t * e * p[2].subZero()
1604 + t * sq_t * p[3].subZero();
1607 OSG::Vec3f CubicBezierCurve::tangent(OSG::Real32 t) const
1609 OSG::Vec3f tangent = fst_derivative(t);
1610 tangent.normalize();
1612 return tangent;
1615 OSG::Vec3f CubicBezierCurve::normal(OSG::Real32 t) const
1617 OSG::Vec3f normal = binormal(t);
1618 normal.crossThis(tangent(t));
1619 normal.normalize();
1621 return normal;
1624 OSG::Vec3f CubicBezierCurve::binormal(OSG::Real32 t) const
1626 OSG::Vec3f binormal = fst_derivative(t);
1627 binormal.crossThis(sec_derivative(t));
1628 binormal.normalize();
1630 while (OSG::osgAbs(binormal.length() - 1.f) >= OSG::Eps)
1632 if (t + OSG::Eps <= 1.f)
1633 t += OSG::Eps;
1634 else if (t - OSG::Eps >= 0.f)
1635 t -= OSG::Eps;
1636 else
1637 OSG_ASSERT(false);
1639 binormal = fst_derivative(t);
1640 binormal.crossThis(sec_derivative(t));
1641 binormal.normalize();
1644 return binormal;
1647 OSG::Matrix CubicBezierCurve::frame(OSG::Real32 t, bool position_only) const
1649 OSG::Matrix mat;
1650 mat.identity();
1652 OSG::Vec3f P = (*this)(t).subZero();
1654 if (position_only)
1656 mat.setTranslate(P);
1658 else
1660 OSG::Vec3f T = tangent(t);
1661 OSG::Vec3f N = normal(t);
1662 OSG::Vec3f B = binormal(t);
1665 OSG::Real32 lT = T.length();
1666 OSG::Real32 lN = N.length();
1667 OSG::Real32 lB = B.length();
1669 OSG::Real32 v1 = T.dot(N);
1670 OSG::Real32 v2 = T.dot(B);
1671 OSG::Real32 v3 = N.dot(B);
1673 OSG_ASSERT(OSG::osgAbs(T.length() - 1.f) < OSG::Eps);
1674 OSG_ASSERT(OSG::osgAbs(N.length() - 1.f) < OSG::Eps);
1675 OSG_ASSERT(OSG::osgAbs(B.length() - 1.f) < OSG::Eps);
1677 mat.setValue(T,N,B,P);
1680 return mat;
1683 OSG::Real32 CubicBezierCurve::length(OSG::UInt32 numSeg) const
1685 OSG_ASSERT(numSeg >= 2);
1687 OSG::Real32 d = 1.f / numSeg;
1688 OSG::Real32 t = d;
1689 OSG::Real32 l = 0.f;
1691 OSG::Pnt3f p0 = operator()(0.f);
1693 while (t <= 1.f)
1695 OSG::Pnt3f p1 = operator()(t);
1697 l += (p1 - p0).length();
1698 t += d;
1701 return l;
1704 OSG::Vec3f CubicBezierCurve::fst_derivative(OSG::Real32 t) const
1706 OSG::Vec3f v10 = p[1] - p[0];
1707 OSG::Vec3f v21 = p[2] - p[1];
1708 OSG::Vec3f v32 = p[3] - p[2];
1710 OSG::Real32 e = 1.f - t;
1711 OSG::Real32 sq_e = e * e;
1712 OSG::Real32 sq_t = t * t;
1714 return 3.f * sq_e * v10 + 6.f * e * t * v21 + 3.f * sq_t * v32;
1717 OSG::Vec3f CubicBezierCurve::sec_derivative(OSG::Real32 t) const
1719 OSG::Vec3f v210 = p[2] - 2.f * p[1] + p[0].subZero();
1720 OSG::Vec3f v321 = p[3] - 2.f * p[2] + p[1].subZero();
1722 OSG::Real32 e = 1.f - t;
1724 return 6.f * e * v210 + 6.f * t * v321;
1727 OSG::Vec3f CubicBezierCurve::thr_devivative(OSG::Real32 t) const
1729 OSG::Vec3f v21 = p[2] - p[1];
1730 OSG::Vec3f v30 = p[3] - p[0];
1732 return -18.f * v21 + 6.f * v30;
1736 SmoothCubicBezierSpline::SmoothCubicBezierSpline(const std::vector<OSG::Pnt3f>& knots)
1737 : knots(knots)
1739 OSG_ASSERT(knots.size() > 3);
1741 points_t p1, p2;
1743 calc_ctrl_pnts(p1, p2);
1745 std::size_t n = knots.size() - 1;
1747 std::vector<OSG::Real32> lengths(n);
1748 OSG::Real32 L = 0.f;
1750 for (std::size_t i = 0; i < n; ++i)
1752 curves.push_back(CubicBezierCurve(knots[i], p1[i], p2[i], knots[i+1]));
1754 lengths[i] = curves[i].length();
1755 L += lengths[i];
1758 OSG_ASSERT(L > 0.f);
1760 OSG::Real32 d = 1.f / L;
1762 intervals.resize(n);
1764 intervals[0] = d * lengths[0];
1766 for (std::size_t i = 1; i < n-1; ++i)
1768 intervals[i] = intervals[i-1] + d * lengths[i];
1771 intervals[n-1] = 1.f;
1774 SmoothCubicBezierSpline::SmoothCubicBezierSpline(const SmoothCubicBezierSpline& rhs)
1775 : knots(rhs.knots)
1776 , intervals(rhs.intervals)
1777 , curves(rhs.curves)
1781 SmoothCubicBezierSpline& SmoothCubicBezierSpline::operator=(const SmoothCubicBezierSpline& rhs)
1783 if (this != &rhs)
1785 knots = rhs.knots;
1786 intervals = rhs.intervals;
1787 curves = rhs.curves;
1789 return *this;
1792 OSG::Pnt3f SmoothCubicBezierSpline::operator()(OSG::Real32 t) const
1794 std::size_t idx = index(t);
1795 return curves[idx](t_(t, idx));
1798 OSG::Vec3f SmoothCubicBezierSpline::tangent(OSG::Real32 t) const
1800 std::size_t idx = index(t);
1801 return curves[idx].tangent(t_(t, idx));
1804 OSG::Vec3f SmoothCubicBezierSpline::normal(OSG::Real32 t) const
1806 std::size_t idx = index(t);
1807 return curves[idx].normal(t_(t, idx));
1810 OSG::Vec3f SmoothCubicBezierSpline::binormal(OSG::Real32 t) const
1812 std::size_t idx = index(t);
1813 return curves[idx].binormal(t_(t, idx));
1816 OSG::Matrix SmoothCubicBezierSpline::frame(OSG::Real32 t, bool position_only) const
1818 std::size_t idx = index(t);
1819 return curves[idx].frame(t_(t, idx), position_only);
1822 OSG::Real32 SmoothCubicBezierSpline::length(OSG::UInt32 numSeg) const
1824 OSG::Real32 l = 0.f;
1825 BOOST_FOREACH(const CubicBezierCurve& c, curves)
1827 l += c.length(numSeg);
1829 return l;
1832 void SmoothCubicBezierSpline::calc_ctrl_pnts(points_t& p1, points_t& p2) const
1834 namespace tp = boost::tuples;
1835 typedef tp::tuple<OSG::Real32, OSG::Real32, OSG::Real32> tuple_t;
1836 typedef std::vector<tuple_t> tuples_t;
1838 std::size_t n = knots.size()-1;
1840 p1.resize(n);
1841 p2.resize(n);
1843 tuples_t a(n), b(n), c(n), d(n);
1845 a[0] = tp::make_tuple(0.f, 0.f, 0.f);
1846 b[0] = tp::make_tuple(2.f, 2.f, 2.f);
1847 c[0] = tp::make_tuple(1.f, 1.f, 1.f);
1848 d[0] = tp::make_tuple(
1849 knots[0].x() + 2.f * knots[1].x(),
1850 knots[0].y() + 2.f * knots[1].y(),
1851 knots[0].z() + 2.f * knots[1].z());
1853 for (std::size_t i = 1; i < n-1; ++i)
1855 a[i] = tp::make_tuple(1.f, 1.f, 1.f);
1856 b[i] = tp::make_tuple(4.f, 4.f, 4.f);
1857 c[i] = tp::make_tuple(1.f, 1.f, 1.f);
1858 d[i] = tp::make_tuple(
1859 4.f * knots[i].x() + 2.f * knots[i+1].x(),
1860 4.f * knots[i].y() + 2.f * knots[i+1].y(),
1861 4.f * knots[i].z() + 2.f * knots[i+1].z());
1864 a[n-1] = tp::make_tuple(2.f, 2.f, 2.f);
1865 b[n-1] = tp::make_tuple(7.f, 7.f, 7.f);
1866 c[n-1] = tp::make_tuple(0.f, 0.f, 0.f);
1867 d[n-1] = tp::make_tuple(
1868 8.f * knots[n-1].x() + 2.f * knots[n].x(),
1869 8.f * knots[n-1].y() + 2.f * knots[n].y(),
1870 8.f * knots[n-1].z() + 2.f * knots[n].z());
1872 for (std::size_t i = 1; i < n; ++i)
1874 tuple_t m = tp::make_tuple(
1875 a[i].get<0>() / b[i-1].get<0>(),
1876 a[i].get<1>() / b[i-1].get<1>(),
1877 a[i].get<2>() / b[i-1].get<2>());
1879 b[i] = tp::make_tuple(
1880 b[i].get<0>() - m.get<0>() * c[i-1].get<0>(),
1881 b[i].get<1>() - m.get<1>() * c[i-1].get<1>(),
1882 b[i].get<2>() - m.get<2>() * c[i-1].get<2>());
1884 d[i] = tp::make_tuple(
1885 d[i].get<0>() - m.get<0>() * d[i-1].get<0>(),
1886 d[i].get<1>() - m.get<1>() * d[i-1].get<1>(),
1887 d[i].get<2>() - m.get<2>() * d[i-1].get<2>());
1890 p1[n-1].setValues(
1891 d[n-1].get<0>() / b[n-1].get<0>(),
1892 d[n-1].get<1>() / b[n-1].get<1>(),
1893 d[n-1].get<2>() / b[n-1].get<2>());
1895 for (long long i = n-2; i >= 0; --i)
1897 p1[i].setValues(
1898 (d[i].get<0>() - c[i].get<0>() * p1[i+1].x()) / b[i].get<0>(),
1899 (d[i].get<1>() - c[i].get<1>() * p1[i+1].y()) / b[i].get<1>(),
1900 (d[i].get<2>() - c[i].get<2>() * p1[i+1].z()) / b[i].get<2>());
1903 for (std::size_t i = 0; i < n-1; ++i)
1905 p2[i].setValues(
1906 2.f * knots[i+1].x() - p1[i+1].x(),
1907 2.f * knots[i+1].y() - p1[i+1].y(),
1908 2.f * knots[i+1].z() - p1[i+1].z());
1911 p2[n-1].setValues(
1912 0.5f * knots[n].x() - p1[n-1].x(),
1913 0.5f * knots[n].y() - p1[n-1].y(),
1914 0.5f * knots[n].z() - p1[n-1].z());
1917 std::size_t SmoothCubicBezierSpline::index(OSG::Real32 t) const
1919 OSG_ASSERT(0.f <= t && t <= 1.f);
1921 std::vector<OSG::Real32>::const_iterator iter = std::lower_bound(intervals.begin(), intervals.end(), t);
1922 std::size_t r = iter - intervals.begin();
1923 return r;
1926 OSG::Real32 SmoothCubicBezierSpline::t_(OSG::Real32 t, std::size_t idx) const
1928 OSG_ASSERT(idx < intervals.size());
1930 OSG::Real32 t0 = 0.f;
1931 OSG::Real32 t1 = 1.f;
1933 if (idx > 0) t0 = intervals[idx-1];
1934 t1 = intervals[idx];
1936 OSG::Real32 r = (t - t0) / (t1 - t0);
1938 return r;
1941 // ============================================================================
1943 // Part VII: dice_knots helper implementation
1945 // ============================================================================
1947 typedef boost::tuples::tuple<int, int, int> index_t;
1949 struct index_hash_t : public std::unary_function<index_t, std::size_t>
1951 std::size_t operator()(const index_t& v) const
1953 std::size_t seed = 0;
1954 boost::hash_combine(seed, v.get<0>());
1955 boost::hash_combine(seed, v.get<1>());
1956 boost::hash_combine(seed, v.get<2>());
1957 return seed;
1961 std::vector<OSG::Pnt3f> dice_knots(bool close_curve)
1964 // idea: sample a number if different cube boxes from the scene and
1965 // take randomly one point from each cube. That guarantees that
1966 // the knot points do not clump and that they are all unequal.
1968 namespace tp = boost::tuples;
1970 boost::unordered_set<index_t, index_hash_t> indices;
1972 while (indices.size() < num_curve_knots)
1974 indices.insert(tp::make_tuple(box_idx_die(), box_idx_die(), box_idx_die()));
1977 OSG::Real32 l = 2 * world_size / num_grid_boxes;
1979 std::vector<OSG::Pnt3f> knots;
1981 BOOST_FOREACH(const index_t& idx, indices)
1983 OSG::Pnt3f p;
1984 p[0] = -world_size + idx.get<0>() * l + unit_die() * l;
1985 p[1] = -world_size + idx.get<1>() * l + unit_die() * l;
1986 p[2] = -world_size + idx.get<2>() * l + unit_die() * l;
1988 knots.push_back(p);
1991 if (close_curve)
1992 knots.push_back(knots.front());
1994 return knots;
1997 // ============================================================================
1999 // Part VIII: The shader programs
2001 // ============================================================================
2004 // vertex shader program.
2006 std::string get_vp_program()
2008 using namespace std;
2010 stringstream ost;
2012 ost << "#version 440 compatibility"
2013 << endl << ""
2014 << endl << "#extension GL_ARB_separate_shader_objects: enable"
2015 << endl << "#extension GL_ARB_shader_storage_buffer_object: enable"
2016 << endl << ""
2017 << endl << "smooth out vec3 vNormalES; // eye space normal"
2018 << endl << "smooth out vec3 vPositionES; // eye space position"
2019 << endl << ""
2020 << endl << "void main()"
2021 << endl << "{"
2022 << endl << " //"
2023 << endl << " // multiply the object space vertex position with the modelview matrix "
2024 << endl << " // to get the eye space vertex position"
2025 << endl << " //"
2026 << endl << " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;"
2027 << endl << ""
2028 << endl << " //"
2029 << endl << " // multiply the object space normal with the normal matrix (transpose of the inverse "
2030 << endl << " // model view matrix) to get the eye space normal"
2031 << endl << " //"
2032 << endl << " vNormalES = gl_NormalMatrix * gl_Normal;"
2033 << endl << ""
2034 << endl << " //"
2035 << endl << " // multiply the combiend modelview projection matrix with the object space vertex"
2036 << endl << " // position to get the clip space position"
2037 << endl << " //"
2038 << endl << " gl_Position = ftransform();"
2039 << endl << "}"
2040 << endl << ""
2041 << endl;
2043 return ost.str();
2047 // fragment shader program for bump mapping in surface local coordinates
2049 std::string get_fp_program()
2051 using namespace std;
2053 stringstream ost;
2055 ost << "#version 440 compatibility"
2056 << endl << ""
2057 << endl << "#extension GL_ARB_separate_shader_objects: enable"
2058 << endl << "#extension GL_ARB_shader_storage_buffer_object: enable"
2059 << endl << ""
2060 << endl << "smooth in vec3 vNormalES; // eye space normal"
2061 << endl << "smooth in vec3 vPositionES; // eye space position"
2062 << endl << ""
2063 << endl << "const int num_materials = 5000;"
2064 << endl << ""
2065 << endl << "const int POINT_LIGHT = 1; // defined in OSGMultiLightChunk.h"
2066 << endl << "const int DIRECTIONAL_LIGHT = 2;"
2067 << endl << "const int SPOT_LIGHT = 3;"
2068 << endl << "const int CINEMA_LIGHT = 4;"
2069 << endl << ""
2070 << endl << "uniform mat4 OSGViewMatrix;"
2071 << endl << ""
2072 << endl << "struct Light"
2073 << endl << "{"
2074 << endl << " vec3 position; // in world space"
2075 << endl << " vec3 direction; // in world space"
2076 << endl << " vec3 color;"
2077 << endl << " float intensity;"
2078 << endl << " float range;"
2079 << endl << " float cosSpotlightAngle;"
2080 << endl << " int type; // specific type of light: POINT_LIGHT, DIRECTIONAL_LIGHT, SPOT_LIGHT or CINEMA_LIGHT"
2081 << endl << " bool enabled; // on/off state of light"
2082 << endl << "};"
2083 << endl << ""
2084 << endl << "layout (std430) buffer Lights"
2085 << endl << "{"
2086 << endl << " Light light[];"
2087 << endl << "} lights;"
2088 << endl << ""
2089 << endl << "struct Material"
2090 << endl << "{"
2091 << endl << " vec3 ambient;"
2092 << endl << " vec3 diffuse;"
2093 << endl << " vec3 specular;"
2094 << endl << " vec3 emissive;"
2095 << endl << ""
2096 << endl << " float opacity;"
2097 << endl << " float shininess;"
2098 << endl << "};"
2099 << endl << ""
2100 << endl << "layout (std430) buffer Materials"
2101 << endl << "{"
2102 << endl << " Material material[num_materials];"
2103 << endl << "} materials;"
2104 << endl << ""
2105 << endl << ""
2106 << endl << "layout (std140) uniform GeomState"
2107 << endl << "{"
2108 << endl << " int material_index;"
2109 << endl << "} geom_state;"
2110 << endl << ""
2111 << endl << "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!"
2112 << endl << ""
2113 << endl << "layout(location = 0) out vec4 vFragColor;"
2114 << endl << ""
2115 << endl << "//"
2116 << endl << "// Calculate the attenuation of the light based on the light "
2117 << endl << "// range r and the distance d of the light to the current point."
2118 << endl << "//"
2119 << endl << "float calcAttenuation(in float r, in float d)"
2120 << endl << "{"
2121 << endl << " return 1.0 - smoothstep(0.75 * r, r, d);"
2122 << endl << "}"
2123 << endl << ""
2124 << endl << "//"
2125 << endl << "// Calculate the attenuation with respect to the spot light cone."
2126 << endl << "// Parameters:"
2127 << endl << "// minCosSpotAngle: the cosine of the spot light angle"
2128 << endl << "// l : normalized direction between fragment and light position"
2129 << endl << "// s : normalized light direction"
2130 << endl << "//"
2131 << endl << "float spotAttenuation(in float minCosSpotAngle, in vec3 l, in vec3 s)"
2132 << endl << "{"
2133 << endl << " float maxCosSpotAngle = mix(minCosSpotAngle, 1.0, 0.5);"
2134 << endl << " float l_dot_s = dot(-l, s);"
2135 << endl << " return smoothstep(minCosSpotAngle, maxCosSpotAngle, l_dot_s);"
2136 << endl << "}"
2137 << endl << ""
2138 << endl << "//"
2139 << endl << "// directional light contribution"
2140 << endl << "//"
2141 << endl << "vec3 directionalLight("
2142 << endl << " in int i, // light identifier, i.e. current light"
2143 << endl << " in int j, // material identifier"
2144 << endl << " in vec3 n, // vertex normal in eye space"
2145 << endl << " in vec3 v) // view direction in eye space"
2146 << endl << "{"
2147 << endl << " if (!lights.light[i].enabled)"
2148 << endl << " return vec3(0.0, 0.0, 0.0);"
2149 << endl << ""
2150 << endl << " //"
2151 << endl << " // the light direction in eye space"
2152 << endl << " //"
2153 << endl << " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
2154 << endl << " vec3 l = -direction.xyz;"
2155 << endl << ""
2156 << endl << " //"
2157 << endl << " // the half vector"
2158 << endl << " //"
2159 << endl << " vec3 h = normalize(l+v);"
2160 << endl << ""
2161 << endl << " float n_dot_l = max(0.0, dot(n, l));"
2162 << endl << " float n_dot_h = max(0.0, dot(n, h));"
2163 << endl << ""
2164 << endl << " float m = materials.material[j].shininess;"
2165 << endl << ""
2166 << endl << " float pf; // power factor"
2167 << endl << ""
2168 << endl << " if (n_dot_l == 0.0)"
2169 << endl << " pf = 0.0;"
2170 << endl << " else"
2171 << endl << " pf = pow(n_dot_h, m);"
2172 << endl << ""
2173 << endl << " vec3 light_intensity = lights.light[i].intensity * lights.light[i].color;"
2174 << endl << ""
2175 << endl << " return materials.material[j].emissive"
2176 << endl << " + light_intensity * materials.material[j].ambient"
2177 << endl << " + light_intensity * materials.material[j].diffuse * n_dot_l"
2178 << endl << " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
2179 << endl << "}"
2180 << endl << ""
2181 << endl << "//"
2182 << endl << "// point light contribution"
2183 << endl << "//"
2184 << endl << "vec3 pointLight("
2185 << endl << " in int i, // light identifier, i.e. current light"
2186 << endl << " in int j, // material identifier"
2187 << endl << " in vec3 n, // vertex normal in eye space"
2188 << endl << " in vec3 v, // view direction in eye space"
2189 << endl << " in vec3 p) // vertex position in eye space"
2190 << endl << "{"
2191 << endl << " if (!lights.light[i].enabled)"
2192 << endl << " return vec3(0.0, 0.0, 0.0);"
2193 << endl << ""
2194 << endl << " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
2195 << endl << " vec3 l = position.xyz - p; // dir from surface to light position"
2196 << endl << " float d = length(l); // dist from surface to light source"
2197 << endl << ""
2198 << endl << " if (lights.light[i].range < d)"
2199 << endl << " return vec3(0.0, 0.0, 0.0);"
2200 << endl << ""
2201 << endl << " l = normalize(l); // norm direction from surf to light"
2202 << endl << ""
2203 << endl << " //"
2204 << endl << " // the half vector"
2205 << endl << " //"
2206 << endl << " vec3 h = normalize(l+v);"
2207 << endl << ""
2208 << endl << " float n_dot_l = max(0.0, dot(n, l));"
2209 << endl << " float n_dot_h = max(0.0, dot(n, h));"
2210 << endl << ""
2211 << endl << " float m = materials.material[j].shininess;"
2212 << endl << ""
2213 << endl << " float pf; // power factor"
2214 << endl << ""
2215 << endl << " if (n_dot_l == 0.0)"
2216 << endl << " pf = 0.0;"
2217 << endl << " else"
2218 << endl << " pf = pow(n_dot_h, m);"
2219 << endl << ""
2220 << endl << " float attenuation = calcAttenuation(lights.light[i].range, d);"
2221 << endl << ""
2222 << endl << " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
2223 << endl << ""
2224 << endl << " return materials.material[j].emissive"
2225 << endl << " + light_intensity * materials.material[j].ambient"
2226 << endl << " + light_intensity * materials.material[j].diffuse * n_dot_l"
2227 << endl << " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
2228 << endl << "}"
2229 << endl << ""
2230 << endl << "//"
2231 << endl << "// spot light contribution"
2232 << endl << "//"
2233 << endl << "vec3 spotLight("
2234 << endl << " in int i, // light identifier, i.e. current light"
2235 << endl << " in int j, // material identifier"
2236 << endl << " in vec3 n, // vertex normal in eye space"
2237 << endl << " in vec3 v, // view direction in eye space"
2238 << endl << " in vec3 p) // vertex position in eye space"
2239 << endl << "{"
2240 << endl << " if (!lights.light[i].enabled)"
2241 << endl << " return vec3(0.0, 0.0, 0.0);"
2242 << endl << ""
2243 << endl << " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
2244 << endl << " vec3 l = position.xyz - p; // dir from surface to light position"
2245 << endl << " float d = length(l); // dist from surface to light source"
2246 << endl << ""
2247 << endl << " if (lights.light[i].range < d)"
2248 << endl << " return vec3(0.0, 0.0, 0.0);"
2249 << endl << ""
2250 << endl << " l = normalize(l); // norm dir from surface to light"
2251 << endl << " "
2252 << endl << " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
2253 << endl << " vec3 s = direction.xyz;"
2254 << endl << " s = normalize(s);"
2255 << endl << ""
2256 << endl << " //"
2257 << endl << " // the half vector"
2258 << endl << " //"
2259 << endl << " vec3 h = normalize(l+v);"
2260 << endl << ""
2261 << endl << " float n_dot_l = max(0.0, dot(n, l));"
2262 << endl << " float n_dot_h = max(0.0, dot(n, h));"
2263 << endl << ""
2264 << endl << " float m = materials.material[j].shininess;"
2265 << endl << ""
2266 << endl << " float pf; // power factor"
2267 << endl << ""
2268 << endl << " if (n_dot_l == 0.0)"
2269 << endl << " pf = 0.0;"
2270 << endl << " else"
2271 << endl << " pf = pow(n_dot_h, m);"
2272 << endl << ""
2273 << endl << " float attenuation = calcAttenuation(lights.light[i].range, d);"
2274 << endl << " attenuation *= spotAttenuation(lights.light[i].cosSpotlightAngle, l, s);"
2275 << endl << ""
2276 << endl << " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
2277 << endl << ""
2278 << endl << " return materials.material[j].emissive"
2279 << endl << " + light_intensity * materials.material[j].ambient"
2280 << endl << " + light_intensity * materials.material[j].diffuse * n_dot_l"
2281 << endl << " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
2282 << endl << "}"
2283 << endl << ""
2284 << endl << "void main()"
2285 << endl << "{"
2286 << endl << " //"
2287 << endl << " // normalize the eye space normal"
2288 << endl << " //"
2289 << endl << " int frontCond = -(1 - int(gl_FrontFacing)*2);"
2290 << endl << " vec3 N = frontCond * normalize(vNormalES);"
2291 << endl << ""
2292 << endl << " //"
2293 << endl << " // get the view vector and normalize it"
2294 << endl << " //"
2295 << endl << " vec3 V = normalize(cCameraPositionES - vPositionES);"
2296 << endl << ""
2297 << endl << " //"
2298 << endl << " // Integrate over all lights: Any unused light does not contribute and each light"
2299 << endl << " // contribute either from the directional light, the point light or the spot light."
2300 << endl << " //"
2301 << endl << " vec3 color = vec3(0.0, 0.0, 0.0);"
2302 << endl << ""
2303 << endl << " int num_lights = lights.light.length();"
2304 << endl << ""
2305 << endl << " for (int i = 0; i < num_lights; ++i)"
2306 << endl << " {"
2307 << endl << " switch (lights.light[i].type)"
2308 << endl << " {"
2309 << endl << " case POINT_LIGHT: color += pointLight(i, geom_state.material_index, N, V, vPositionES); break;"
2310 << endl << " case DIRECTIONAL_LIGHT: color += directionalLight(i, geom_state.material_index, N, V); break;"
2311 << endl << " case SPOT_LIGHT: color += spotLight(i, geom_state.material_index, N, V, vPositionES); break;"
2312 << endl << " }"
2313 << endl << " }"
2314 << endl << " vFragColor = vec4(color, materials.material[geom_state.material_index].opacity);"
2315 << endl << ""
2316 << endl << "}"
2317 << endl << ""
2318 << endl;
2320 return ost.str();