1 // OpenSG Example: MultiRangeLightClusterShadingStage
3 // This example implements a forward cluster shading algorithm according to
4 // Ola Olsson et.al and Emil Persson
5 // https://newq.net/publications/more/s2015-many-lights-course
7 // It uses the MultiLightChunk for the light representation and the
8 // ClusterShadingStage core. It shows a simple scene that
9 // is filled with geometry and point, spot and cinema lights.
10 // Keyboard bindings allow to manipulate the setup in various ways.
12 // At startup you can see 128 lights and 256 geometries moving in the scene.
13 // On a NVidia GeForce GTX 560 rendering this scene renders smoothly.
14 // Pressing button 't' stops the clustering and the frame rate drops.
15 // After enabling clustering again by pressing 't' you can increase
16 // the number of lights to 512 by pressing key '3' two times. Now the
17 // frame rate miserable despite of the clustering. The reason is that
18 // the cluster population is now to hight. We can lower it by decreasing
19 // the range of influence of the lights by pressing key 'P' (shift) four
20 // times. Now the frame rate is somewhat reasonable. Switching clustering
21 // off by key 't' gets the GPU into considerable workload with resulting
22 // in a very poor frame rate.
25 // - only tested on decsent NVidia GPUs
26 // - this example is a proof of concept
27 // - this example is not performance optimized
31 // Space : toogle geometry simulation on/off
33 // 2 : half number of lights
34 // 3 : double number of lights
35 // 4 : half number of geometry objects
36 // 5 : double number of geometry objects
37 // a : add directional test lights useful only if the view
38 // frustum is visualized
39 // b : show correct light geometry frustum
40 // c : cull lights on cpu. Only useful for testing
41 // e/E : speed up/down simulation
42 // h : toogle HDR stage usage on/off
43 // i/I : increase/decrease light intensity
44 // l : toogle light simulation on/off
45 // m : assign new color to geometry
46 // o/O : double/half simulation time interval
47 // p/P : increase/decrease light range
48 // r : reset the example
49 // s : toogle statistics on/off
50 // t : toogle usage of cluster shading on/off
51 // u : toggle spot direction line on/off
52 // U : toggle special spot direction cases
53 // v : toogle frustum visualization on/off
54 // x : recreate the lights with current spot dir case
57 #include <boost/functional/hash.hpp>
58 #include <boost/unordered_set.hpp>
59 #include <boost/foreach.hpp>
60 #include <boost/random.hpp>
61 #include <boost/tuple/tuple.hpp>
62 #include "boost/tuple/tuple_comparison.hpp"
63 #include <boost/multi_array.hpp>
65 #ifdef OSG_BUILD_ACTIVE
68 #include <OSGConfig.h>
69 #include <OSGSimpleGeometry.h>
70 #include <OSGGLUTWindow.h>
71 #include <OSGSimpleSceneManager.h>
72 #include <OSGBaseFunctions.h>
73 #include <OSGTransform.h>
80 #include <OSGMatrixCamera.h>
81 #include <OSGPerspectiveCamera.h>
82 #include <OSGOrthographicCamera.h>
83 #include <OSGHDR2Stage.h>
84 #include <OSGClusterShadingStage.h>
85 #include <OSGInverseTransform.h>
86 #include <OSGShaderProgramChunk.h>
87 #include <OSGShaderProgram.h>
88 #include <OSGShaderVariableOSG.h>
89 #include <OSGShaderProgramVariableChunk.h>
90 #include <OSGShaderProgramVariables.h>
91 #include <OSGShaderStorageBufferObjChunk.h>
92 #include <OSGShaderStorageBufferObjStdLayoutChunk.h>
93 #include <OSGUniformBufferObjChunk.h>
94 #include <OSGChunkMaterial.h>
95 #include <OSGMaterialGroup.h>
96 #include <OSGMaterialChunkOverrideGroup.h>
97 #include <OSGMatrixUtility.h>
98 #include <OSGMultiLightChunk.h>
99 #include <OSGMultiPropertyUBOChunk.h>
100 #include <OSGMultiPropertySSBOChunk.h>
101 #include <OSGPolygonChunk.h>
102 #include <OSGDepthChunk.h>
103 #include <OSGBlendChunk.h>
104 #include <OSGTextureObjChunk.h>
105 #include <OSGTextureEnvChunk.h>
106 #include <OSGTextureImageChunk.h>
107 #include <OSGTwoSidedLightingChunk.h>
108 #include <OSGAlgorithmComputeElement.h>
109 #include <OSGComputeShaderAlgorithm.h>
110 #include <OSGComputeShaderChunk.h>
111 #include <OSGGeoProperties.h>
112 #include <OSGSimpleLightGeometry.h>
113 #include <OSGSimpleCurve.h>
117 #include <OpenSG/OSGGLUT.h>
118 #include <OpenSG/OSGConfig.h>
119 #include <OpenSG/OSGSimpleGeometry.h>
120 #include <OpenSG/OSGGLUTWindow.h>
121 #include <OpenSG/OSGSimpleSceneManager.h>
122 #include <OpenSG/OSGBaseFunctions.h>
123 #include <OpenSG/OSGTransform.h>
124 #include <OpenSG/OSGGroup.h>
127 #include <OpenSG/OSGGLEXT.h>
128 #include <OpenSG/OSGTime.h>
129 #include <OpenSG/OSGPlane.h>
130 #include <OpenSG/OSGMatrixCamera.h>
131 #include <OpenSG/OSGPerspectiveCamera.h>
132 #include <OpenSG/OSGOrthographicCamera.h>
133 #include <OpenSG/OSGHDR2Stage.h>
134 #include <OpenSG/OSGClusterShadingStage.h>
135 #include <OpenSG/OSGInverseTransform.h>
136 #include <OpenSG/OSGShaderProgramChunk.h>
137 #include <OpenSG/OSGShaderProgram.h>
138 #include <OpenSG/OSGShaderVariableOSG.h>
139 #include <OpenSG/OSGShaderProgramVariableChunk.h>
140 #include <OpenSG/OSGShaderProgramVariables.h>
141 #include <OpenSG/OSGShaderStorageBufferObjChunk.h>
142 #include <OpenSG/OSGShaderStorageBufferObjStdLayoutChunk.h>
143 #include <OpenSG/OSGUniformBufferObjChunk.h>
144 #include <OpenSG/OSGChunkMaterial.h>
145 #include <OpenSG/OSGMaterialGroup.h>
146 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
147 #include <OpenSG/OSGMatrixUtility.h>
148 #include <OpenSG/OSGMultiLightChunk.h>
149 #include <OpenSG/OSGMultiPropertyUBOChunk.h>
150 #include <OpenSG/OSGMultiPropertySSBOChunk.h>
151 #include <OpenSG/OSGPolygonChunk.h>
152 #include <OpenSG/OSGDepthChunk.h>
153 #include <OpenSG/OSGBlendChunk.h>
154 #include <OpenSG/OSGTextureObjChunk.h>
155 #include <OpenSG/OSGTextureEnvChunk.h>
156 #include <OpenSG/OSGTextureImageChunk.h>
157 #include <OpenSG/OSGTwoSidedLightingChunk.h>
158 #include <OpenSG/OSGAlgorithmComputeElement.h>
159 #include <OpenSG/OSGComputeShaderAlgorithm.h>
160 #include <OpenSG/OSGComputeShaderChunk.h>
161 #include <OpenSG/OSGGeoProperties.h>
162 #include <OpenSG/OSGSimpleLightGeometry.h>
163 #include <OpenSG/OSGSimpleCurve.h>
166 // ============================================================================
168 // Part: Declaration of the example scene and some helpers:
169 // - constants that governs the example
170 // - random number generators
171 // - smooth cubic Bezier spline curve
173 // ============================================================================
175 const bool use_ortho_camera
= false; // use a orthographic camera instead of the perspective camera
177 const OSG::Int32 init_num_geometries
= 256; // the initial number of to be lit geometry
178 const OSG::Int32 max_num_geometries
= 2048; // the maximal number of lit geometry
180 const OSG::Int32 num_grid_boxes
= 100; // each light and geometry has a motion curve.
181 // Sample a number if different cube boxes from the scene and
182 // take randomly one point from each cube. That guarantees that
183 // the knot points do not clump and that they are all unequal.
184 const OSG::Int32 num_curve_knots
= 40; // each motion curve has that number of knot points
186 const std::size_t num_materials
= 5000; // material database has this number of entries
188 const OSG::Int32 init_num_lights
= 128; // initial number if example lights
189 const OSG::Int32 max_num_lights
= 2048; // maximal number of allowed lights
191 const OSG::Real32 max_light_power
= 10.f
; // light intensity is choosen randomly up to the maximal light power
193 const OSG::Real32 world_size
= 10.f
; // lights and geometry init positions are bounded in the world
194 const OSG::Real32 box_factor
= 1.5f
; // visualization box is drawn around the world
196 OSG::Real32 simulation_delta
= 0.0001f
; // determines the simulation speed (keys e/E)
197 OSG::Real32 elapse_time_limit
= 10.f
; // time in milliseconds after which a simulation step is performed (keys o/O)
201 const OSG::Real32 rangeFactor
= 1.15f
; // range multiplication factor (keys p/P)
202 const OSG::Real32 intensityFactor
= 1.2f
; // intensity multiplication factor (keys i/I)
204 const OSG::UInt32 block_size
= 16; // number of compute shader threads per xy-direction
205 const OSG::UInt32 tile_size
= 64; // number of pixel per cluster tile per xy-direction
206 const OSG::UInt32 num_cluster_z
= 32; // number of clusters in the z direction
207 const OSG::Real32 near_plane_offset
= 5.f
; // clustering starts to (zNear + near_plane_offset)
209 const OSG::UInt32 light_index_list_size
= 2097152; // Max number of light index list entries.
210 // If we have a screen size of 1920*1080 pixel and assume
211 // a 32 cluster in z-direction we have, with a tile size
212 // of 64 pixel, 30*17*32 = 16320 cluster. With 2^21 = 2097152
213 // light list entries we have on average space for around 64
214 // lights per cluster. The light list then occupy
215 // 2097152*4 bytes = 8388608 bytes of graphic memory.
217 const OSG::Vec3i work_group_size
= OSG::Vec3i(block_size
, block_size
, 1);
218 // each compute shader work group has that thread layout
220 const OSG::UInt32 num_test_val_entries
= 65536; // number of array elements in the TestData members.
221 // on default the test data is not transfered to the GPU
222 // and no test are performed. Test were used on example
223 // development and are leaved in for illustration purpose.
226 // Simulation parameters
228 OSG::TimeStamp time_stamp
= 0; // time stamp is updated after each simulation step
229 OSG::Real32 simulation_param
= 0.f
; // value in range [0,1]. Used for motion curve evaluation
230 bool simulate_geometry
= true; // motion of lit geometry
231 bool simulate_lights
= true; // motion of shading lights
233 bool visualize_frustum
= false;
235 OSG::SimpleSceneManagerRefPtr mgr
; // the global scene manager
238 // The example makes use of many randomly choosen values for various parameters.
239 // Most parameters have specific ranges and types. Therefore the example provides
240 // special dices on uniform distributions over the ranges for the different parameters.
242 typedef boost::mt19937 RNGType
;
243 RNGType
rng(time(0));
245 boost::uniform_int
<> box_dist(0, num_grid_boxes
-1);
246 boost::variate_generator
<RNGType
, boost::uniform_int
<> > box_idx_die(rng
, box_dist
);
248 boost::uniform_int
<> die_dist(1, 6);
249 boost::variate_generator
<RNGType
, boost::uniform_int
<> > classic_die(rng
, die_dist
);
251 boost::uniform_int
<> geom_dist(0, 7);
252 boost::variate_generator
<RNGType
, boost::uniform_int
<> > geom_idx_die(rng
, geom_dist
);
254 boost::uniform_01
<float> unit_distribution
;
255 boost::variate_generator
< RNGType
, boost::uniform_01
<float> > unit_die(rng
, unit_distribution
);
257 boost::uniform_real
<float> small_distribution(0.1f
, 1.f
);
258 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > small_die(rng
, small_distribution
);
260 boost::uniform_real
<float> spot_distribution(5.f
, 90.f
);
261 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > spot_die(rng
, spot_distribution
);
263 boost::uniform_real
<float> light_range_distribution(0.2f
, 0.7f
);
264 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > light_range_die(rng
, light_range_distribution
);
266 boost::uniform_real
<float> light_ellipsis_roundness_distribution1(0.2f
, 1.0f
);
267 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > light_ellipsis_roundness_die1(rng
, light_ellipsis_roundness_distribution1
);
269 boost::uniform_real
<float> light_ellipsis_roundness_distribution2(1.0f
, 2.0f
);
270 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > light_ellipsis_roundness_die2(rng
, light_ellipsis_roundness_distribution2
);
272 boost::uniform_real
<float> light_ellipsis_roundness_distribution3(2.0f
, 51.0f
);
273 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > light_ellipsis_roundness_die3(rng
, light_ellipsis_roundness_distribution3
);
275 boost::uniform_real
<float> light_ellipsis_twist_distribution(0.f
, 360.0f
);
276 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > light_ellipsis_twist_die(rng
, light_ellipsis_twist_distribution
);
278 boost::uniform_real
<float> light_ellipsis_radius_distribution(0.1f
, 2.0f
);
279 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > light_ellipsis_radius_die(rng
, light_ellipsis_radius_distribution
);
281 boost::uniform_real
<float> light_ellipsis_radius_ratio_distribution(1.01f
, 1.5f
);
282 boost::variate_generator
< RNGType
, boost::uniform_real
<float> > light_ellipsis_radius_ratio_die(rng
, light_ellipsis_radius_ratio_distribution
);
284 std::vector
<OSG::Pnt3f
> dice_knots(bool close_curve
);
286 OSG::Vec3f
dice_unit_vector()
290 while (v
.length() < OSG::Eps
)
292 -1.f
+ 2.f
* unit_die(),
293 -1.f
+ 2.f
* unit_die(),
294 -1.f
+ 2.f
* unit_die());
301 // ============================================================================
303 // Part: Declaration/Implementation of
304 // - struct Light and type VecLightsT,
305 // - struct Material and type VecMaterialsT,
306 // - struct GeomState
307 // and corresponding initialization routines.
309 // ============================================================================
312 // simple light data structure
314 struct Light
: public OSG::MultiLight
316 explicit Light(Type e
);
319 static Light
create_light(Type e
, OSG::Int32 test_dir_light_type
= -1);
321 void create_light_geometry(OSG::UInt32 material_idx
);
323 OSG::TransformRefPtr transform
; // the beacons transform core
324 OSG::SmoothCubicBezierSpline curve
; // the path that the light will follow
326 static bool cpu_cull_lights
;
327 static bool cpu_calc_frustums
;
328 static bool add_dir_test_lights
;
329 static bool correct_light_geometry
;
330 static bool use_light_index_list
;
331 static bool show_spot_dir_line
;
332 static int force_spot_dir
;
333 static OSG::Vec3f dir_test_case_6
;
334 static OSG::Vec3f dir_test_case_7
;
335 static OSG::Vec3f dir_test_case_8
;
338 bool Light::cpu_cull_lights
= false;
339 bool Light::cpu_calc_frustums
= false;
340 bool Light::add_dir_test_lights
= false;
341 bool Light::correct_light_geometry
= false;
342 bool Light::use_light_index_list
= true;
343 bool Light::show_spot_dir_line
= false;
344 int Light::force_spot_dir
= 0;
345 OSG::Vec3f
Light::dir_test_case_6
= OSG::Vec3f(0,0,-1);
346 OSG::Vec3f
Light::dir_test_case_7
= OSG::Vec3f(0,0,-1);
347 OSG::Vec3f
Light::dir_test_case_8
= OSG::Vec3f(0,0,-1);
349 typedef std::vector
<Light
> VecLightsT
; // multiple lights
350 VecLightsT lights
; // the lights of the scene
355 , curve(dice_knots(true))
365 // Simple material data structure
370 : ambient (0.f
, 0.f
, 0.f
)
371 , diffuse (0.f
, 0.f
, 0.f
)
372 , specular(0.f
, 0.f
, 0.f
)
373 , emissive(0.f
, 0.f
, 0.f
)
378 OSG::Color3f ambient
;
379 OSG::Color3f diffuse
;
380 OSG::Color3f specular
;
381 OSG::Color3f emissive
;
384 OSG::Real32 shininess
;
386 static OSG::UInt32 ambient_id
;
387 static OSG::UInt32 diffuse_id
;
388 static OSG::UInt32 specular_id
;
389 static OSG::UInt32 emissive_id
;
390 static OSG::UInt32 opacity_id
;
391 static OSG::UInt32 shininess_id
;
394 OSG::UInt32
Material:: ambient_id
= 0;
395 OSG::UInt32
Material:: diffuse_id
= 0;
396 OSG::UInt32
Material:: specular_id
= 0;
397 OSG::UInt32
Material:: emissive_id
= 0;
398 OSG::UInt32
Material:: opacity_id
= 0;
399 OSG::UInt32
Material::shininess_id
= 0;
401 typedef std::vector
<Material
> VecMaterialsT
; // multiple materials
403 VecMaterialsT
initialize_materials(std::size_t num
) // helper to create materials
405 OSG_ASSERT(num
> max_num_lights
+ 1);
407 VecMaterialsT
mat(num
);
409 for (std::size_t i
= max_num_lights
+1; i
< num
; ++i
)
411 mat
[i
].ambient
= OSG::Color3f(0.001f
, 0.001f
, 0.001f
);
412 mat
[i
].diffuse
.setRandom();
413 mat
[i
].specular
= OSG::Color3f(0.9f
, 0.9f
, 0.9f
);
414 mat
[i
].emissive
= OSG::Color3f(0.0f
, 0.0f
, 0.0f
);
415 mat
[i
].opacity
= 1.f
;
416 mat
[i
].shininess
= 320.f
* small_die();
418 //int r = classic_die();
420 // mat[i].opacity = small_die();
424 // special grey material for box
426 mat
[0].ambient
= OSG::Color3f(0.001f
, 0.001f
, 0.001f
);
427 mat
[0].diffuse
= OSG::Color3f(0.7f
, 0.7f
, 0.7f
);
428 mat
[0].specular
= OSG::Color3f(0.9f
, 0.9f
, 0.9f
);
429 mat
[0].emissive
= OSG::Color3f(0.0f
, 0.0f
, 0.0f
);
430 mat
[0].opacity
= 1.f
;
431 mat
[0].shininess
= 100.f
;
436 VecMaterialsT materials
= initialize_materials(num_materials
); // the material database
439 // we reserve the first max_num_lights + 1 materials for the light simulation and
442 boost::uniform_int
<OSG::UInt32
> material_dist(max_num_lights
+1, num_materials
-1);
443 boost::variate_generator
<RNGType
, boost::uniform_int
<OSG::UInt32
> > material_idx_die(rng
, material_dist
);
446 // Simple geometry state data structure
454 OSG::UInt32 material_index
;
456 static OSG::UInt32 material_index_id
;
459 OSG::UInt32
GeomState::material_index_id
= 0;
461 // ============================================================================
463 // Part: Creation and update of the light state
465 // ============================================================================
467 OSG::MultiLightChunkTransitPtr
create_light_state(const VecLightsT
& vLights
)
469 OSG::MultiLightChunkRefPtr lightChunk
= OSG::MultiLightChunk::create();
471 lightChunk
->setUsage(GL_DYNAMIC_DRAW
);
472 lightChunk
->setLayoutType(OSG::MultiLight::SIMPLE_LAYOUT
| OSG::MultiLight::CINEMA_LAYOUT
);
474 lightChunk
->setHasEyeToLightSpaceMatrix(true); // provide a struct entry for the transform from view space to light space
475 lightChunk
->setHasCosSpotlightAngle (true); // provide a struct entry for the cosine of the spot light angle (defaults to true)
476 lightChunk
->setHasSpotlightAngle (true); // provide a struct entry for the spot light angle itself (defaults to false)
478 //lightChunk->setEyeSpace(true);
480 BOOST_FOREACH(const Light
& light
, vLights
)
482 lightChunk
->addLight(light
);
485 return OSG::MultiLightChunkTransitPtr(lightChunk
);
488 void update_light_state(OSG::MultiLightChunk
* lightChunk
, const VecLightsT
& vLights
)
492 if (lightChunk
->numLights() != vLights
.size())
494 lightChunk
->clearLights();
496 BOOST_FOREACH(const Light
& light
, vLights
)
498 lightChunk
->addLight(light
);
503 for (OSG::UInt32 idx
= 0; idx
< vLights
.size(); ++idx
)
505 const Light
& light
= vLights
[idx
];
506 lightChunk
->updateLight(idx
, light
);
512 // ============================================================================
514 // Part: Some routines for handling of the memory buffer and the the
515 // creation on the MultiPropertySSBOChunk objects:
517 // i) create_material_database_state,
518 // update_material_database_state
520 // ii) create_geometry_material_state,
521 // update_geometry_material_state
523 // ============================================================================
526 // i) the material shader storage buffer object
528 OSG::MultiPropertySSBOChunkTransitPtr
create_material_database_state(const VecMaterialsT
& vMaterials
)
530 OSG::MultiPropertySSBOChunkRefPtr materialChunk
= OSG::MultiPropertySSBOChunk::create();
532 OSG::UInt32 vec3_id
, float_id
;
534 vec3_id
= materialChunk
->addMember(OSG::MultiPropertySSBOChunk:: VEC3_T
, 4);
535 float_id
= materialChunk
->addMember(OSG::MultiPropertySSBOChunk::FLOAT_T
, 2);
537 materialChunk
->setUsage(GL_STATIC_DRAW
);
539 Material:: ambient_id
= vec3_id
++;
540 Material:: diffuse_id
= vec3_id
++;
541 Material:: specular_id
= vec3_id
++;
542 Material:: emissive_id
= vec3_id
;
544 Material:: opacity_id
= float_id
++;
545 Material::shininess_id
= float_id
;
547 BOOST_FOREACH(const Material
& mat
, vMaterials
)
549 OSG::UInt32 idx
= materialChunk
->addProperty();
551 materialChunk
->setVec3Property (idx
, Material:: ambient_id
, mat
.ambient
);
552 materialChunk
->setVec3Property (idx
, Material:: diffuse_id
, mat
.diffuse
);
553 materialChunk
->setVec3Property (idx
, Material:: specular_id
, mat
.specular
);
554 materialChunk
->setVec3Property (idx
, Material:: emissive_id
, mat
.emissive
);
556 materialChunk
->setFloatProperty(idx
, Material:: opacity_id
, mat
.opacity
);
557 materialChunk
->setFloatProperty(idx
, Material::shininess_id
, mat
.shininess
);
560 return OSG::MultiPropertySSBOChunkTransitPtr(materialChunk
);
563 void update_material_database_state(OSG::MultiPropertySSBOChunk
* materialChunk
, const VecMaterialsT
& vMaterials
)
567 if (materialChunk
->getNumProperties() != vMaterials
.size())
569 materialChunk
->clearProperties();
571 BOOST_FOREACH(const Material
& mat
, vMaterials
)
573 OSG::UInt32 idx
= materialChunk
->addProperty();
575 materialChunk
->setVec3Property (idx
, Material:: ambient_id
, mat
.ambient
);
576 materialChunk
->setVec3Property (idx
, Material:: diffuse_id
, mat
.diffuse
);
577 materialChunk
->setVec3Property (idx
, Material:: specular_id
, mat
.specular
);
578 materialChunk
->setVec3Property (idx
, Material:: emissive_id
, mat
.emissive
);
580 materialChunk
->setFloatProperty(idx
, Material:: opacity_id
, mat
.opacity
);
581 materialChunk
->setFloatProperty(idx
, Material::shininess_id
, mat
.shininess
);
586 for (OSG::UInt32 idx
= 0; idx
< vMaterials
.size(); ++idx
)
588 const Material
& mat
= vMaterials
[idx
];
590 materialChunk
->setVec3Property (idx
, Material:: ambient_id
, mat
.ambient
);
591 materialChunk
->setVec3Property (idx
, Material:: diffuse_id
, mat
.diffuse
);
592 materialChunk
->setVec3Property (idx
, Material:: specular_id
, mat
.specular
);
593 materialChunk
->setVec3Property (idx
, Material:: emissive_id
, mat
.emissive
);
595 materialChunk
->setFloatProperty(idx
, Material:: opacity_id
, mat
.opacity
);
596 materialChunk
->setFloatProperty(idx
, Material::shininess_id
, mat
.shininess
);
603 // ii) the geomertry shader storage buffer object
605 OSG::MultiPropertyUBOChunkTransitPtr
create_geometry_material_state(const GeomState
& geomState
)
607 OSG::MultiPropertyUBOChunkRefPtr geomStateChunk
= OSG::MultiPropertyUBOChunk::create();
609 GeomState::material_index_id
= geomStateChunk
->addMember(OSG::MultiPropertyUBOChunk::UINT_T
, 1);
610 geomStateChunk
->setUsage(GL_DYNAMIC_DRAW
);
612 OSG::UInt32 idx
= geomStateChunk
->addProperty();
613 geomStateChunk
->setUIntProperty(idx
, GeomState::material_index_id
, geomState
.material_index
);
615 return OSG::MultiPropertyUBOChunkTransitPtr(geomStateChunk
);
618 void update_geometry_material_state(OSG::MultiPropertyUBOChunk
* geomStateChunk
, const GeomState
& geomState
)
622 if (geomStateChunk
->getNumProperties() != 1)
624 geomStateChunk
->clearProperties();
626 OSG::UInt32 idx
= geomStateChunk
->addProperty();
627 geomStateChunk
->setUIntProperty(idx
, GeomState::material_index_id
, geomState
.material_index
);
631 geomStateChunk
->setUIntProperty( 0, GeomState::material_index_id
, geomState
.material_index
);
636 // ============================================================================
638 // Part: The application finally starts here
640 // ============================================================================
642 // UBO block binding points
643 const OSG::UInt32 geom_binding_point
= 0;
645 // SSBO block binding points
646 const OSG::UInt32 material_binding_point
= 0;
651 std::string
get_vp_program();
652 std::string
get_fp_program();
654 OSG::ShaderProgramRefPtr frag_shader
= NULL
;
659 OSG::NodeRefPtr scene_node
= NULL
;
662 // Cluster visualisation root node
664 OSG::NodeRefPtr cluster_geometry_root_node
= NULL
;
667 // The ClusterShadingStage
669 OSG::ClusterShadingStageRefPtr cluster_shading_stage
= NULL
;
670 OSG::NodeRefPtr cluster_shading_node
= NULL
;
675 OSG::HDR2StageRefPtr hdr_stage
= NULL
;
676 OSG::NodeRefPtr hdr_node
= NULL
;
679 // The material database for all visible geometry: objects, lights, stage box
681 OSG::MultiPropertySSBOChunkRefPtr ssbo_material_database
= NULL
;
684 // The mulit light chunk
686 OSG::MultiLightChunkRefPtr multi_light_chunk
= NULL
;
689 // The shader program variable chunk for the geom state
691 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk
= NULL
;
694 // Shader Storage buffer objects corresponding to transient shader blocks
696 std::vector
<OSG::MultiPropertyUBOChunkRefPtr
> ubo_geom_states
;
699 // A separate transformation for each object and a spline for the trajectory
701 std::vector
<OSG::NodeRefPtr
> geom_nodes
;
702 std::vector
<OSG::TransformRefPtr
> geom_trafos
;
703 std::vector
<OSG::SmoothCubicBezierSpline
> geom_curves
;
706 // Simulate some movement in the scene
708 void update_simulation()
711 // Simulation code: If enough time has passed perform a simulation step.
714 if (time_stamp
== 0) time_stamp
= OSG::getTimeStamp();
716 OSG::Time elapsed
= OSG::getTimeStampMsecs(OSG::getTimeStamp() - time_stamp
);
718 if (elapsed
> elapse_time_limit
)
720 OSG::Matrix matSimulation
;
722 simulation_param
+= simulation_delta
;
723 if (simulation_param
>= 1.f
)
724 simulation_param
= 0.f
;
726 if (simulate_geometry
)
728 std::size_t numCurves
= geom_curves
.size();
730 OSG_ASSERT(numCurves
== geom_trafos
.size());
732 for (std::size_t i
= 0; i
< numCurves
; ++i
)
734 matSimulation
= geom_curves
[i
].getFrame(simulation_param
);
735 geom_trafos
[i
]->setMatrix(matSimulation
);
741 BOOST_FOREACH(Light
& light
, lights
)
743 matSimulation
= light
.curve
.getFrame(simulation_param
, true);
744 light
.transform
->setMatrix(matSimulation
);
749 time_stamp
= OSG::getTimeStamp();
754 // Cluster shading stage ...
756 void setup_cluster_shading_stage()
758 if (cluster_shading_stage
)
761 // The multi light chunk must be known by the cluster shading stage
763 cluster_shading_stage
->setMultiLightChunk(multi_light_chunk
);
766 // Some values that determine the computational efficiency
768 cluster_shading_stage
->setMaxLightIndexListSize (light_index_list_size
);
769 cluster_shading_stage
->setMaxClusterLightCount (1024);
770 cluster_shading_stage
->setBlockSize (block_size
);
771 cluster_shading_stage
->setTileSize (tile_size
);
772 cluster_shading_stage
->setNumClusterZ (num_cluster_z
);
773 cluster_shading_stage
->setNearPlaneOffset (near_plane_offset
);
776 // UBO fragment/compute shader binding points
778 cluster_shading_stage
->setDispatchDataBindingPnt(1);
779 cluster_shading_stage
->setClusterDataBindingPnt (2);
782 // SSBO fragment/compute shader binding points
784 cluster_shading_stage
->setLightBindingPnt (1);
785 cluster_shading_stage
->setAffectedLightIndexListBindingPnt (2);
786 cluster_shading_stage
->setFrustumBindingPnt (3);
787 cluster_shading_stage
->setLightIndexListBindingPnt (4);
788 cluster_shading_stage
->setLightIndexCounterBindingPnt (5);
791 // Texture image fragment shader binding point
793 cluster_shading_stage
->setLightGridBindingPnt(0);
798 cluster_shading_stage
->setCalcFrustumsOnCPU ( Light::cpu_calc_frustums
);
799 cluster_shading_stage
->setCullLighsOnCPU ( Light::cpu_cull_lights
);
800 cluster_shading_stage
->setDisabled (!Light::use_light_index_list
);
804 void removeClusterShadingStage()
806 OSG::GroupRefPtr group
= OSG::Group::create();
807 cluster_shading_node
->setCore(group
);
809 cluster_shading_stage
= NULL
;
812 void createClusterShadingStage()
814 if (!cluster_shading_stage
)
816 cluster_shading_stage
= OSG::ClusterShadingStage::create();
817 setup_cluster_shading_stage();
820 if (cluster_shading_node
)
821 cluster_shading_node
->setCore(cluster_shading_stage
);
827 void setup_hdr_stage()
831 hdr_stage
->setApplyGamma (true);
832 hdr_stage
->setAccurateGamma (true);
834 hdr_stage
->setAdjustLuminance (false);
836 hdr_stage
->setPerformBloom (false);
837 hdr_stage
->setBloomBackground (false);
839 hdr_stage
->setForceBackground (true);
840 hdr_stage
->setUse_ITU_R_BT_709 (true);
841 hdr_stage
->setMipmapLevel (-1);
843 hdr_stage
->setTarget (OSG::HDR2Stage::COMPOSITE_TEXTURE
);
844 hdr_stage
->setCarryDepth (true);
846 hdr_stage
->setColorBufferInternalFormat (GL_RGBA16F
);
847 hdr_stage
->setColorBufferPixelFormat (GL_RGBA
);
848 hdr_stage
->setColorBufferType (GL_FLOAT
);
850 hdr_stage
->setDepthBufferInternalFormat (GL_DEPTH24_STENCIL8
);
851 hdr_stage
->setDepthBufferPixelFormat (GL_DEPTH_STENCIL
);
852 hdr_stage
->setDepthBufferType (GL_UNSIGNED_INT_24_8
);
854 hdr_stage
->setLumBufferInternalFormat (GL_R32F
);
855 hdr_stage
->setLumBufferPixelFormat (GL_RED
);
856 hdr_stage
->setLumBufferType (GL_FLOAT
);
858 hdr_stage
->setImageBufferInternalFormat (GL_RGB16F
);
859 hdr_stage
->setImageBufferPixelFormat (GL_RGB
);
860 hdr_stage
->setImageBufferType (GL_FLOAT
);
862 hdr_stage
->setNumSamples (0);
864 hdr_stage
->setBloomThreshold (2.0f
);
865 hdr_stage
->setBloomMagnitude (0.0f
);
866 hdr_stage
->setToneMappingMode (OSG::HDR2Stage::REINHARD_TONE_MAPPING
);
867 hdr_stage
->setExposure (0.0f
);
868 hdr_stage
->setKeyValue (0.18f
);
869 hdr_stage
->setAutoExposureMode (OSG::HDR2Stage::MANUAL
);
870 hdr_stage
->setWhiteLevel (5.0f
);
871 hdr_stage
->setFilmicShoulderStrenght (0.15f
);
872 hdr_stage
->setFilmicLinearStrength (0.5f
);
873 hdr_stage
->setFilmicLinearAngle (0.1f
);
874 hdr_stage
->setFilmicToeStrength (0.2f
);
875 hdr_stage
->setFilmicToeNumerator (0.02f
);
876 hdr_stage
->setFilmicToeDenominator (0.3f
);
877 hdr_stage
->setFilmicLinearWhite (11.2f
);
878 hdr_stage
->setSaturation (1.0f
);
879 hdr_stage
->setDragoBias (0.85f
);
880 hdr_stage
->setTau (1.25f
);
881 hdr_stage
->setNumTaps (4);
882 hdr_stage
->setBlurGaussSigma (0.8f
);
883 hdr_stage
->setUseLinChromCorrection (true);
887 void removeHDRStage()
889 OSG::GroupRefPtr group
= OSG::Group::create();
890 hdr_node
->setCore(group
);
895 void createHDRStage()
899 hdr_stage
= OSG::HDR2Stage::create();
904 hdr_node
->setCore(hdr_stage
);
910 void deinitialize_lights()
912 BOOST_FOREACH(const Light
& light
, lights
)
914 scene_node
->subChild(light
.beacon
);
920 void initialize_lights(OSG::UInt32 num
) // helper to create lights
922 deinitialize_lights();
924 for (OSG::UInt32 i
= 0; i
< num
; ++i
)
927 int n
= classic_die();
934 type
= OSG::MultiLight::POINT_LIGHT
;
938 type
= OSG::MultiLight::SPOT_LIGHT
;
942 type
= OSG::MultiLight::CINEMA_LIGHT
;
946 lights
.push_back(Light::create_light(type
));
948 lights
[i
].create_light_geometry(i
+1);
950 scene_node
->addChild(lights
[i
].beacon
);
953 if (Light::add_dir_test_lights
)
955 lights
.push_back(Light::create_light(OSG::MultiLight::DIRECTIONAL_LIGHT
, 0));
956 lights
.push_back(Light::create_light(OSG::MultiLight::DIRECTIONAL_LIGHT
, 1));
960 void change_spot_dir_lights()
962 for (std::size_t i
= 0; i
< lights
.size(); ++i
)
964 Light
& light
= lights
[i
];
966 switch (Light::force_spot_dir
)
968 case 0: light
.direction
= dice_unit_vector(); break;
969 case 1: light
.direction
= OSG::Vec3f(0, 0,-1); break;
970 case 2: light
.direction
= OSG::Vec3f(1, 0, 0); break;
971 case 3: light
.direction
= OSG::Vec3f(0,-1, 0); break;
972 case 4: light
.direction
= OSG::Vec3f(1, 0,-1); break;
973 case 5: light
.direction
= OSG::Vec3f(1,-1,-1); break;
976 static bool increase_flag
= true;
978 light
.direction
= Light::dir_test_case_6
;
979 light
.direction
.normalize();
981 OSG::Vec3f
e1(1,0,-1);
982 OSG::Vec3f
e2(0,0,-1);
984 if (Light::dir_test_case_6
.equals(e1
, OSG::Eps
))
985 increase_flag
= false;
986 if (Light::dir_test_case_6
.equals(e2
, OSG::Eps
))
987 increase_flag
= true;
990 Light::dir_test_case_6
+= OSG::Vec3f(0.1f
, 0.f
, 0.f
);
992 Light::dir_test_case_6
-= OSG::Vec3f(0.1f
, 0.f
, 0.f
);
997 static bool increase_flag
= true;
999 light
.direction
= Light::dir_test_case_7
;
1000 light
.direction
.normalize();
1002 OSG::Vec3f
e1(1,-1,-1);
1003 OSG::Vec3f
e2(0,0,-1);
1005 if (Light::dir_test_case_7
.equals(e1
, OSG::Eps
))
1006 increase_flag
= false;
1007 if (Light::dir_test_case_7
.equals(e2
, OSG::Eps
))
1008 increase_flag
= true;
1011 Light::dir_test_case_7
+= OSG::Vec3f(0.1f
, -0.1f
, 0.f
);
1013 Light::dir_test_case_7
-= OSG::Vec3f(0.1f
, -0.1f
, 0.f
);
1019 static bool increase_flag
= true;
1021 light
.direction
= Light::dir_test_case_8
;
1022 light
.direction
.normalize();
1024 OSG::Vec3f
e1(0,-1, 0);
1025 OSG::Vec3f
e2(0, 0,-1);
1027 if (Light::dir_test_case_8
.equals(e1
, OSG::Eps
))
1028 increase_flag
= false;
1029 if (Light::dir_test_case_8
.equals(e2
, OSG::Eps
))
1030 increase_flag
= true;
1033 Light::dir_test_case_8
+= OSG::Vec3f(0.f
, -0.1f
, 0.1f
);
1035 Light::dir_test_case_8
-= OSG::Vec3f(0.f
, -0.1f
, 0.1f
);
1045 lights
[i
].create_light_geometry(OSG::UInt32(i
+1));
1049 Light
Light::create_light(
1050 Type e
, // type of the light
1051 OSG::Int32 test_dir_light_type
) // for special testing directional lights
1055 l
.beacon
= OSG::makeCoredNode
<OSG::Transform
>(&l
.transform
);
1056 l
.transform
->setMatrix(OSG::Matrix::identity());
1058 OSG::Real32 L
= box_factor
* world_size
;
1060 switch (Light::force_spot_dir
)
1062 case 0: l
.direction
= dice_unit_vector(); break;
1063 case 1: l
.direction
= OSG::Vec3f(0, 0,-1); break;
1064 case 2: l
.direction
= OSG::Vec3f(1, 0, 0); break;
1065 case 3: l
.direction
= OSG::Vec3f(0,-1, 0); break;
1066 case 4: l
.direction
= OSG::Vec3f(1, 0,-1); break;
1067 case 5: l
.direction
= OSG::Vec3f(1,-1,-1); break;
1068 case 6: l
.direction
= OSG::Vec3f(0, 0,-1); break;
1069 case 7: l
.direction
= OSG::Vec3f(0, 0,-1); break;
1070 case 8: l
.direction
= OSG::Vec3f(0, 0,-1); break;
1074 Light::dir_test_case_6
= OSG::Vec3f(0,0,-1);
1075 Light::dir_test_case_7
= OSG::Vec3f(0,0,-1);
1076 Light::dir_test_case_8
= OSG::Vec3f(0,0,-1);
1078 l
.color
.setRandom();
1079 l
.intensity
= max_light_power
* small_die();
1080 l
.rangeCutOff
= L
* light_range_die();
1084 case OSG::MultiLight::POINT_LIGHT
:
1089 case OSG::MultiLight::DIRECTIONAL_LIGHT
:
1091 if (Light::add_dir_test_lights
)
1093 if (test_dir_light_type
== 0)
1094 l
.direction
= OSG::Vec3f(0,0,-1);
1095 if (test_dir_light_type
== 1)
1096 l
.direction
= OSG::Vec3f(0,0,1);
1103 case OSG::MultiLight::SPOT_LIGHT
:
1105 l
.spotlightAngle
= spot_die();
1109 case OSG::MultiLight::CINEMA_LIGHT
:
1111 l
.innerSuperEllipsesWidth
= light_ellipsis_radius_die();
1112 l
.innerSuperEllipsesHeight
= light_ellipsis_radius_die();
1114 float f
= light_ellipsis_radius_ratio_die();
1116 l
.outerSuperEllipsesWidth
= f
* l
.innerSuperEllipsesWidth
;
1117 l
.outerSuperEllipsesHeight
= f
* l
.innerSuperEllipsesHeight
;
1119 int n
= classic_die();
1124 l
.superEllipsesRoundness
= light_ellipsis_roundness_die1();
1128 l
.superEllipsesRoundness
= light_ellipsis_roundness_die2();
1132 l
.superEllipsesRoundness
= light_ellipsis_roundness_die3();
1136 l
.superEllipsesTwist
= light_ellipsis_twist_die();
1138 //std::cout << "d = (" << l.direction.x() << ", " << l.direction.y() << ", " << l.direction.z() << ")" << std::endl;
1139 //std::cout << "a = " << l.innerSuperEllipsesWidth << std::endl;
1140 //std::cout << "b = " << l.innerSuperEllipsesHeight << std::endl;
1141 //std::cout << "A = " << l.outerSuperEllipsesWidth << std::endl;
1142 //std::cout << "B = " << l.outerSuperEllipsesHeight << std::endl;
1143 //std::cout << "r = " << l.superEllipsesRoundness << std::endl;
1144 //std::cout << "w = " << l.superEllipsesTwist << std::endl;
1155 void Light::create_light_geometry(OSG::UInt32 material_idx
)
1157 if (!beacon
) return;
1159 beacon
->clearChildren();
1162 mat
.emissive
= color
;
1165 materials
[material_idx
] = mat
;
1167 OSG::ChunkMaterialRefPtr geomState
= OSG::ChunkMaterial::create();
1169 OSG::Real32 R
= rangeCutOff
;
1171 if (!correct_light_geometry
)
1176 case OSG::MultiLight::POINT_LIGHT
:
1178 OSG::GeometryRefPtr geometry
= OSG::makeSphereGeo(3, R
);
1179 OSG::NodeRefPtr node
= OSG::makeNodeFor(geometry
);
1181 GeomState geom
; geom
.material_index
= material_idx
; // material index used for light animiation
1182 OSG::MultiPropertyUBOChunkRefPtr uboGeomState
= create_geometry_material_state(geom
);
1183 geomState
->addChunk(uboGeomState
, geom_binding_point
); // buffer binding point
1184 geomState
->addChunk(shader_var_chunk
); // block binding point
1186 geometry
->setMaterial(geomState
);
1188 beacon
->addChild(node
);
1191 // Test: Add mini sphere at the origin of the point light sphere
1194 // OSG::GeometryRefPtr geometry = OSG::makeSphereGeo(6, 0.1);
1195 // OSG::NodeRefPtr node = OSG::makeNodeFor(geometry);
1197 // GeomState geom; geom.material_index = material_idx; // material index used for light animiation
1198 // OSG::MultiPropertyUBOChunkRefPtr uboGeomState = create_geometry_material_state(geom);
1199 // geomState->addChunk(uboGeomState, geom_binding_point); // buffer binding point
1200 // geomState->addChunk(shader_var_chunk); // block binding point
1202 // geometry->setMaterial(geomState);
1204 // beacon->addChild(node);
1209 case OSG::MultiLight::DIRECTIONAL_LIGHT
:
1214 case OSG::MultiLight::SPOT_LIGHT
:
1216 GeomState geom
; geom
.material_index
= material_idx
; // material index used for light animiation
1217 OSG::MultiPropertyUBOChunkRefPtr uboGeomState
= create_geometry_material_state(geom
);
1218 geomState
->addChunk(uboGeomState
, geom_binding_point
); // buffer binding point
1219 geomState
->addChunk(shader_var_chunk
); // block binding point
1223 OSG::GeometryRefPtr geometry
= OSG::makeSpotGeo(h
, OSG::osgDegree2Rad(spotlightAngle
), 24, 24);
1224 geometry
->setMaterial(geomState
);
1226 OSG::TransformRefPtr coneTrans
= OSG::Transform::create();
1229 OSG::MatrixRotateTowards(rotMat
, OSG::Vec3f(0.f
, 1.f
, 0.f
), direction
);
1230 coneTrans
->setMatrix(rotMat
);
1232 OSG::NodeRefPtr coneTransNode
= OSG::makeNodeFor(coneTrans
);
1233 OSG::NodeRefPtr coneNode
= OSG::makeNodeFor(geometry
);
1235 beacon
->addChild(coneTransNode
);
1236 coneTransNode
->addChild(coneNode
);
1239 // Create a help line to visualize the spot hit point on the wall
1241 if (Light::show_spot_dir_line
)
1243 OSG::GeometryRefPtr line_geometry
= OSG::makeCylinderGeo(30, 0.1f
, 24, true, true, true );
1244 line_geometry
->setMaterial(geomState
);
1246 OSG::TransformRefPtr line_translation
= OSG::Transform::create();
1247 OSG::Matrix matLineTrans
;
1248 matLineTrans
.setTranslate(OSG::Vec3f(0,-15,0));
1249 line_translation
->setMatrix(matLineTrans
);
1251 OSG::TransformRefPtr line_rotation
= OSG::Transform::create();
1252 OSG::Matrix matLineRot
;
1253 matLineRot
.setRotate(OSG::Quaternion(OSG::Vec3f(1,0,0), OSG::Pi
));
1254 line_rotation
->setMatrix(matLineRot
);
1256 OSG::NodeRefPtr lineRotationNode
= OSG::makeNodeFor(line_rotation
);
1257 OSG::NodeRefPtr lineTranslationNode
= OSG::makeNodeFor(line_translation
);
1258 OSG::NodeRefPtr lineGeometryNode
= OSG::makeNodeFor(line_geometry
);
1259 coneTransNode
->addChild(lineRotationNode
);
1260 lineRotationNode
->addChild(lineTranslationNode
);
1261 lineTranslationNode
->addChild(lineGeometryNode
);
1266 case OSG::MultiLight::CINEMA_LIGHT
:
1268 GeomState geom
; geom
.material_index
= material_idx
; // material index used for light animiation
1269 OSG::MultiPropertyUBOChunkRefPtr uboGeomState
= create_geometry_material_state(geom
);
1270 geomState
->addChunk(uboGeomState
, geom_binding_point
); // buffer binding point
1271 geomState
->addChunk(shader_var_chunk
); // block binding point
1275 OSG::GeometryRefPtr geometry
= OSG::makeCinemaGeo(
1276 outerSuperEllipsesWidth
,
1277 outerSuperEllipsesHeight
,
1278 superEllipsesRoundness
,
1279 OSG::osgDegree2Rad(superEllipsesTwist
),
1281 geometry
->setMaterial(geomState
);
1283 OSG::Matrix matLSFromWS
;
1285 OSG::Matrix matLightPos
;
1286 matLightPos
.setTranslate(position
);
1288 OSG::Matrix matLightDir
;
1289 OSG::Quaternion
rotLightDir(OSG::Vec3f(0.f
, 0.f
, 1.f
), -direction
);
1290 matLightDir
.setRotate(rotLightDir
);
1292 matLSFromWS
.mult (matLightPos
);
1293 matLSFromWS
.mult (matLightDir
);
1296 matRot
.setRotate(OSG::Quaternion(OSG::Vec3f(1,0,0), -0.5*OSG::Pi
));
1298 matLSFromWS
.mult(matRot
);
1300 OSG::TransformRefPtr coneTrans
= OSG::Transform::create();
1301 coneTrans
->setMatrix(matLSFromWS
);
1303 OSG::NodeRefPtr coneTransNode
= OSG::makeNodeFor(coneTrans
);
1304 OSG::NodeRefPtr coneNode
= OSG::makeNodeFor(geometry
);
1306 beacon
->addChild(coneTransNode
);
1307 coneTransNode
->addChild(coneNode
);
1310 // Create a help line to visualize the spot hit point on the wall
1312 if (Light::show_spot_dir_line
)
1314 OSG::GeometryRefPtr line_geometry
= OSG::makeCylinderGeo(30, 0.1f
, 24, true, true, true );
1315 line_geometry
->setMaterial(geomState
);
1317 OSG::TransformRefPtr line_translation
= OSG::Transform::create();
1318 OSG::Matrix matLineTrans
;
1319 matLineTrans
.setTranslate(OSG::Vec3f(0,-15,0));
1320 line_translation
->setMatrix(matLineTrans
);
1322 OSG::TransformRefPtr line_rotation
= OSG::Transform::create();
1323 OSG::Matrix matLineRot
;
1324 matLineRot
.setRotate(OSG::Quaternion(OSG::Vec3f(1,0,0), OSG::Pi
));
1325 line_rotation
->setMatrix(matLineRot
);
1327 OSG::NodeRefPtr lineRotationNode
= OSG::makeNodeFor(line_rotation
);
1328 OSG::NodeRefPtr lineTranslationNode
= OSG::makeNodeFor(line_translation
);
1329 OSG::NodeRefPtr lineGeometryNode
= OSG::makeNodeFor(line_geometry
);
1330 coneTransNode
->addChild(lineRotationNode
);
1331 lineRotationNode
->addChild(lineTranslationNode
);
1332 lineTranslationNode
->addChild(lineGeometryNode
);
1341 OSG::PolygonChunkRefPtr polygonChunk
= OSG::PolygonChunk::create();
1342 polygonChunk
->setFrontMode(GL_SMOOTH
);
1343 polygonChunk
->setBackMode(GL_SMOOTH
);
1344 polygonChunk
->setOffsetFactor(1.f
);
1345 polygonChunk
->setOffsetBias(1.f
);
1346 polygonChunk
->setOffsetFill(true);
1348 if (mat
.opacity
< 1.f
)
1350 polygonChunk
->setCullFace(GL_BACK
);
1352 OSG::BlendChunkRefPtr blendChunk
= OSG::BlendChunk::create();
1353 blendChunk
->setSrcFactor (GL_SRC_ALPHA
);
1354 blendChunk
->setDestFactor(GL_ONE_MINUS_SRC_ALPHA
);
1355 geomState
->addChunk(blendChunk
);
1356 geomState
->setTransparencyMode(OSG::Material::TransparencyForceTransparent
);
1358 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk
= OSG::TwoSidedLightingChunk::create();
1359 geomState
->addChunk(twoSidedLightingChunk
);
1362 polygonChunk
->setCullFace(GL_BACK
);
1363 geomState
->setTransparencyMode(OSG::Material::TransparencyForceOpaque
);
1366 geomState
->addChunk(polygonChunk
);
1369 OSG::NodeTransitPtr
createBox()
1371 OSG::NodeRefPtr boxRoot
= OSG::makeCoredNode
<OSG::Group
>();
1373 OSG::Real32 L
= box_factor
* world_size
;
1374 OSG::GeometryRefPtr boxPlane
= OSG::makePlaneGeo(2.f
*L
, 2.f
*L
, 128, 128);
1376 OSG::NodeRefPtr boxBottom
= OSG::makeNodeFor(boxPlane
);
1377 OSG::NodeRefPtr boxLeft
= OSG::makeNodeFor(boxPlane
);
1378 OSG::NodeRefPtr boxRight
= OSG::makeNodeFor(boxPlane
);
1379 OSG::NodeRefPtr boxFar
= OSG::makeNodeFor(boxPlane
);
1381 OSG::TransformRefPtr boxBottomTrans
= OSG::Transform::create();
1382 OSG::TransformRefPtr boxLeftTrans
= OSG::Transform::create();
1383 OSG::TransformRefPtr boxRightTrans
= OSG::Transform::create();
1384 OSG::TransformRefPtr boxFarTrans
= OSG::Transform::create();
1386 OSG::Matrix matBottom
, matLeft
, matRight
, matFar
;
1388 matBottom
.setTransform(OSG::Vec3f(0.f
, -L
, 0.f
), OSG::Quaternion( OSG::Vec3f(1, 0, 0), OSG::osgDegree2Rad(270.f
)));
1389 matLeft
.setTransform(OSG::Vec3f( -L
, 0.f
, 0.f
), OSG::Quaternion( OSG::Vec3f(0, 1, 0), OSG::osgDegree2Rad(90.f
)));
1390 matRight
.setTransform(OSG::Vec3f( L
, 0.f
, 0.f
), OSG::Quaternion( OSG::Vec3f(0, 1, 0), OSG::osgDegree2Rad(270.f
)));
1391 matFar
.setTransform(OSG::Vec3f(0.f
, 0.f
, -L
), OSG::Quaternion( OSG::Vec3f(0, 0, 1), OSG::osgDegree2Rad( 0.f
)));
1393 boxBottomTrans
->setMatrix(matBottom
);
1394 boxLeftTrans
->setMatrix(matLeft
);
1395 boxRightTrans
->setMatrix(matRight
);
1396 boxFarTrans
->setMatrix(matFar
);
1398 OSG::NodeRefPtr boxBottomTransNode
= OSG::makeNodeFor(boxBottomTrans
);
1399 OSG::NodeRefPtr boxLeftTransNode
= OSG::makeNodeFor(boxLeftTrans
);
1400 OSG::NodeRefPtr boxRightTransNode
= OSG::makeNodeFor(boxRightTrans
);
1401 OSG::NodeRefPtr boxFarTransNode
= OSG::makeNodeFor(boxFarTrans
);
1403 boxBottomTransNode
->addChild(boxBottom
);
1404 boxLeftTransNode
->addChild(boxLeft
);
1405 boxRightTransNode
->addChild(boxRight
);
1406 boxFarTransNode
->addChild(boxFar
);
1408 boxRoot
->addChild(boxBottomTransNode
);
1409 boxRoot
->addChild(boxLeftTransNode
);
1410 boxRoot
->addChild(boxRightTransNode
);
1411 boxRoot
->addChild(boxFarTransNode
);
1413 GeomState geom
; geom
.material_index
= 0; // grey box material index
1414 OSG::ChunkMaterialRefPtr geomState
= OSG::ChunkMaterial::create();
1415 OSG::MultiPropertyUBOChunkRefPtr uboGeomState
= create_geometry_material_state(geom
);
1416 geomState
->addChunk(uboGeomState
, geom_binding_point
); // buffer binding point
1417 geomState
->addChunk(shader_var_chunk
); // block binding point
1419 OSG::PolygonChunkRefPtr polygonChunk
= OSG::PolygonChunk::create();
1420 polygonChunk
->setFrontMode(GL_SMOOTH
);
1421 polygonChunk
->setBackMode(GL_SMOOTH
);
1422 polygonChunk
->setOffsetFactor(1.f
);
1423 polygonChunk
->setOffsetBias(1.f
);
1424 polygonChunk
->setOffsetFill(true);
1425 polygonChunk
->setCullFace(GL_NONE
);
1426 geomState
->addChunk(polygonChunk
);
1428 geomState
->setTransparencyMode(OSG::Material::TransparencyForceOpaque
);
1430 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk
= OSG::TwoSidedLightingChunk::create();
1431 geomState
->addChunk(twoSidedLightingChunk
);
1433 boxPlane
->setMaterial(geomState
);
1435 return OSG::NodeTransitPtr(boxRoot
);
1438 OSG::NodeTransitPtr
createGeometry()
1440 int idx
= geom_idx_die();
1442 OSG::GeometryRefPtr geometry
;
1447 geometry
= OSG::makeConeGeo(3.f
* small_die(), 1.f
* small_die(), 24, true, true);
1450 geometry
= OSG::makeBoxGeo(3.f
* small_die(), 3.f
* small_die(), 3.f
* small_die(), 1, 1, 1);
1453 geometry
= OSG::makeCylinderGeo(3.f
* small_die(), .3f
, 24, true, true, true );
1456 geometry
= OSG::makeSphereGeo(6, 3.f
* small_die());
1459 geometry
= OSG::makeTorusGeo(0.6f
* small_die(), 2.f
* small_die(), 24, 36);
1461 case 5: // ellipsoide
1462 geometry
= OSG::makeLatLongEllipsoidGeo(24, 36, 2.f
* small_die(), 1.f
* small_die());
1465 geometry
= OSG::makeConicalFrustumGeo(2.f
* small_die(), 2.f
* small_die(), 2.f
* small_die(), 6, true, true, true);
1468 geometry
= OSG::makeTeapotGeo(24, 1.f
* small_die());
1472 OSG::NodeRefPtr geomNode
= OSG::makeNodeFor(geometry
);
1474 OSG::TransformRefPtr trafoCore
= OSG::Transform::create();
1475 OSG::NodeRefPtr transNode
= OSG::makeNodeFor(trafoCore
);
1476 transNode
->addChild(geomNode
);
1478 GeomState geom
; geom
.material_index
= material_idx_die();
1479 OSG::ChunkMaterialRefPtr geomState
= OSG::ChunkMaterial::create();
1480 OSG::MultiPropertyUBOChunkRefPtr uboGeomState
= create_geometry_material_state(geom
);
1481 geomState
->addChunk(uboGeomState
, geom_binding_point
); // buffer binding point
1482 geomState
->addChunk(shader_var_chunk
); // block binding point
1484 OSG::PolygonChunkRefPtr polygonChunk
= OSG::PolygonChunk::create();
1485 polygonChunk
->setFrontMode(GL_SMOOTH
);
1486 polygonChunk
->setBackMode(GL_SMOOTH
);
1487 polygonChunk
->setOffsetFactor(1.f
);
1488 polygonChunk
->setOffsetBias(1.f
);
1489 polygonChunk
->setOffsetFill(true);
1491 OSG::Real32 opacity
= materials
[geom
.material_index
].opacity
;
1494 polygonChunk
->setCullFace(GL_BACK
);
1496 OSG::BlendChunkRefPtr blendChunk
= OSG::BlendChunk::create();
1497 blendChunk
->setSrcFactor (GL_SRC_ALPHA
);
1498 blendChunk
->setDestFactor(GL_ONE_MINUS_SRC_ALPHA
);
1499 geomState
->addChunk(blendChunk
);
1500 geomState
->setTransparencyMode(OSG::Material::TransparencyForceTransparent
);
1502 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk
= OSG::TwoSidedLightingChunk::create();
1503 geomState
->addChunk(twoSidedLightingChunk
);
1506 polygonChunk
->setCullFace(GL_BACK
);
1507 geomState
->setTransparencyMode(OSG::Material::TransparencyForceOpaque
);
1510 geomState
->addChunk(polygonChunk
);
1512 geometry
->setMaterial(geomState
);
1514 geom_nodes
.push_back(transNode
);
1515 geom_trafos
.push_back(trafoCore
);
1516 ubo_geom_states
.push_back(uboGeomState
);
1518 geom_curves
.push_back(OSG::SmoothCubicBezierSpline(dice_knots(true)));
1520 return OSG::NodeTransitPtr(transNode
);
1524 // forward declaration so we can have the interesting stuff upfront
1526 int setupGLUT (int *argc
, char *argv
[]);
1532 // Initialize GLUT & OpenSG and set up the scene
1534 int main(int argc
, char **argv
)
1537 OSG::osgInit(argc
,argv
);
1540 int winid
= setupGLUT(&argc
, argv
);
1544 // open a new scope, because the pointers below should go out of scope
1545 // before entering glutMainLoop.
1546 // Otherwise OpenSG will complain about objects being alive after shutdown.
1548 // the connection between GLUT and OpenSG
1549 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
1550 gwin
->setGlutId(winid
);
1553 // create the SimpleSceneManager helper
1554 mgr
= OSG::SimpleSceneManager::create();
1555 mgr
->setWindow(gwin
);
1558 // Because we animate the lights by simple geometry, the lights initialization must be happens
1559 // after the creation of the 'shader_var_chunk' and after the creation of the scene node that
1560 // actually contains the geometry. Additionally, it must happens before we call 'create_light_state',
1561 // since here we do need the already defined lights.
1564 cluster_shading_node
= OSG::makeCoredNode
<OSG::Group
>();
1565 hdr_node
= OSG::makeCoredNode
<OSG::Group
>();
1568 // The block binding is added to each ChunkMaterial in order to provide the state
1569 // shader uniform block for the geometery shown in the scene
1571 shader_var_chunk
= OSG::ShaderProgramVariableChunk::create();
1572 shader_var_chunk
->addUniformBlock("GeomState", geom_binding_point
);
1575 // The scene does contain all visible rendering. It will be append to the hdr node.
1577 scene_node
= OSG::makeCoredNode
<OSG::Group
>();
1579 initialize_lights(init_num_lights
);
1582 // create shader storage buffer objects and corresponding materials
1584 ssbo_material_database
= create_material_database_state(materials
);
1585 multi_light_chunk
= create_light_state(lights
);
1587 hdr_node
->addChild(cluster_shading_node
);
1588 cluster_shading_node
->addChild(scene_node
);
1593 mgr
->setRoot(hdr_node
);
1595 if (use_ortho_camera
)
1597 OSG::OrthographicCameraRefPtr orthoCamera
= OSG::OrthographicCamera::create();
1598 mgr
->setCamera(orthoCamera
);
1602 createClusterShadingStage();
1605 // create the shader program
1607 OSG::ShaderProgramChunkRefPtr progChunk
= OSG::ShaderProgramChunk::create();
1608 OSG::ShaderProgramRefPtr vertShader
= OSG::ShaderProgram::createVertexShader();
1609 frag_shader
= OSG::ShaderProgram::createFragmentShader();
1611 vertShader
->setProgram(get_vp_program());
1612 frag_shader
->setProgram(get_fp_program());
1614 frag_shader
->addOSGVariable("OSGViewMatrix");
1617 // binding the shader storage block to a buffer binding point can be performed
1618 // either by calling the shaders's addShaderStorageBlock method or by
1619 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
1620 // In the following we use both variants for illustration.
1622 frag_shader
->addShaderStorageBlock("Materials",
1623 material_binding_point
);
1625 progChunk
->addShader( vertShader
);
1626 progChunk
->addShader(frag_shader
);
1628 OSG::PolygonChunkRefPtr polygonChunk
= OSG::PolygonChunk::create();
1629 polygonChunk
->setFrontMode(GL_FILL
);
1630 polygonChunk
->setBackMode(GL_FILL
);
1631 polygonChunk
->setCullFace(GL_BACK
);
1633 OSG::DepthChunkRefPtr depthChunk
= OSG::DepthChunk::create();
1634 depthChunk
->setEnable(true);
1636 OSG::ChunkMaterialRefPtr progState
= OSG::ChunkMaterial::create();
1637 progState
->addChunk(ssbo_material_database
, material_binding_point
);
1639 progState
->addChunk(progChunk
);
1640 progState
->addChunk(polygonChunk
);
1641 progState
->addChunk(depthChunk
);
1643 scene_node
->addChild(createBox());
1645 cluster_geometry_root_node
= OSG::makeCoredNode
<OSG::Group
>();
1646 scene_node
->addChild(cluster_geometry_root_node
);
1648 for (OSG::Int32 i
= 0; i
< init_num_geometries
; ++i
)
1649 scene_node
->addChild(createGeometry());
1651 OSG::MaterialChunkOverrideGroupRefPtr mgrp
= OSG::MaterialChunkOverrideGroup::create();
1652 mgrp
->setMaterial(progState
);
1653 scene_node
->setCore(mgrp
);
1655 OSG::commitChanges();
1659 // show the whole scene
1670 // GLUT callback functions
1674 // redraw the window
1683 update_simulation();
1685 OSG::commitChanges();
1691 // react to size changes
1693 void reshape(int w
, int h
)
1697 glutPostRedisplay();
1701 // react to mouse button presses
1703 void mouse(int button
, int state
, int x
, int y
)
1706 mgr
->mouseButtonRelease(button
, x
, y
);
1708 mgr
->mouseButtonPress(button
, x
, y
);
1710 glutPostRedisplay();
1714 // react to mouse motions with pressed buttons
1716 void motion(int x
, int y
)
1718 mgr
->mouseMove(x
, y
);
1719 glutPostRedisplay();
1725 void keyboard(unsigned char k
, int x
, int y
)
1731 // clean up global variables
1737 cluster_geometry_root_node
= NULL
;
1739 cluster_shading_stage
= NULL
;
1740 cluster_shading_node
= NULL
;
1745 ssbo_material_database
= NULL
;
1747 multi_light_chunk
= NULL
;
1748 shader_var_chunk
= NULL
;
1751 geom_trafos
.clear();
1752 geom_curves
.clear();
1754 ubo_geom_states
.clear();
1768 simulate_geometry
= !simulate_geometry
;
1769 std::cout
<< "simulate_geometry = " << simulate_geometry
<< std::endl
;
1775 initialize_lights(1);
1776 update_light_state(multi_light_chunk
, lights
);
1777 update_material_database_state(ssbo_material_database
, materials
);
1778 glutPostRedisplay();
1784 if (lights
.size() > 1)
1786 OSG::UInt32 num
= static_cast<OSG::UInt32
>(lights
.size() / 2);
1787 initialize_lights(num
);
1788 update_light_state(multi_light_chunk
, lights
);
1789 update_material_database_state(ssbo_material_database
, materials
);
1791 std::cout
<< "number if lights = " << num
<< std::endl
;
1793 glutPostRedisplay();
1797 std::cout
<< "minimal number if lights reached!" << std::endl
;
1804 if (lights
.size() <= max_num_lights
)
1806 OSG::UInt32 num
= static_cast<OSG::UInt32
>(lights
.size() * 2);
1807 initialize_lights(num
);
1808 update_light_state(multi_light_chunk
, lights
);
1809 update_material_database_state(ssbo_material_database
, materials
);
1811 std::cout
<< "number if lights = " << num
<< std::endl
;
1813 glutPostRedisplay();
1817 std::cout
<< "maximal number if lights reached!" << std::endl
;
1825 if (geom_nodes
.size() > 1)
1827 OSG::UInt32 num
= static_cast<OSG::UInt32
>(geom_nodes
.size() / 2);
1829 BOOST_FOREACH(OSG::Node
* node
, geom_nodes
)
1830 scene_node
->subChild(node
);
1833 geom_trafos
.clear();
1834 geom_curves
.clear();
1835 ubo_geom_states
.clear();
1837 for (OSG::UInt32 i
= 0; i
< num
; ++i
)
1838 scene_node
->addChild(createGeometry());
1840 std::cout
<< "number if geometries = " << num
<< std::endl
;
1842 glutPostRedisplay();
1846 std::cout
<< "minimal number if geometries reached!" << std::endl
;
1853 if (geom_nodes
.size() <= max_num_geometries
)
1855 OSG::UInt32 num
= static_cast<OSG::UInt32
>(geom_nodes
.size() * 2);
1857 BOOST_FOREACH(OSG::Node
* node
, geom_nodes
)
1858 scene_node
->subChild(node
);
1861 geom_trafos
.clear();
1862 geom_curves
.clear();
1863 ubo_geom_states
.clear();
1865 for (OSG::UInt32 i
= 0; i
< num
; ++i
)
1866 scene_node
->addChild(createGeometry());
1868 std::cout
<< "number if geometries = " << num
<< std::endl
;
1870 glutPostRedisplay();
1874 std::cout
<< "maximal number if geometries reached!" << std::endl
;
1881 Light::add_dir_test_lights
= !Light::add_dir_test_lights
;
1882 std::cout
<< "Light::add_dir_test_lights = " << Light::add_dir_test_lights
<< std::endl
;
1884 initialize_lights(1);
1885 update_light_state(multi_light_chunk
, lights
);
1886 update_material_database_state(ssbo_material_database
, materials
);
1887 glutPostRedisplay();
1893 Light::correct_light_geometry
= !Light::correct_light_geometry
;
1894 std::cout
<< "Light::correct_light_geometry = " << Light::correct_light_geometry
<< std::endl
;
1896 for (std::size_t i
= 0; i
< lights
.size(); ++i
)
1898 Light
& light
= lights
[i
];
1899 light
.create_light_geometry(OSG::UInt32(i
+1));
1902 glutPostRedisplay();
1908 Light::cpu_cull_lights
= !Light::cpu_cull_lights
;
1909 std::cout
<< "Light::cpu_cull_lights = " << Light::cpu_cull_lights
<< std::endl
;
1911 cluster_shading_stage
->setCullLighsOnCPU(Light::cpu_cull_lights
);
1913 if (Light::cpu_cull_lights
&& !Light::cpu_calc_frustums
)
1915 Light::cpu_calc_frustums
= true;
1916 std::cout
<< "Light::cpu_calc_frustums = " << Light::cpu_calc_frustums
<< std::endl
;
1917 cluster_shading_stage
->setCalcFrustumsOnCPU(Light::cpu_calc_frustums
);
1919 glutPostRedisplay();
1925 Light::cpu_calc_frustums
= !Light::cpu_calc_frustums
;
1926 std::cout
<< "Light::cpu_calc_frustums = " << Light::cpu_calc_frustums
<< std::endl
;
1928 cluster_shading_stage
->setCalcFrustumsOnCPU(Light::cpu_calc_frustums
);
1930 if (Light::cpu_cull_lights
&& !Light::cpu_calc_frustums
)
1932 Light::cpu_cull_lights
= false;
1933 std::cout
<< "Light::cpu_cull_lights = " << Light::cpu_cull_lights
<< std::endl
;
1934 cluster_shading_stage
->setCullLighsOnCPU(Light::cpu_cull_lights
);
1936 glutPostRedisplay();
1942 simulation_delta
*= 2.f
;
1948 simulation_delta
/= 2.f
;
1954 OSG::HDR2Stage
* core
= dynamic_cast<OSG::HDR2Stage
*>(hdr_node
->getCore());
1959 std::cout
<< "HDR is off" << std::endl
;
1965 std::cout
<< "HDR is on" << std::endl
;
1968 glutPostRedisplay();
1974 BOOST_FOREACH(Light
& light
, lights
)
1975 light
.intensity
*= 1.2f
;
1977 update_light_state(multi_light_chunk
, lights
);
1978 glutPostRedisplay();
1984 BOOST_FOREACH(Light
& light
, lights
)
1985 if (light
.rangeCutOff
/ intensityFactor
>= OSG::Eps
)
1986 light
.intensity
/= intensityFactor
;
1988 update_light_state(multi_light_chunk
, lights
);
1989 glutPostRedisplay();
1995 simulate_lights
= !simulate_lights
;
1996 std::cout
<< "simulate_lights = " << simulate_lights
<< std::endl
;
2002 BOOST_FOREACH(OSG::MultiPropertyUBOChunk
* uboGeomState
, ubo_geom_states
)
2004 GeomState geom
; geom
.material_index
= material_idx_die();
2005 update_geometry_material_state(uboGeomState
, geom
);
2008 glutPostRedisplay();
2014 elapse_time_limit
*= 2.f
;
2020 elapse_time_limit
/= 2.f
;
2026 for (std::size_t i
= 0; i
< lights
.size(); ++i
)
2028 Light
& light
= lights
[i
];
2030 light
.rangeCutOff
*= rangeFactor
;
2031 light
.create_light_geometry(OSG::UInt32(i
+1));
2034 update_light_state(multi_light_chunk
, lights
);
2035 glutPostRedisplay();
2041 for (std::size_t i
= 0; i
< lights
.size(); ++i
)
2043 Light
& light
= lights
[i
];
2045 if (light
.rangeCutOff
/ rangeFactor
>= OSG::Eps
)
2047 light
.rangeCutOff
/= rangeFactor
;
2048 light
.create_light_geometry(OSG::UInt32(i
+1));
2052 update_light_state(multi_light_chunk
, lights
);
2053 glutPostRedisplay();
2059 initialize_lights(init_num_lights
);
2060 update_light_state(multi_light_chunk
, lights
);
2061 update_material_database_state(ssbo_material_database
, materials
);
2063 simulation_delta
= 0.0001f
;
2064 elapse_time_limit
= 10.f
;
2066 simulate_geometry
= true;
2067 simulate_lights
= true;
2069 std::cout
<< "example resetted" << std::endl
;
2071 glutPostRedisplay();
2077 mgr
->setStatistics(!mgr
->getStatistics());
2083 Light::use_light_index_list
= !Light::use_light_index_list
;
2084 std::cout
<< "Light::use_light_index_list = " << Light::use_light_index_list
<< std::endl
;
2085 cluster_shading_stage
->setDisabled(!Light::use_light_index_list
);
2086 glutPostRedisplay();
2092 Light::show_spot_dir_line
= !Light::show_spot_dir_line
;
2093 std::cout
<< "Light::show_spot_dir_line = " << Light::show_spot_dir_line
<< std::endl
;
2095 for (std::size_t i
= 0; i
< lights
.size(); ++i
)
2097 Light
& light
= lights
[i
];
2098 light
.create_light_geometry(OSG::UInt32(i
+1));
2101 glutPostRedisplay();
2107 Light::force_spot_dir
+= 1;
2108 if (Light::force_spot_dir
> 9)
2109 Light::force_spot_dir
= 0;
2111 std::cout
<< "Light::force_spot_dir = ";
2113 switch (Light::force_spot_dir
)
2115 case 0: std::cout
<< "dice"; break;
2116 case 1: std::cout
<< "(0, 0,-1)"; break;
2117 case 2: std::cout
<< "(1, 0, 0)"; break;
2118 case 3: std::cout
<< "(0,-1, 0)"; break;
2119 case 4: std::cout
<< "(1, 0,-1)"; break;
2120 case 5: std::cout
<< "(1,-1,-1)"; break;
2121 case 6: std::cout
<< "from (0,0,-1) to (1,0,-1)"; break;
2122 case 7: std::cout
<< "from (0,0,-1) to (1,-1,-1)"; break;
2123 case 8: std::cout
<< "from (0,0,-1) to (0,-1, 0)"; break;
2124 case 9: std::cout
<< "recreate"; break;
2127 std::cout
<< std::endl
;
2133 change_spot_dir_lights();
2134 update_light_state(multi_light_chunk
, lights
);
2135 update_material_database_state(ssbo_material_database
, materials
);
2136 glutPostRedisplay();
2144 // setup the GLUT library which handles the windows for us
2146 int setupGLUT(int *argc
, char *argv
[])
2148 glutInit(argc
, argv
);
2149 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
2150 glutInitWindowSize(1000, 800);
2152 int winid
= glutCreateWindow("OpenSG");
2154 glutReshapeFunc(reshape
);
2155 glutDisplayFunc(display
);
2156 glutMouseFunc(mouse
);
2157 glutMotionFunc(motion
);
2158 glutKeyboardFunc(keyboard
);
2160 // call the redraw function whenever there's nothing else to do
2161 glutIdleFunc(display
);
2168 glutReshapeFunc(NULL
);
2169 glutMouseFunc(NULL
);
2170 glutMotionFunc(NULL
);
2171 glutKeyboardFunc(NULL
);
2177 std::cout
<< "simulate_geometry = " << simulate_geometry
<< std::endl
;
2178 std::cout
<< "simulate_lights = " << simulate_lights
<< std::endl
;
2179 std::cout
<< "number if lights = " << lights
.size() << std::endl
;
2180 std::cout
<< "number if geometries = " << geom_nodes
.size() << std::endl
;
2181 std::cout
<< "Light::use_light_index_list = " << Light::use_light_index_list
<< std::endl
;
2182 std::cout
<< "Light::add_dir_test_lights = " << Light::add_dir_test_lights
<< std::endl
;
2183 std::cout
<< "Light::correct_light_geometry = " << Light::correct_light_geometry
<< std::endl
;
2184 std::cout
<< "Light::show_spot_dir_line = " << Light::show_spot_dir_line
<< std::endl
;
2185 std::cout
<< "Light::cpu_cull_lights = " << Light::cpu_cull_lights
<< std::endl
;
2186 std::cout
<< "Light::cpu_calc_frustums = " << Light::cpu_calc_frustums
<< std::endl
;
2187 std::cout
<< "HDR is " << (dynamic_cast<OSG::HDR2Stage
*>(hdr_node
->getCore()) != NULL
? "on" : "off") << std::endl
;
2188 std::cout
<< "visualize_frustum = " << visualize_frustum
<< std::endl
;
2193 std::cout
<< "Esc : quit example" << std::endl
;
2194 std::cout
<< "Space : toogle geometry simulation on/off" << std::endl
;
2195 std::cout
<< "1 : only one light" << std::endl
;
2196 std::cout
<< "2 : half number of lights" << std::endl
;
2197 std::cout
<< "3 : double number of lights" << std::endl
;
2198 std::cout
<< "4 : half number of geometry objects" << std::endl
;
2199 std::cout
<< "5 : double number of geometry objects" << std::endl
;
2200 std::cout
<< "a : add directional test lights" << std::endl
;
2201 std::cout
<< "b : show correct light geometry" << std::endl
;
2202 std::cout
<< "c : cull lights on cpu" << std::endl
;
2203 std::cout
<< "C : calc frustums on cpu" << std::endl
;
2204 std::cout
<< "e/E : speed up/down simulation" << std::endl
;
2205 std::cout
<< "h : toogle HDR stage usage on/off" << std::endl
;
2206 std::cout
<< "i/I : increase/decrease light intensity" << std::endl
;
2207 std::cout
<< "l : toogle light simulation on/off" << std::endl
;
2208 std::cout
<< "m : assign new color to geometry" << std::endl
;
2209 std::cout
<< "o/O : double/half simulation time interval" << std::endl
;
2210 std::cout
<< "p/P : increase/decrease light range" << std::endl
;
2211 std::cout
<< "r : reset the example" << std::endl
;
2212 std::cout
<< "s : toogle statistics on/off" << std::endl
;
2213 std::cout
<< "t : toogle usage of cluster shading on/off" << std::endl
;
2214 std::cout
<< "u : toggle spot direction line on/off" << std::endl
;
2215 std::cout
<< "U : toggle special spot direction cases" << std::endl
;
2216 std::cout
<< "x : recreate the lights with current spot dir case" << std::endl
;
2219 // ============================================================================
2221 // Part: dice_knots helper implementation
2223 // ============================================================================
2225 typedef boost::tuples::tuple
<int, int, int> index_t
;
2227 struct index_hash_t
: public std::unary_function
<index_t
, std::size_t>
2229 std::size_t operator()(const index_t
& v
) const
2231 std::size_t seed
= 0;
2232 boost::hash_combine(seed
, v
.get
<0>());
2233 boost::hash_combine(seed
, v
.get
<1>());
2234 boost::hash_combine(seed
, v
.get
<2>());
2239 std::vector
<OSG::Pnt3f
> dice_knots(bool close_curve
)
2242 // idea: sample a number if different cube boxes from the scene and
2243 // take randomly one point from each cube. That guarantees that
2244 // the knot points do not clump and that they are all unequal.
2246 namespace tp
= boost::tuples
;
2248 boost::unordered_set
<index_t
, index_hash_t
> indices
;
2250 while (indices
.size() < num_curve_knots
)
2252 indices
.insert(tp::make_tuple(box_idx_die(), box_idx_die(), box_idx_die()));
2255 OSG::Real32 l
= 2 * world_size
/ num_grid_boxes
;
2257 std::vector
<OSG::Pnt3f
> knots
;
2259 BOOST_FOREACH(const index_t
& idx
, indices
)
2262 p
[0] = -world_size
+ idx
.get
<0>() * l
+ unit_die() * l
;
2263 p
[1] = -world_size
+ idx
.get
<1>() * l
+ unit_die() * l
;
2264 p
[2] = -world_size
+ idx
.get
<2>() * l
+ unit_die() * l
;
2270 knots
.push_back(knots
.front());
2275 // ============================================================================
2277 // Part: The shader programs
2279 // ============================================================================
2282 // vertex shader program.
2284 std::string
get_vp_program()
2286 using namespace std
;
2290 ost
<< "#version 440 compatibility"
2292 << endl
<< "#extension GL_ARB_shader_storage_buffer_object: enable"
2294 << endl
<< "smooth out vec3 vNormalES; // eye space normal"
2295 << endl
<< "smooth out vec3 vPositionES; // eye space position"
2297 << endl
<< "void main()"
2300 << endl
<< " // multiply the object space vertex position with the modelview matrix "
2301 << endl
<< " // to get the eye space vertex position"
2303 << endl
<< " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;"
2306 << endl
<< " // multiply the object space normal with the normal matrix (transpose of the inverse "
2307 << endl
<< " // model view matrix) to get the eye space normal"
2309 << endl
<< " vNormalES = gl_NormalMatrix * gl_Normal;"
2312 << endl
<< " // multiply the combiend modelview projection matrix with the object space vertex"
2313 << endl
<< " // position to get the clip space position"
2315 << endl
<< " gl_Position = ftransform();"
2324 // fragment shader program for bump mapping in surface local coordinates
2326 std::string
get_fp_program()
2328 using namespace std
;
2333 << "#version 440 compatibility"
2335 << endl
<< "#extension GL_ARB_shader_storage_buffer_object: enable"
2336 << endl
<< "#extension GL_ARB_shader_image_load_store: enable"
2338 << endl
<< "smooth in vec3 vNormalES; // eye space normal"
2339 << endl
<< "smooth in vec3 vPositionES; // eye space position"
2341 << endl
<< "const int num_materials = " << num_materials
<< ";"
2343 << endl
<< "uniform mat4 OSGViewMatrix; // from world space to view space transformation"
2345 << cluster_shading_stage
->getFragmentProgramSnippet()
2347 << endl
<< "struct Material"
2349 << endl
<< " vec3 ambient;"
2350 << endl
<< " vec3 diffuse;"
2351 << endl
<< " vec3 specular;"
2352 << endl
<< " vec3 emissive;"
2354 << endl
<< " float opacity;"
2355 << endl
<< " float shininess;"
2358 << endl
<< "layout (std430) buffer Materials"
2360 << endl
<< " Material material[num_materials];"
2361 << endl
<< "} materials;"
2364 << endl
<< "layout (std140) uniform GeomState"
2366 << endl
<< " uint material_index;"
2367 << endl
<< "} geom_state;"
2369 << endl
<< "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!"
2371 << endl
<< "layout(location = 0) out vec4 vFragColor;"
2374 << endl
<< "// Calculate the attenuation of the light based on the light "
2375 << endl
<< "// range r and the distance d of the light to the current point."
2377 << endl
<< "float calcAttenuation("
2378 << endl
<< " in const float r,"
2379 << endl
<< " in const float d)"
2382 << endl
<< " // Perform smooth Hermite interpolation between 0 and 1, when e0<x<e1"
2383 << endl
<< " // float t = clamp((x-e0)/(e1-e0),0.0,1.0);"
2384 << endl
<< " // smoothstep(e0,e1,x) = t*t*(3-2*t);"
2386 << endl
<< " return 1.0 - smoothstep(0.75 * r, r, d);"
2390 << endl
<< "// Calculate the attenuation with respect to the spot light cone."
2391 << endl
<< "// Parameters:"
2392 << endl
<< "// minCosSpotAngle: the cosine of the spot light angle"
2393 << endl
<< "// l : normalized direction between fragment and light position"
2394 << endl
<< "// s : normalized light direction"
2396 << endl
<< "float spotAttenuation("
2397 << endl
<< " in const float minCosSpotAngle,"
2398 << endl
<< " in const vec3 l,"
2399 << endl
<< " in const vec3 s)"
2402 << endl
<< " // Linear interpolate between x and y using weight a"
2403 << endl
<< " // mix(x,y,a) = x*(1-a)+y*a"
2405 << endl
<< " float maxCosSpotAngle = mix(minCosSpotAngle, 1.0, 0.5);"
2406 << endl
<< " float l_dot_s = dot(-l, s);"
2408 << endl
<< " // Perform smooth Hermite interpolation between 0 and 1, when e0<x<e1"
2409 << endl
<< " // float t = clamp((x-e0)/(e1-e0),0.0,1.0);"
2410 << endl
<< " // smoothstep(e0,e1,x) = t*t*(3-2*t);"
2412 << endl
<< " return smoothstep(minCosSpotAngle, maxCosSpotAngle, l_dot_s);"
2416 << endl
<< "// cinema (uber) light super ellipses clipping"
2417 << endl
<< "// Parameters:"
2418 << endl
<< "// a : inner super ellipses width"
2419 << endl
<< "// b : inner super ellipses height"
2420 << endl
<< "// A : outer super ellipses width"
2421 << endl
<< "// B : outer super ellipses height"
2422 << endl
<< "// r : roundness parameter"
2423 << endl
<< "// theta : twist parameter"
2424 << endl
<< "// pos : fragment position in light space"
2426 << endl
<< "// |x/a|^r + |y/b|^r = 1 <=> a*b*(|b*x|^r + |a*y|^r)^(-1/r) = 1"
2428 << endl
<< "// smoothstep(e0,e1,x)"
2429 << endl
<< "// Perform smooth Hermite interpolation between 0 and 1, when e0<x<e1"
2430 << endl
<< "// float t = clamp((x-e0)/(e1-e0),0.0,1.0);"
2431 << endl
<< "// smoothstep(e0,e1,x) = t*t*(3-2*t);"
2433 << endl
<< "float clipSuperEllipses("
2434 << endl
<< " in float a,"
2435 << endl
<< " in float b,"
2436 << endl
<< " in float A,"
2437 << endl
<< " in float B,"
2438 << endl
<< " in float r,"
2439 << endl
<< " in float theta,"
2440 << endl
<< " in vec3 pos)"
2442 << endl
<< " float result = 1.0;"
2444 << endl
<< " vec2 P = pos.xy / pos.z;"
2445 << endl
<< " if (all(equal(P, vec2(0.0, 0.0))))"
2446 << endl
<< " return 1.0;"
2448 << endl
<< " float cos_theta = cos(-theta);"
2449 << endl
<< " float sin_theta = sin(-theta);"
2451 << endl
<< " float x = abs(cos_theta * P.x - sin_theta * P.y);"
2452 << endl
<< " float y = abs(sin_theta * P.x + cos_theta * P.y);"
2454 << endl
<< " if (r > 50) // basically a square"
2456 << endl
<< " // Simpler case of a square"
2457 << endl
<< " result = (1.0 - smoothstep(a, A, x)) * (1.0 - smoothstep(b, B, y));"
2461 << endl
<< " float q = pow(x/a, r) + pow(y/b, r);"
2462 << endl
<< " float Q = pow(x/A, r) + pow(y/B, r);"
2464 << endl
<< " if (q < 1) return 1.0;"
2465 << endl
<< " if (Q >= 1) return 0.0;"
2467 << endl
<< " result = 1.0 - smoothstep(q, Q, 1.0);"
2470 << endl
<< " return result;"
2474 << endl
<< "// directional light contribution"
2476 << endl
<< "vec3 directionalLight("
2477 << endl
<< " in const uint i, // light identifier, i.e. current light"
2478 << endl
<< " in const uint j, // material identifier"
2479 << endl
<< " in const vec3 n, // vertex normal in eye space"
2480 << endl
<< " in const vec3 v) // view direction in eye space"
2482 << endl
<< " if (!lights.light[i].enabled)"
2483 << endl
<< " return vec3(0.0, 0.0, 0.0);"
2486 << endl
<< " // Transform the light direction from world space into eye space for further considerations"
2488 << endl
<< " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
2490 << endl
<< " vec3 l = -direction.xyz;"
2493 << endl
<< " // the half vector"
2495 << endl
<< " vec3 h = normalize(l+v);"
2497 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
2498 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
2500 << endl
<< " float m = materials.material[j].shininess;"
2502 << endl
<< " float pf; // power factor"
2504 << endl
<< " if (n_dot_l == 0.0)"
2505 << endl
<< " pf = 0.0;"
2507 << endl
<< " pf = pow(n_dot_h, m);"
2509 << endl
<< " vec3 light_intensity = lights.light[i].intensity * lights.light[i].color;"
2511 << endl
<< " return materials.material[j].emissive"
2512 << endl
<< " + light_intensity * materials.material[j].ambient"
2513 << endl
<< " + light_intensity * materials.material[j].diffuse * n_dot_l"
2514 << endl
<< " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
2518 << endl
<< "// point light contribution"
2520 << endl
<< "vec3 pointLight("
2521 << endl
<< " in const uint i, // light identifier, i.e. current light"
2522 << endl
<< " in const uint j, // material identifier"
2523 << endl
<< " in const vec3 n, // vertex normal in eye space"
2524 << endl
<< " in const vec3 v, // view direction in eye space"
2525 << endl
<< " in const vec3 p) // vertex position in eye space"
2527 << endl
<< " if (!lights.light[i].enabled)"
2528 << endl
<< " return vec3(0.0, 0.0, 0.0);"
2531 << endl
<< " // Transform the light position from world space into eye space for further considerations"
2533 << endl
<< " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
2535 << endl
<< " vec3 l = position.xyz - p; // dir from surface to light position"
2536 << endl
<< " float d = length(l); // dist from surface to light source"
2538 << endl
<< " if (lights.light[i].rangeCutOff < d)"
2539 << endl
<< " return vec3(0.0, 0.0, 0.0);"
2541 << endl
<< " l = normalize(l); // norm direction from surf to light"
2544 << endl
<< " // the half vector"
2546 << endl
<< " vec3 h = normalize(l+v);"
2548 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
2549 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
2551 << endl
<< " float m = materials.material[j].shininess;"
2553 << endl
<< " float pf; // power factor"
2555 << endl
<< " if (n_dot_l == 0.0)"
2556 << endl
<< " pf = 0.0;"
2558 << endl
<< " pf = pow(n_dot_h, m);"
2560 << endl
<< " float attenuation = calcAttenuation(lights.light[i].rangeCutOff, d);"
2562 << endl
<< " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
2564 << endl
<< " return materials.material[j].emissive"
2565 << endl
<< " + light_intensity * materials.material[j].ambient"
2566 << endl
<< " + light_intensity * materials.material[j].diffuse * n_dot_l"
2567 << endl
<< " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
2571 << endl
<< "// spot light contribution"
2573 << endl
<< "vec3 spotLight("
2574 << endl
<< " in const uint i, // light identifier, i.e. current light"
2575 << endl
<< " in const uint j, // material identifier"
2576 << endl
<< " in const vec3 n, // vertex normal in eye space"
2577 << endl
<< " in const vec3 v, // view direction in eye space"
2578 << endl
<< " in const vec3 p) // vertex position in eye space"
2580 << endl
<< " if (!lights.light[i].enabled)"
2581 << endl
<< " return vec3(0.0, 0.0, 0.0);"
2584 << endl
<< " // Transform the light position from world space into eye space for further considerations"
2586 << endl
<< " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
2588 << endl
<< " vec3 l = position.xyz - p; // dir from surface to light position"
2589 << endl
<< " float d = length(l); // dist from surface to light source"
2591 << endl
<< " if (lights.light[i].rangeCutOff < d)"
2592 << endl
<< " return vec3(0.0, 0.0, 0.0);"
2594 << endl
<< " l = normalize(l); // norm dir from surface to light"
2597 << endl
<< " // Transform the light direction from world space into eye space for further considerations"
2599 << endl
<< " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
2601 << endl
<< " vec3 s = direction.xyz;"
2602 << endl
<< " s = normalize(s);"
2605 << endl
<< " // the half vector"
2607 << endl
<< " vec3 h = normalize(l+v);"
2609 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
2610 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
2612 << endl
<< " float m = materials.material[j].shininess;"
2614 << endl
<< " float pf; // power factor"
2616 << endl
<< " if (n_dot_l == 0.0)"
2617 << endl
<< " pf = 0.0;"
2619 << endl
<< " pf = pow(n_dot_h, m);"
2621 << endl
<< " float attenuation = calcAttenuation(lights.light[i].rangeCutOff, d);"
2623 << endl
<< " attenuation *= spotAttenuation(lights.light[i].cosSpotlightAngle, l, s);"
2625 << endl
<< " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
2627 << endl
<< " return materials.material[j].emissive"
2628 << endl
<< " + light_intensity * materials.material[j].ambient"
2629 << endl
<< " + light_intensity * materials.material[j].diffuse * n_dot_l"
2630 << endl
<< " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
2634 << endl
<< "// cinema light contribution"
2636 << endl
<< "vec3 cinemaLight("
2637 << endl
<< " in const uint i, // light identifier, i.e. current light"
2638 << endl
<< " in const uint j, // material identifier"
2639 << endl
<< " in const vec3 n, // vertex normal in eye space"
2640 << endl
<< " in const vec3 v, // view direction in eye space"
2641 << endl
<< " in const vec3 p) // vertex position in eye space"
2643 << endl
<< " if (!lights.light[i].enabled)"
2644 << endl
<< " return vec3(0.0, 0.0, 0.0);"
2647 << endl
<< " // Transform the light position from world space into eye space for further considerations"
2649 << endl
<< " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
2651 << endl
<< " vec3 l = position.xyz - p; // dir from surface to light position"
2652 << endl
<< " float d = length(l); // dist from surface to light source"
2654 << endl
<< " if (lights.light[i].rangeCutOff < d)"
2655 << endl
<< " return vec3(0.0, 0.0, 0.0);"
2657 << endl
<< " l = normalize(l); // norm dir from surface to light"
2660 << endl
<< " // Transform the light direction from world space into eye space for further considerations"
2662 << endl
<< " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
2664 << endl
<< " vec3 s = direction.xyz;"
2665 << endl
<< " s = normalize(s);"
2668 << endl
<< " // the half vector"
2670 << endl
<< " vec3 h = normalize(l+v);"
2672 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
2673 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
2675 << endl
<< " float m = materials.material[j].shininess;"
2677 << endl
<< " float pf; // power factor"
2679 << endl
<< " if (n_dot_l == 0.0)"
2680 << endl
<< " pf = 0.0;"
2682 << endl
<< " pf = pow(n_dot_h, m);"
2684 << endl
<< " float attenuation = calcAttenuation(lights.light[i].rangeCutOff, d);"
2686 << endl
<< " vec3 p_LS = (lights.light[i].eyeToLightSpaceMatrix * vec4(p, 1.0)).xyz;"
2688 << endl
<< " attenuation *= clipSuperEllipses("
2689 << endl
<< " lights.light[i].innerSuperEllipsesWidth,"
2690 << endl
<< " lights.light[i].innerSuperEllipsesHeight,"
2691 << endl
<< " lights.light[i].outerSuperEllipsesWidth,"
2692 << endl
<< " lights.light[i].outerSuperEllipsesHeight,"
2693 << endl
<< " lights.light[i].superEllipsesRoundness,"
2694 << endl
<< " lights.light[i].superEllipsesTwist,"
2695 << endl
<< " p_LS);"
2697 << endl
<< " if (p_LS.z > 0.0) attenuation = 0.0;"
2699 << endl
<< " attenuation = clamp(attenuation, 0.0, 1.0);"
2701 << endl
<< " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
2703 << endl
<< " return materials.material[j].emissive"
2704 << endl
<< " + light_intensity * materials.material[j].ambient"
2705 << endl
<< " + light_intensity * materials.material[j].diffuse * n_dot_l"
2706 << endl
<< " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
2709 << endl
<< "void main()"
2712 << endl
<< " // normalize the eye space normal"
2714 << endl
<< " int frontCond = -(1 - int(gl_FrontFacing)*2);"
2715 << endl
<< " vec3 N = frontCond * normalize(vNormalES);"
2718 << endl
<< " // get the view vector and normalize it"
2720 << endl
<< " vec3 V = normalize(cCameraPositionES - vPositionES);"
2723 << endl
<< " // Integrate over all lights: Any unused light does not contribute and each light"
2724 << endl
<< " // contribute either from the directional light, the point light or the spot light."
2726 << endl
<< " vec3 color = vec3(0.0, 0.0, 0.0);"
2728 << endl
<< " uint list_idx = 0;"
2729 << endl
<< " uint light_count = 0;"
2731 << endl
<< " if (clusteringData.enabled)"
2733 << endl
<< " uvec2 grid_data = getGridData(gl_FragCoord.xy, vPositionES.z);"
2735 << endl
<< " list_idx = grid_data.x;"
2736 << endl
<< " light_count = grid_data.y;"
2740 << endl
<< " light_count = affectedLightIndexList.idx.length();"
2743 << endl
<< " for (uint i = 0; i < light_count; ++i)"
2745 << endl
<< " uint light_idx = (clusteringData.enabled) ? lightIndexList.idx[list_idx+i] : affectedLightIndexList.idx[i];"
2747 << endl
<< " switch (lights.light[light_idx].type)"
2749 << endl
<< " case POINT_LIGHT: color += pointLight(light_idx, geom_state.material_index, N, V, vPositionES); break;"
2750 << endl
<< " case DIRECTIONAL_LIGHT: color += directionalLight(light_idx, geom_state.material_index, N, V); break;"
2751 << endl
<< " case SPOT_LIGHT: color += spotLight(light_idx, geom_state.material_index, N, V, vPositionES); break;"
2752 << endl
<< " case CINEMA_LIGHT: color += cinemaLight(light_idx, geom_state.material_index, N, V, vPositionES); break;"
2755 << endl
<< " vFragColor = vec4(color, materials.material[geom_state.material_index].opacity);"