changed: gcc8 base update
[opensg.git] / Examples / Advanced / multirangelightclustershading.cpp
blob72e9fc5817935246b386ee05039f834e2a4ede09
1 // OpenSG Example: MultiRangeLightClusterShading
2 //
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
6 //
7 // It uses the MultiLightChunk for the light representation and allows
8 // to visualize the lights frustums. 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.
24 // Remarks:
25 // - only tested on decsent NVidia GPUs
26 // - this example is a proof of concept
27 // - this example is not performance optimized
29 // Key bindings:
30 // Esc : quit example
31 // Space : toogle geometry simulation on/off
32 // 1 : only one light
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
66 // Headers
67 #include <OSGGLUT.h>
68 #include <OSGConfig.h>
69 #include <OSGSimpleGeometry.h>
70 #include <OSGGLUTWindow.h>
71 #include <OSGSimpleSceneManager.h>
72 #include <OSGBaseFunctions.h>
73 #include <OSGTransform.h>
74 #include <OSGGroup.h>
76 // new headers:
77 #include <OSGGLEXT.h>
78 #include <OSGTime.h>
79 #include <OSGPlane.h>
80 #include <OSGMatrixCamera.h>
81 #include <OSGPerspectiveCamera.h>
82 #include <OSGOrthographicCamera.h>
83 #include <OSGHDR2Stage.h>
84 #include <OSGInverseTransform.h>
85 #include <OSGShaderProgramChunk.h>
86 #include <OSGShaderProgram.h>
87 #include <OSGShaderVariableOSG.h>
88 #include <OSGShaderProgramVariableChunk.h>
89 #include <OSGShaderProgramVariables.h>
90 #include <OSGShaderStorageBufferObjChunk.h>
91 #include <OSGShaderStorageBufferObjStdLayoutChunk.h>
92 #include <OSGUniformBufferObjChunk.h>
93 #include <OSGChunkMaterial.h>
94 #include <OSGMaterialGroup.h>
95 #include <OSGMaterialChunkOverrideGroup.h>
96 #include <OSGMatrixUtility.h>
97 #include <OSGMultiLightChunk.h>
98 #include <OSGMultiPropertyUBOChunk.h>
99 #include <OSGMultiPropertySSBOChunk.h>
100 #include <OSGPolygonChunk.h>
101 #include <OSGDepthChunk.h>
102 #include <OSGBlendChunk.h>
103 #include <OSGTextureObjChunk.h>
104 #include <OSGTextureEnvChunk.h>
105 #include <OSGTextureImageChunk.h>
106 #include <OSGTwoSidedLightingChunk.h>
107 #include <OSGAlgorithmComputeElement.h>
108 #include <OSGComputeShaderAlgorithm.h>
109 #include <OSGComputeShaderChunk.h>
110 #include <OSGGeoProperties.h>
112 #else
113 // Headers
114 #include <OpenSG/OSGGLUT.h>
115 #include <OpenSG/OSGConfig.h>
116 #include <OpenSG/OSGSimpleGeometry.h>
117 #include <OpenSG/OSGGLUTWindow.h>
118 #include <OpenSG/OSGSimpleSceneManager.h>
119 #include <OpenSG/OSGBaseFunctions.h>
120 #include <OpenSG/OSGTransform.h>
121 #include <OpenSG/OSGGroup.h>
123 // new headers:
124 #include <OpenSG/OSGGLEXT.h>
125 #include <OpenSG/OSGTime.h>
126 #include <OpenSG/OSGPlane.h>
127 #include <OpenSG/OSGMatrixCamera.h>
128 #include <OpenSG/OSGPerspectiveCamera.h>
129 #include <OpenSG/OSGOrthographicCamera.h>
130 #include <OpenSG/OSGHDR2Stage.h>
131 #include <OpenSG/OSGInverseTransform.h>
132 #include <OpenSG/OSGShaderProgramChunk.h>
133 #include <OpenSG/OSGShaderProgram.h>
134 #include <OpenSG/OSGShaderVariableOSG.h>
135 #include <OpenSG/OSGShaderProgramVariableChunk.h>
136 #include <OpenSG/OSGShaderProgramVariables.h>
137 #include <OpenSG/OSGShaderStorageBufferObjChunk.h>
138 #include <OpenSG/OSGShaderStorageBufferObjStdLayoutChunk.h>
139 #include <OSGUniformBufferObjChunk.h>
140 #include <OpenSG/OSGChunkMaterial.h>
141 #include <OpenSG/OSGMaterialGroup.h>
142 #include <OpenSG/OSGMaterialChunkOverrideGroup.h>
143 #include <OpenSG/OSGMatrixUtility.h>
144 #include <OpenSG/OSGMultiLightChunk.h>
145 #include <OpenSG/OSGMultiPropertyUBOChunk.h>
146 #include <OpenSG/OSGMultiPropertySSBOChunk.h>
147 #include <OpenSG/OSGPolygonChunk.h>
148 #include <OpenSG/OSGDepthChunk.h>
149 #include <OpenSG/OSGBlendChunk.h>
150 #include <OpenSG/OSGTextureObjChunk.h>
151 #include <OpenSG/OSGTextureEnvChunk.h>
152 #include <OpenSG/OSGTextureImageChunk.h>
153 #include <OpenSG/OSGTwoSidedLightingChunk.h>
154 #include <OpenSG/OSGAlgorithmComputeElement.h>
155 #include <OpenSG/OSGComputeShaderAlgorithm.h>
156 #include <OpenSG/OSGComputeShaderChunk.h>
157 #include <OpenSG/OSGGeoProperties.h>
159 #endif
161 // ============================================================================
163 // Part: Declaration of the example scene and some helpers:
164 // - constants that governs the example
165 // - random number generators
166 // - smooth cubic Bezier spline curve
168 // ============================================================================
170 const bool use_ortho_camera = false; // use a orthographic camera instead of the perspective camera
172 const OSG::Int32 init_num_geometries = 256; // the initial number of to be lit geometry
173 const OSG::Int32 max_num_geometries = 2048; // the maximal number of lit geometry
175 const OSG::Int32 num_grid_boxes = 100; // each light and geometry has a motion curve.
176 // Sample a number if different cube boxes from the scene and
177 // take randomly one point from each cube. That guarantees that
178 // the knot points do not clump and that they are all unequal.
179 const OSG::Int32 num_curve_knots = 40; // each motion curve has that number of knot points
181 const std::size_t num_materials = 5000; // material database has this number of entries
183 const OSG::Int32 init_num_lights = 128; // initial number if example lights
184 const OSG::Int32 max_num_lights = 2048; // maximal number of allowed lights
186 const OSG::Real32 max_light_power = 10.f; // light intensity is choosen randomly up to the maximal light power
188 const OSG::Real32 world_size = 10.f; // lights and geometry init positions are bounded in the world
189 const OSG::Real32 box_factor = 1.5f; // visualization box is drawn around the world
191 OSG::Real32 simulation_delta = 0.0001f; // determines the simulation speed (keys e/E)
192 OSG::Real32 elapse_time_limit = 10.f; // time in milliseconds after which a simulation step is performed (keys o/O)
196 const OSG::Real32 rangeFactor = 1.15f; // range multiplication factor (keys p/P)
197 const OSG::Real32 intensityFactor = 1.2f; // intensity multiplication factor (keys i/I)
199 const OSG::UInt32 block_size = 16; // number of compute shader threads per xy-direction
200 const OSG::UInt32 tile_size = 64; // number of pixel per cluster tile per xy-direction
201 const OSG::UInt32 num_cluster_z = 32; // number of clusters in the z direction
202 const OSG::Real32 near_plane_offset = 5.f; // clustering starts to (zNear + near_plane_offset)
204 const OSG::UInt32 light_index_list_size = 2097152; // Max number of light index list entries.
205 // If we have a screen size of 1920*1080 pixel and assume
206 // a 32 cluster in z-direction we have, with a tile size
207 // of 64 pixel, 30*17*32 = 16320 cluster. With 2^21 = 2097152
208 // light list entries we have on average space for around 64
209 // lights per cluster. The light list then occupy
210 // 2097152*4 bytes = 8388608 bytes of graphic memory.
212 const OSG::Vec3i work_group_size = OSG::Vec3i(block_size, block_size, 1);
213 // each compute shader work group has that thread layout
215 const OSG::UInt32 num_test_val_entries = 65536; // number of array elements in the TestData members.
216 // on default the test data is not transfered to the GPU
217 // and no test are performed. Test were used on example
218 // development and are leaved in for illustration purpose.
221 // Simulation parameters
223 OSG::TimeStamp time_stamp = 0; // time stamp is updated after each simulation step
224 OSG::Real32 simulation_param = 0.f; // value in range [0,1]. Used for motion curve evaluation
225 bool simulate_geometry = true; // motion of lit geometry
226 bool simulate_lights = true; // motion of shading lights
228 OSG::SimpleSceneManagerRefPtr mgr; // the global scene manager
231 // The example makes use of many randomly choosen values for various parameters.
232 // Most parameters have specific ranges and types. Therefore the example provides
233 // special dices on uniform distributions over the ranges for the different parameters.
235 typedef boost::mt19937 RNGType;
236 RNGType rng(time(0));
238 boost::uniform_int<> box_dist(0, num_grid_boxes-1);
239 boost::variate_generator<RNGType, boost::uniform_int<> > box_idx_die(rng, box_dist);
241 boost::uniform_int<> die_dist(1, 6);
242 boost::variate_generator<RNGType, boost::uniform_int<> > classic_die(rng, die_dist);
244 boost::uniform_int<> geom_dist(0, 7);
245 boost::variate_generator<RNGType, boost::uniform_int<> > geom_idx_die(rng, geom_dist);
247 boost::uniform_01<float> unit_distribution;
248 boost::variate_generator< RNGType, boost::uniform_01<float> > unit_die(rng, unit_distribution);
250 boost::uniform_real<float> small_distribution(0.1f, 1.f);
251 boost::variate_generator< RNGType, boost::uniform_real<float> > small_die(rng, small_distribution);
253 boost::uniform_real<float> spot_distribution(5.f, 90.f);
254 boost::variate_generator< RNGType, boost::uniform_real<float> > spot_die(rng, spot_distribution);
256 boost::uniform_real<float> light_range_distribution(0.2f, 0.7f);
257 boost::variate_generator< RNGType, boost::uniform_real<float> > light_range_die(rng, light_range_distribution);
259 boost::uniform_real<float> light_ellipsis_roundness_distribution1(0.2f, 1.0f);
260 boost::variate_generator< RNGType, boost::uniform_real<float> > light_ellipsis_roundness_die1(rng, light_ellipsis_roundness_distribution1);
262 boost::uniform_real<float> light_ellipsis_roundness_distribution2(1.0f, 2.0f);
263 boost::variate_generator< RNGType, boost::uniform_real<float> > light_ellipsis_roundness_die2(rng, light_ellipsis_roundness_distribution2);
265 boost::uniform_real<float> light_ellipsis_roundness_distribution3(2.0f, 51.0f);
266 boost::variate_generator< RNGType, boost::uniform_real<float> > light_ellipsis_roundness_die3(rng, light_ellipsis_roundness_distribution3);
268 boost::uniform_real<float> light_ellipsis_twist_distribution(0.f, 360.0f);
269 boost::variate_generator< RNGType, boost::uniform_real<float> > light_ellipsis_twist_die(rng, light_ellipsis_twist_distribution);
271 boost::uniform_real<float> light_ellipsis_radius_distribution(0.1f, 2.0f);
272 boost::variate_generator< RNGType, boost::uniform_real<float> > light_ellipsis_radius_die(rng, light_ellipsis_radius_distribution);
274 boost::uniform_real<float> light_ellipsis_radius_ratio_distribution(1.01f, 1.5f);
275 boost::variate_generator< RNGType, boost::uniform_real<float> > light_ellipsis_radius_ratio_die(rng, light_ellipsis_radius_ratio_distribution);
277 std::vector<OSG::Pnt3f> dice_knots(bool close_curve);
279 OSG::Vec3f dice_unit_vector()
281 OSG::Vec3f v;
283 while (v.length() < OSG::Eps)
284 v.setValues(
285 -1.f + 2.f * unit_die(),
286 -1.f + 2.f * unit_die(),
287 -1.f + 2.f * unit_die());
289 v.normalize();
291 return v;
295 // The example uses cubic bezier curves for the light and geometry motion simulation.
296 // The smooth curves are piecewise constructed from these cubic bezier curves.
298 class CubicBezierCurve
300 public:
301 CubicBezierCurve(const OSG::Pnt3f& p0, const OSG::Pnt3f& p1, const OSG::Pnt3f& p2, const OSG::Pnt3f& p3);
302 CubicBezierCurve(const CubicBezierCurve& rhs);
304 CubicBezierCurve& operator=(const CubicBezierCurve& rhs);
306 OSG::Pnt3f operator() (OSG::Real32 t) const;
307 OSG::Vec3f tangent (OSG::Real32 t) const;
308 OSG::Vec3f normal (OSG::Real32 t) const;
309 OSG::Vec3f binormal (OSG::Real32 t) const;
310 OSG::Matrix frame (OSG::Real32 t, bool position_only) const;
311 OSG::Real32 length (OSG::UInt32 numSeg = 10) const;
313 private:
314 OSG::Vec3f fst_derivative (OSG::Real32 t) const;
315 OSG::Vec3f sec_derivative (OSG::Real32 t) const;
316 OSG::Vec3f thr_devivative (OSG::Real32 t) const;
318 private:
319 OSG::Pnt3f p[4];
322 class SmoothCubicBezierSpline
324 public:
325 typedef std::vector<OSG::Pnt3f> points_t;
327 SmoothCubicBezierSpline(const points_t& knots);
328 SmoothCubicBezierSpline(const SmoothCubicBezierSpline& rhs);
330 SmoothCubicBezierSpline& operator=(const SmoothCubicBezierSpline& rhs);
332 OSG::Pnt3f operator() (OSG::Real32 t) const;
333 OSG::Vec3f tangent (OSG::Real32 t) const;
334 OSG::Vec3f normal (OSG::Real32 t) const;
335 OSG::Vec3f binormal (OSG::Real32 t) const;
336 OSG::Matrix frame (OSG::Real32 t, bool position_only = false) const;
337 OSG::Real32 length (OSG::UInt32 numSeg = 10) const;
339 private:
340 void calc_ctrl_pnts (points_t& p1, points_t& p2) const;
341 std::size_t index (OSG::Real32 t) const;
342 OSG::Real32 t_ (OSG::Real32 t, std::size_t idx) const;
344 private:
345 std::vector<OSG::Pnt3f> knots;
346 std::vector<OSG::Real32> intervals;
347 std::vector<CubicBezierCurve> curves;
350 // ============================================================================
352 // Part: Math helper
353 // - reflect_at_plane_through_orgin
354 // - rotate_a_into_direction_b
356 // ============================================================================
359 // The plane normal N is expected to be normalized
361 OSG::Matrix reflect_at_plane_through_orgin(const OSG::Vec3f& N)
363 OSG::Real32 xx = N[0]*N[0];
364 OSG::Real32 yy = N[1]*N[1];
365 OSG::Real32 zz = N[2]*N[2];
366 OSG::Real32 xy = N[0]*N[1];
367 OSG::Real32 xz = N[0]*N[2];
368 OSG::Real32 yz = N[1]*N[2];
370 return OSG::Matrix(1.f-2.f*xx, -2.f*xy, -2.f*xz, 0.f,
371 -2.f*xy, 1.f-2.f*yy, -2.f*yz, 0.f,
372 -2.f*xz, -2.f*yz, 1.f-2.f*zz, 0.f,
373 0.f, 0.f, 0.f, 1.f);
377 // The resulting orthonormal matrix rotates vector a into the direction of vector b.
378 // If b is a unit vector then the resulting vector b' = M*b is identical
379 // to b and for some unit vector a' the resulting vector b' = M*a' is also a unit
380 // vector. Neither the length of a or b is used in the calculation of the
381 // rotation matrix!
384 OSG::Matrix rotate_a_into_direction_b(OSG::Vec3f a, OSG::Vec3f b)
386 OSG::Matrix R;
388 a.normalize();
389 b.normalize();
391 OSG::Real32 c = a.dot(b);
392 if (OSG::osgAbs(1.f - c) < OSG::Eps)
393 return R;
395 if (OSG::osgAbs(-1.f - c) < OSG::Eps)
396 return reflect_at_plane_through_orgin(a);
398 OSG::Vec3f v = a.cross(b);
400 OSG::Matrix skew( 0.f,-v[2], v[1], 0.f,
401 v[2], 0.f,-v[0], 0.f,
402 -v[1], v[0], 0.f, 0.f,
403 0.f, 0.f, 0.f, 0.f);
405 OSG::Matrix T(skew); T.mult(skew); T.scale(1.f / (1.f + c));
407 R.add(skew); R.add(T);
409 return R;
413 OSG::Matrix rotate_a_into_direction_b(OSG::Vec3f a, OSG::Vec3f b)
415 OSG::Matrix R;
417 a.normalize();
418 b.normalize();
420 OSG::Real32 c = a.dot(b);
421 if (OSG::osgAbs(1.f - c) < OSG::Eps)
422 return R;
424 if (OSG::osgAbs(-1.f - c) < OSG::Eps)
425 return reflect_at_plane_through_orgin(a);
427 OSG::Vec3f v = a.cross(b);
429 OSG::Real32 theta = OSG::osgACos(c);
431 OSG::Matrix skew( 0.f,-v[2], v[1], 0.f,
432 v[2], 0.f,-v[0], 0.f,
433 -v[1], v[0], 0.f, 0.f,
434 0.f, 0.f, 0.f, 0.f);
436 OSG::Matrix T(skew); T.mult(skew);
438 skew.scale(OSG::osgSin(theta));
439 T.scale(1 - OSG::osgCos(theta));
441 R.add(skew); R.add(T);
443 return R;
447 // ============================================================================
449 // Part: Extensions for simple geometry generation
450 // - makeSpotGeo
451 // - makePyramidGeo
452 // - makeCinemaGeo
454 // ============================================================================
456 OSG::GeometryTransitPtr makeSpotGeo(
457 OSG::Real32 R, // the spot range/radius of influence
458 OSG::Real32 angle, // the spot half angle in degree
459 OSG::UInt32 slices, // the number of subdivisions in z-Dir, i.e. in spot direction
460 OSG::UInt32 sides) // the number of circle subdivisions
462 OSG::GeoUInt8PropertyRefPtr types = OSG::GeoUInt8Property::create();
463 OSG::GeoUInt32PropertyRefPtr lens = OSG::GeoUInt32Property::create();
464 OSG::GeoPnt3fPropertyRefPtr pnts = OSG::GeoPnt3fProperty::create();
465 OSG::GeoVec3fPropertyRefPtr norms = OSG::GeoVec3fProperty::create();
467 OSG::GeoUInt8Property::StoredFieldType *t = types->editFieldPtr();
468 OSG::GeoUInt32Property::StoredFieldType *l = lens ->editFieldPtr();
469 OSG::GeoPnt3fProperty::StoredFieldType *p = pnts ->editFieldPtr();
470 OSG::GeoVec3fProperty::StoredFieldType *n = norms->editFieldPtr();
472 // get even slices and sides
473 if ( (slices & 1) == 1 )
474 slices += 1;
476 if ( (sides & 1) == 1 )
477 sides += 1;
479 OSG::Real32 a_cone = OSG::osgDegree2Rad(angle);
480 OSG::Real32 h_cone = R * OSG::osgCos(a_cone);
481 OSG::Real32 d_cone = h_cone / slices;
483 OSG::Real32 delta_phi = 2.f * OSG::Pi / (sides-1);
485 OSG::Vec3f ey(0,1,0);
487 typedef std::vector<OSG::Pnt3f> VecPntsT;
489 VecPntsT vecOddPnts(sides), vecEvenPnts(sides);
490 VecPntsT* pvecLast = &vecOddPnts;
491 VecPntsT* pvecCurr = &vecEvenPnts;
494 // First the cone itself
496 std::vector<OSG::Vec3f> vecNormals(sides);
497 for (OSG::UInt32 i = 0; i < sides; ++i)
499 OSG::Real32 phi = i * delta_phi;
501 vecNormals[i] = -OSG::Vec3f(OSG::osgCos(a_cone) * OSG::osgCos(phi), OSG::osgSin(a_cone), OSG::osgCos(a_cone) * OSG::osgSin(phi));
504 OSG::Pnt3f pT(0,0,0); // tip of spot cone
506 (*pvecLast)[0] = pT;
508 for (OSG::UInt32 j = 1; j <= slices; ++j)
510 OSG::Real32 l_cone = j * d_cone;
511 OSG::Real32 r_cone = l_cone * OSG::osgTan(a_cone);
513 OSG::Pnt3f pR = pT + l_cone * ey;
515 OSG::Real32 d_phi = (j & 0) ? delta_phi : delta_phi + delta_phi/2.f;
517 OSG::Real32 phi = (j & 0) ? 0 : delta_phi/2.f;
519 for (OSG::UInt32 i = 0; i < sides-1; ++i)
521 phi += delta_phi;
522 (*pvecCurr)[i] = pR + r_cone * OSG::Vec3f(OSG::osgSin(phi), 0, -OSG::osgCos(phi));
525 (*pvecCurr)[sides-1] = (*pvecCurr)[0];
527 if (j == 1)
529 t->push_back(GL_TRIANGLE_FAN);
530 l->push_back(1 + sides);
532 p->push_back((*pvecLast)[0]);
533 n->push_back(OSG::Vec3f(0,-1,0));
535 for (OSG::UInt32 i = 0; i < sides; ++i)
537 p->push_back((*pvecCurr)[i]);
538 n->push_back(vecNormals[i]);
541 else
543 t->push_back(GL_TRIANGLE_STRIP);
544 l->push_back(2*sides);
546 for (OSG::UInt32 i = 0; i < sides; ++i)
548 p->push_back((*pvecLast)[i]);
549 p->push_back((*pvecCurr)[i]);
551 n->push_back(vecNormals[i]);
552 n->push_back(vecNormals[i]);
556 std::swap(pvecLast, pvecCurr);
560 // Second the sphere cap
562 OSG::Real32 d_alpha = a_cone / (slices-1);
564 for (OSG::UInt32 j = 0; j < slices; ++j)
566 if (j < slices-1)
568 OSG::Real32 da_cone = a_cone - j * d_alpha;
570 OSG::Real32 l_cone = R * OSG::osgCos(da_cone);
571 OSG::Real32 r_cone = R * OSG::osgSin(da_cone);
573 OSG::Pnt3f pj = pT + l_cone * ey;
575 OSG::Real32 phi = (j & 0) ? 0 : delta_phi/2.f;
577 for (OSG::UInt32 i = 0; i < sides-1; ++i)
579 phi += delta_phi;
580 (*pvecCurr)[i] = pj + r_cone * OSG::Vec3f(OSG::osgSin(phi), 0, -OSG::osgCos(phi));
582 OSG::Vec3f n = (*pvecCurr)[i] - pT;
583 n.normalize();
584 vecNormals[i] = n;
587 (*pvecCurr)[sides-1] = (*pvecCurr)[0];
589 t->push_back(GL_TRIANGLE_STRIP);
590 l->push_back(2*sides);
592 for (OSG::UInt32 i = 0; i < sides; ++i)
594 p->push_back((*pvecLast)[i]);
595 p->push_back((*pvecCurr)[i]);
597 n->push_back(vecNormals[i]);
598 n->push_back(vecNormals[i]);
601 else
603 t->push_back(GL_TRIANGLE_FAN);
604 l->push_back(1 + sides);
606 p->push_back(pT + R * ey);
607 n->push_back(OSG::Vec3f(0,-1,0));
609 for (OSG::Int32 i = sides-1; i >= 0; --i)
611 p->push_back((*pvecLast)[i]);
612 n->push_back(vecNormals[i]);
616 std::swap(pvecLast, pvecCurr);
619 OSG::GeometryTransitPtr geo = OSG::Geometry::create();
621 geo->setTypes (types);
622 geo->setLengths (lens);
623 geo->setPositions(pnts);
624 geo->setNormals (norms);
626 geo->setMaterial(OSG::getDefaultUnlitMaterial());
628 return geo;
631 OSG::GeometryTransitPtr makeCinemaGeo(
632 OSG::Real32 a, // superellipses width
633 OSG::Real32 b, // superellipses height
634 OSG::Real32 r, // superellipses roundness parameter
635 OSG::Real32 theta, // superellipses twist parameter in radians
636 OSG::Real32 h, // z-height of the body
637 OSG::UInt32 slices, // the number of subdivisions in z-Dir, i.e. in spot direction
638 OSG::UInt32 sides) // the number of circle subdivisions
640 OSG::GeoUInt8PropertyRefPtr types = OSG::GeoUInt8Property::create();
641 OSG::GeoUInt32PropertyRefPtr lens = OSG::GeoUInt32Property::create();
642 OSG::GeoPnt3fPropertyRefPtr pnts = OSG::GeoPnt3fProperty::create();
643 OSG::GeoVec3fPropertyRefPtr norms = OSG::GeoVec3fProperty::create();
645 OSG::GeoUInt8Property::StoredFieldType *t = types->editFieldPtr();
646 OSG::GeoUInt32Property::StoredFieldType *l = lens ->editFieldPtr();
647 OSG::GeoPnt3fProperty::StoredFieldType *p = pnts ->editFieldPtr();
648 OSG::GeoVec3fProperty::StoredFieldType *n = norms->editFieldPtr();
650 // get even slices and sides
651 if ( (slices & 1) == 1 )
652 slices += 1;
654 if ( (sides & 1) == 1 )
655 sides += 1;
657 OSG::Real32 cos_theta = OSG::osgCos(theta);
658 OSG::Real32 sin_theta = OSG::osgSin(theta);
660 OSG::Real32 d_body = h / slices;
662 OSG::Real32 delta_phi = 2.f * OSG::Pi / (sides-1);
664 OSG::Real32 two_inv_r = 2.0/r;
666 OSG::Vec3f ey(0,1,0);
668 typedef std::vector<OSG::Pnt3f> VecPntsT;
670 VecPntsT vecOddPnts(sides), vecEvenPnts(sides);
671 VecPntsT* pvecLast = &vecOddPnts;
672 VecPntsT* pvecCurr = &vecEvenPnts;
675 // First the superellipses body itself
677 OSG::Pnt3f pT(0,0,0); // tip of body
679 (*pvecLast)[0] = pT;
681 for (OSG::UInt32 j = 1; j <= slices; ++j)
683 OSG::Real32 l_body = j * d_body;
685 OSG::Pnt3f pR = pT + l_body * ey;
687 OSG::Real32 A = l_body * a;
688 OSG::Real32 B = l_body * b;
690 OSG::Real32 phi = 0.f;
692 for (OSG::UInt32 i = 0; i < sides-1; ++i)
694 OSG::Real32 c = OSG::osgCos(phi);
695 OSG::Real32 s = OSG::osgSin(phi);
697 OSG::Real32 x = A * OSG::osgSgn(c) * OSG::osgPow(OSG::osgAbs(c), two_inv_r);
698 OSG::Real32 z = B * OSG::osgSgn(s) * OSG::osgPow(OSG::osgAbs(s), two_inv_r);
700 OSG::Pnt3f p = pR + OSG::Vec3f(
701 x * cos_theta - z * sin_theta,
703 x * sin_theta + z * cos_theta
706 OSG::Real32 L = p.subZero().length();
708 if (L > h)
710 OSG::Vec3f v = p.subZero();
711 v.normalize();
712 v *= h;
713 p = v.addToZero();
716 (*pvecCurr)[i] = p;
718 phi += delta_phi;
721 (*pvecCurr)[sides-1] = (*pvecCurr)[0];
723 if (j == 1)
725 t->push_back(GL_TRIANGLE_FAN);
726 l->push_back(1 + sides);
728 p->push_back((*pvecLast)[0]);
729 n->push_back(OSG::Vec3f(0,-1,0));
731 for (OSG::UInt32 i = 0; i < sides; ++i)
733 p->push_back((*pvecCurr)[i]);
735 OSG::Vec3f v0;
736 OSG::Vec3f v1;
738 if (i < sides-1)
740 v0 = (*pvecCurr)[i] - (*pvecLast)[0];
741 v1 = (*pvecCurr)[i+1] - (*pvecLast)[0];
743 else if (i == sides-1)
745 v0 = (*pvecCurr)[0] - (*pvecLast)[0];
746 v1 = (*pvecCurr)[1] - (*pvecLast)[0];
749 OSG::Vec3f v = v1.cross(v0);
750 v.normalize();
751 n->push_back(v);
754 else
756 t->push_back(GL_TRIANGLE_STRIP);
757 l->push_back(2*sides);
759 for (OSG::UInt32 i = 0; i < sides; ++i)
761 p->push_back((*pvecLast)[i]);
762 p->push_back((*pvecCurr)[i]);
764 OSG::Vec3f v0;
765 OSG::Vec3f v1;
766 OSG::Vec3f v2;
768 if (i < sides-1)
770 v0 = (*pvecLast)[i+1] - (*pvecCurr)[i];
771 v1 = (*pvecLast)[i+1] - (*pvecLast)[i];
772 v2 = (*pvecCurr)[i+1] - (*pvecLast)[i+1];
774 else if (i == sides-1)
776 v0 = (*pvecLast)[1] - (*pvecCurr)[0];
777 v1 = (*pvecLast)[1] - (*pvecLast)[0];
778 v2 = (*pvecCurr)[1] - (*pvecLast)[1];
781 OSG::Vec3f n0 = v1.cross(v0);
782 OSG::Vec3f n1 = v2.cross(v1);
784 n0.normalize();
785 n1.normalize();
787 n->push_back(n0);
788 n->push_back(n1);
792 std::swap(pvecLast, pvecCurr);
796 // Second the sphere cap
798 OSG::Real32 delta_a = a / (slices - 1);
799 OSG::Real32 delta_b = b / (slices - 1);
801 OSG::Pnt3f pE = pT + h * ey;
803 for (OSG::Int32 j = slices-2; j >= 0; --j)
805 OSG::Real32 A = h * delta_a * j;
806 OSG::Real32 B = h * delta_b * j;
808 OSG::Real32 phi = 0.f;
810 for (OSG::UInt32 i = 0; i < sides-1; ++i)
812 OSG::Real32 c = OSG::osgCos(phi);
813 OSG::Real32 s = OSG::osgSin(phi);
815 OSG::Real32 x = A * OSG::osgSgn(c) * OSG::osgPow(OSG::osgAbs(c), two_inv_r);
816 OSG::Real32 z = B * OSG::osgSgn(s) * OSG::osgPow(OSG::osgAbs(s), two_inv_r);
818 OSG::Pnt3f p = pE + OSG::Vec3f(
819 x * cos_theta - z * sin_theta,
821 x * sin_theta + z * cos_theta
824 OSG::Real32 L = p.subZero().length();
826 if (L > h)
828 OSG::Vec3f v = p.subZero();
829 v.normalize();
830 v *= h;
831 p = v.addToZero();
834 (*pvecCurr)[i] = p;
836 phi += delta_phi;
839 (*pvecCurr)[sides-1] = (*pvecCurr)[0];
841 if (j < OSG::Int32(slices-1) && j > 0)
843 t->push_back(GL_TRIANGLE_STRIP);
844 l->push_back(2*sides);
846 for (OSG::UInt32 i = 0; i < sides; ++i)
848 p->push_back((*pvecLast)[i]);
849 p->push_back((*pvecCurr)[i]);
851 OSG::Vec3f v0;
852 OSG::Vec3f v1;
853 OSG::Vec3f v2;
855 if (i < sides-1)
857 v0 = (*pvecLast)[i+1] - (*pvecCurr)[i];
858 v1 = (*pvecLast)[i+1] - (*pvecLast)[i];
859 v2 = (*pvecCurr)[i+1] - (*pvecLast)[i+1];
861 else if (i == sides-1)
863 v0 = (*pvecLast)[1] - (*pvecCurr)[0];
864 v1 = (*pvecLast)[1] - (*pvecLast)[0];
865 v2 = (*pvecCurr)[1] - (*pvecLast)[1];
868 OSG::Vec3f n0 = v1.cross(v0);
869 OSG::Vec3f n1 = v2.cross(v1);
871 n0.normalize();
872 n1.normalize();
874 n->push_back(n0);
875 n->push_back(n1);
879 if (j == 1)
881 t->push_back(GL_TRIANGLE_FAN);
882 l->push_back(1 + sides);
884 p->push_back(pE);
885 n->push_back(OSG::Vec3f(0,1,0));
887 for (OSG::Int32 i = sides-1; i >= 0; --i)
889 p->push_back((*pvecCurr)[i]);
891 OSG::Vec3f v0;
892 OSG::Vec3f v1;
894 if (i < OSG::Int32(sides-1))
896 v0 = (*pvecCurr)[i] - pE;
897 v1 = (*pvecCurr)[i+1] - pE;
899 else if (i == sides-1)
901 v0 = (*pvecCurr)[0] - pE;
902 v1 = (*pvecCurr)[1] - pE;
905 OSG::Vec3f v = v1.cross(v0);
906 v.normalize();
907 n->push_back(v);
911 std::swap(pvecLast, pvecCurr);
914 OSG::GeometryTransitPtr geo = OSG::Geometry::create();
916 geo->setTypes (types);
917 geo->setLengths (lens);
918 geo->setPositions(pnts);
919 geo->setNormals (norms);
921 geo->setMaterial(OSG::getDefaultUnlitMaterial());
923 return geo;
926 OSG::GeometryTransitPtr makePyramidGeo(
927 const OSG::Pnt3f& nlt, const OSG::Pnt3f& nlb,
928 const OSG::Pnt3f& nrt, const OSG::Pnt3f& nrb,
929 const OSG::Pnt3f& flt, const OSG::Pnt3f& flb,
930 const OSG::Pnt3f& frt, const OSG::Pnt3f& frb)
932 OSG::GeoUInt8PropertyRefPtr type = OSG::GeoUInt8Property::create();
933 type->addValue(GL_QUADS);
935 OSG::GeoUInt32PropertyRefPtr lens = OSG::GeoUInt32Property::create();
936 lens->addValue(6 * 4);
938 OSG::GeoPnt3fPropertyRefPtr pnts = OSG::GeoPnt3fProperty::create();
939 // front face
940 pnts->addValue(nlb);
941 pnts->addValue(nrb);
942 pnts->addValue(nrt);
943 pnts->addValue(nlt);
945 // back face
946 pnts->addValue(frb);
947 pnts->addValue(flb);
948 pnts->addValue(flt);
949 pnts->addValue(frt);
951 // left face
952 pnts->addValue(flb);
953 pnts->addValue(nlb);
954 pnts->addValue(nlt);
955 pnts->addValue(flt);
957 // right face
958 pnts->addValue(nrb);
959 pnts->addValue(frb);
960 pnts->addValue(frt);
961 pnts->addValue(nrt);
963 // top face
964 pnts->addValue(nrt);
965 pnts->addValue(frt);
966 pnts->addValue(flt);
967 pnts->addValue(nlt);
969 // bottom face
970 pnts->addValue(nlb);
971 pnts->addValue(flb);
972 pnts->addValue(frb);
973 pnts->addValue(nrb);
975 OSG::GeoVec3fPropertyRefPtr normals = OSG::GeoVec3fProperty::create();
976 OSG::Vec3f v1, v2, n;
978 // front face
979 v1 = nrb - nlb; v2 = nlt - nlb; n = v1.cross(v2); n.normalize(); for (int i = 0; i < 4; ++i) normals->addValue(n);
981 // back face
982 v1 = flb - frb; v2 = frt - frb; n = v1.cross(v2); n.normalize(); for (int i = 0; i < 4; ++i) normals->addValue(n);
984 // left face
985 v1 = nlb - flb; v2 = flt - flb; n = v1.cross(v2); n.normalize(); for (int i = 0; i < 4; ++i) normals->addValue(n);
987 // right face
988 v1 = frb - nrb; v2 = nrt - nrb; n = v1.cross(v2); n.normalize(); for (int i = 0; i < 4; ++i) normals->addValue(n);
990 // top face
991 v1 = frt - nrt; v2 = nlt - nrt; n = v1.cross(v2); n.normalize(); for (int i = 0; i < 4; ++i) normals->addValue(n);
993 // bottom face
994 v1 = flb - nlb; v2 = nrb - nlb; n = v1.cross(v2); n.normalize(); for (int i = 0; i < 4; ++i) normals->addValue(n);
996 OSG::GeometryTransitPtr geo = OSG::Geometry::create();
998 geo->setTypes (type);
999 geo->setLengths (lens);
1000 geo->setPositions(pnts);
1001 geo->setNormals (normals);
1003 geo->setMaterial(OSG::getDefaultUnlitMaterial());
1005 return geo;
1008 // ============================================================================
1010 // Part: Declaration/Implementation of
1011 // - type VecImageDataT
1012 // - type VecLightIndexT
1013 // - struct DispatchData
1014 // - struct ClusteringData
1015 // - struct TestData
1016 // - light grid image
1017 // - light grid texture object
1018 // - light grid image texture chunk
1019 // - struct Frustum and VecFrustumsT
1020 // - NdcFromScreen, NdcFromScreen, ClipFromNdc, EyeFromClip, EyeFromNdc
1021 // - calc_ortho_frustums_cpu
1022 // - calc_persp_frustums_cpu
1023 // - create_frustum_state, update_frustum_state
1024 // - create_index_state, update_index_state
1025 // - create_light_index_counter_state
1026 // - struct Sphere and struct Cone
1027 // - SphereInsidePlane, SphereInsideFrustum, PointInsidePlane, ConeInsidePlane, ConeInsideFrustum
1028 // - transformToEyeSpace
1029 // - PointLightInsideFrustum, SpotLightInsideFrustum
1030 // - cluster_k, cluster_z, cluster_test
1031 // - cullLights
1032 // - struct Light and type VecLightsT,
1033 // - struct Material and type VecMaterialsT,
1034 // - struct GeomState
1035 // and corresponding initialization routines.
1037 // ============================================================================
1039 typedef std::vector<std::pair<OSG::UInt32, OSG::UInt32> > VecImageDataT;
1040 typedef std::vector<OSG::UInt32> VecLightIndexT;
1043 // Data used by the frustum plane computation shader
1045 struct DispatchData
1047 DispatchData() : matTransf(), viewport(), numTiles() {}
1049 OSG::Matrix matTransf;
1050 OSG::Vec4u viewport;
1051 OSG::Vec2i numTiles;
1053 static OSG::UInt32 matTransf_id;
1054 static OSG::UInt32 viewport_id;
1055 static OSG::UInt32 numTiles_id;
1058 OSG::UInt32 DispatchData::matTransf_id = 0;
1059 OSG::UInt32 DispatchData::viewport_id = 0;
1060 OSG::UInt32 DispatchData::numTiles_id = 0;
1062 OSG::UniformBufferObjChunkTransitPtr create_dispatch_data(const DispatchData& data)
1064 OSG::UniformBufferObjChunkRefPtr chunk = OSG::UniformBufferObjChunk::create();
1066 DispatchData::matTransf_id = chunk->addMat4 ("DispatchData.matTransf");
1067 DispatchData:: viewport_id = chunk->addUVec4("DispatchData.viewport");
1068 DispatchData:: numTiles_id = chunk->addIVec2("DispatchData.numTiles");
1070 chunk->setMat4 (DispatchData::matTransf_id, data.matTransf);
1071 chunk->setUVec4(DispatchData:: viewport_id, data.viewport);
1072 chunk->setIVec2(DispatchData:: numTiles_id, data.numTiles);
1074 chunk->setBlockName("DispatchData");
1075 chunk->setUsage(GL_DYNAMIC_DRAW);
1077 return OSG::UniformBufferObjChunkTransitPtr(chunk);
1080 void update_dispatch_data(OSG::UniformBufferObjChunk* chunk, const DispatchData& data)
1082 if (chunk)
1084 chunk->setMat4 (DispatchData::matTransf_id, data.matTransf);
1085 chunk->setUVec4(DispatchData:: viewport_id, data.viewport);
1086 chunk->setIVec2(DispatchData:: numTiles_id, data.numTiles);
1091 // The clustering data is used in the light cull shader and in the fragment shader.
1092 // Its data is used for:
1093 // - the cluster_k key evaluation
1094 // - the cluster_z eye space z evaluation
1096 // At the moment we support two cluster_k/cluster_z functions: cluster_k/cluster_z and cluster_k_verbose/cluster_z_verbose.
1097 // Ultimatively only the cluster_k/cluster_z variant will be used. The other one is only for
1098 // testing purpose.
1100 struct ClusteringData
1102 ClusteringData()
1103 : zNear(0.f)
1104 , zFar(0.f)
1105 //, D(0.f)
1106 , nD(0.f)
1107 , a(0.f)
1108 , b(0.f)
1109 //, c(0)
1110 , c_1(0)
1111 , p_v(0,0)
1112 //, n_c(0,0,0)
1113 , t_v(0)
1116 OSG::Real32 zNear; // positive near plane distance from eye zNear > 0
1117 OSG::Real32 zFar; // positive far plane distance from eye zFar > zNear > 0
1118 //OSG::Real32 D; // positive near plane offset D >= 0 // for testing
1119 OSG::Real32 nD; // zNear + D : shader optimization
1120 OSG::Real32 lg_nD; // log2(nD) : shader optimization
1121 OSG::Real32 a; // precalculated factor (c-1)/log2(f/(n+D))
1122 OSG::Real32 b; // precalculated factor log2(f/(n+D))/(c-1)
1123 //OSG::Int32 c; // number of cluster planes // for testing
1124 OSG::Int32 c_1; // number of cluster planes minus one : shader optimization
1125 OSG::Vec2i p_v; // viewport corner points
1126 //OSG::Vec3i n_c; // number of clusters // for testing
1127 OSG::Int32 t_v; // test dependent content // for testing
1129 static OSG::UInt32 zNear_id;
1130 static OSG::UInt32 zFar_id;
1131 //static OSG::UInt32 D_id;
1132 static OSG::UInt32 nD_id;
1133 static OSG::UInt32 lg_nD_id;
1134 static OSG::UInt32 a_id;
1135 static OSG::UInt32 b_id;
1136 //static OSG::UInt32 c_id;
1137 static OSG::UInt32 c_1_id;
1138 static OSG::UInt32 p_v_id;
1139 //static OSG::UInt32 n_c_id;
1140 static OSG::UInt32 t_v_id;
1143 OSG::UInt32 ClusteringData::zNear_id = 0;
1144 OSG::UInt32 ClusteringData:: zFar_id = 0;
1145 //OSG::UInt32 ClusteringData:: D_id = 0;
1146 OSG::UInt32 ClusteringData:: nD_id = 0;
1147 OSG::UInt32 ClusteringData::lg_nD_id = 0;
1148 OSG::UInt32 ClusteringData:: a_id = 0;
1149 OSG::UInt32 ClusteringData:: b_id = 0;
1150 //OSG::UInt32 ClusteringData:: c_id = 0;
1151 OSG::UInt32 ClusteringData:: c_1_id = 0;
1152 OSG::UInt32 ClusteringData:: p_v_id = 0;
1153 //OSG::UInt32 ClusteringData:: n_c_id = 0;
1154 OSG::UInt32 ClusteringData:: t_v_id = 0;
1156 OSG::UniformBufferObjChunkTransitPtr create_clustering_data(const ClusteringData& data)
1158 OSG::UniformBufferObjChunkRefPtr chunk = OSG::UniformBufferObjChunk::create();
1160 ClusteringData::zNear_id = chunk->addFloat("ClusteringData.zNear");
1161 ClusteringData:: zFar_id = chunk->addFloat("ClusteringData.zFar");
1162 //ClusteringData:: D_id = chunk->addFloat("ClusteringData.D");
1163 ClusteringData:: nD_id = chunk->addFloat("ClusteringData.nD");
1164 ClusteringData::lg_nD_id = chunk->addFloat("ClusteringData.lg_nD");
1165 ClusteringData:: a_id = chunk->addFloat("ClusteringData.a");
1166 ClusteringData:: b_id = chunk->addFloat("ClusteringData.b");
1167 //ClusteringData:: c_id = chunk->addInt ("ClusteringData.c");
1168 ClusteringData:: c_1_id = chunk->addInt ("ClusteringData.c_1");
1169 ClusteringData:: p_v_id = chunk->addIVec2("ClusteringData.p_v");
1170 //ClusteringData:: n_c_id = chunk->addIVec3("ClusteringData.n_c");
1171 ClusteringData:: t_v_id = chunk->addInt ("ClusteringData.t_v");
1173 chunk->setFloat(ClusteringData::zNear_id, data.zNear);
1174 chunk->setFloat(ClusteringData:: zFar_id, data.zFar);
1175 //chunk->setFloat(ClusteringData:: D_id, data.D);
1176 chunk->setFloat(ClusteringData:: nD_id, data.nD);
1177 chunk->setFloat(ClusteringData::lg_nD_id, data.lg_nD);
1178 chunk->setFloat(ClusteringData:: a_id, data.a);
1179 chunk->setFloat(ClusteringData:: b_id, data.b);
1180 //chunk->setInt (ClusteringData:: c_id, data.c);
1181 chunk->setInt (ClusteringData:: c_1_id, data.c_1);
1182 chunk->setIVec2(ClusteringData:: p_v_id, data.p_v);
1183 //chunk->setIVec3(ClusteringData:: n_c_id, data.n_c);
1184 chunk->setInt (ClusteringData:: t_v_id, data.t_v);
1186 chunk->setBlockName("ClusteringData");
1187 chunk->setUsage(GL_STATIC_DRAW);
1189 return OSG::UniformBufferObjChunkTransitPtr(chunk);
1192 void update_clustering_data(OSG::UniformBufferObjChunk* chunk, const ClusteringData& data)
1194 if (chunk)
1196 chunk->setFloat(ClusteringData::zNear_id, data.zNear);
1197 chunk->setFloat(ClusteringData:: zFar_id, data.zFar);
1198 //chunk->setFloat(ClusteringData:: D_id, data.D);
1199 chunk->setFloat(ClusteringData:: nD_id, data.nD);
1200 chunk->setFloat(ClusteringData::lg_nD_id, data.lg_nD);
1201 chunk->setFloat(ClusteringData:: a_id, data.a);
1202 chunk->setFloat(ClusteringData:: b_id, data.b);
1203 //chunk->setInt (ClusteringData:: c_id, data.c);
1204 chunk->setInt (ClusteringData:: c_1_id, data.c_1);
1205 chunk->setIVec2(ClusteringData:: p_v_id, data.p_v);
1206 //chunk->setIVec3(ClusteringData:: n_c_id, data.n_c);
1207 chunk->setInt (ClusteringData:: t_v_id, data.t_v);
1212 // The test data is used to compare the cpu with gpu computation
1214 struct TestData
1216 static const OSG::UInt32 num_array_elements = num_test_val_entries;
1217 TestData()
1218 : value01(0.f)
1219 , value02(0.f)
1220 , value03(0.f)
1221 , value04(0.f)
1222 , value05(0.f,0.f,0.f)
1223 , value06(0.f,0.f,0.f)
1224 , value07(0)
1225 , value08(0)
1226 , value09(0)
1227 , value10(0)
1228 , value11(0,0,0)
1229 , value12(0,0,0)
1230 , value13(num_array_elements, 0.f)
1231 , value14(num_array_elements, 0.f)
1232 , value15(num_array_elements, 0)
1233 , value16(num_array_elements, OSG::Vec3f(0.f,0.f,0.f))
1234 , value17(num_array_elements, OSG::Vec3f(0.f,0.f,0.f))
1237 void clear()
1239 value01 = 0.f;
1240 value02 = 0.f;
1241 value03 = 0.f;
1242 value04 = 0.f;
1243 value05 = OSG::Vec3f(0.f,0.f,0.f);
1244 value06 = OSG::Vec3f(0.f,0.f,0.f);
1245 value07 = 0;
1246 value08 = 0;
1247 value09 = 0;
1248 value10 = 0;
1249 value11 = OSG::Vec3i(0,0,0);
1250 value12 = OSG::Vec3u(0,0,0);
1252 for (OSG::UInt32 i = 0; i < num_array_elements; ++i)
1254 value13[i] = 0.f;
1255 value14[i] = 0.f;
1256 value15[i] = 0;
1257 value16[i] = OSG::Vec3f(0.f,0.f,0.f);
1258 value17[i] = OSG::Vec3f(0.f,0.f,0.f);
1262 OSG::Real32 value01;
1263 OSG::Real32 value02;
1264 OSG::Real32 value03;
1265 OSG::Real32 value04;
1266 OSG::Vec3f value05;
1267 OSG::Vec3f value06;
1268 OSG::Int32 value07;
1269 OSG::Int32 value08;
1270 OSG::UInt32 value09;
1271 OSG::UInt32 value10;
1272 OSG::Vec3i value11;
1273 OSG::Vec3u value12;
1275 std::vector<OSG::Real32> value13;
1276 std::vector<OSG::Real32> value14;
1277 std::vector<OSG::UInt32> value15;
1278 std::vector<OSG::Vec3f> value16;
1279 std::vector<OSG::Vec3f> value17;
1282 TestData globalTestData;
1284 std::size_t calc_test_data_buffer_size(const TestData& data)
1286 std::size_t ao = 0; // aligned offset
1287 std::size_t bo = 0; // base offset
1289 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::Real32);
1290 ao = OSG::alignOffset( 4, bo); bo = ao;
1291 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::Real32);
1292 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::Real32);
1293 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::Real32);
1295 ao = OSG::alignOffset(16, bo); bo = ao + sizeof(OSG::Vec3f);
1296 ao = OSG::alignOffset(16, bo); bo = ao + sizeof(OSG::Vec3f);
1298 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::Int32);
1299 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::Int32);
1301 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::UInt32);
1302 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::UInt32);
1304 ao = OSG::alignOffset(16, bo); bo = ao + sizeof(OSG::Vec3i);
1305 ao = OSG::alignOffset(16, bo); bo = ao + sizeof(OSG::Vec3u);
1307 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1309 ao = OSG::alignOffset( 4, bo);
1310 bo = ao + sizeof(OSG::Real32);
1312 ao = OSG::alignOffset( 4, bo); bo = ao;
1314 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1316 ao = OSG::alignOffset( 4, bo);
1317 bo = ao + sizeof(OSG::Real32);
1319 ao = OSG::alignOffset( 4, bo); bo = ao;
1321 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1323 ao = OSG::alignOffset( 4, bo);
1324 bo = ao + sizeof(OSG::UInt32);
1326 ao = OSG::alignOffset( 4, bo); bo = ao;
1328 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1330 ao = OSG::alignOffset(16, bo);
1331 bo = ao + sizeof(OSG::Vec3f);
1333 ao = OSG::alignOffset(16, bo); bo = ao;
1335 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1337 ao = OSG::alignOffset(16, bo);
1338 bo = ao + sizeof(OSG::Vec3f);
1340 ao = OSG::alignOffset(16, bo); bo = ao;
1342 return ao;
1345 std::vector<OSG::UInt8> create_test_data_buffer(const TestData& data)
1347 std::size_t size = calc_test_data_buffer_size(data);
1349 std::vector<OSG::UInt8> buffer(size);
1351 std::size_t ao = 0; // aligned offset
1352 std::size_t bo = 0; // base offset
1354 ao = OSG::alignOffset( 4, bo);
1355 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = data.value01;
1356 bo = ao + sizeof(OSG::Real32);
1358 ao = OSG::alignOffset( 4, bo);
1359 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = data.value02;
1360 bo = ao + sizeof(OSG::Real32);
1362 ao = OSG::alignOffset( 4, bo);
1363 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = data.value03;
1364 bo = ao + sizeof(OSG::Real32);
1366 ao = OSG::alignOffset( 4, bo);
1367 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = data.value04;
1368 bo = ao + sizeof(OSG::Real32);
1370 ao = OSG::alignOffset(16, bo);
1371 memcpy(&buffer[0] + ao, &data.value05[0], sizeof(OSG::Vec3f));
1372 bo = ao + sizeof(OSG::Vec3f);
1374 ao = OSG::alignOffset(16, bo);
1375 memcpy(&buffer[0] + ao, &data.value06[0], sizeof(OSG::Vec3f));
1376 bo = ao + sizeof(OSG::Vec3f);
1378 ao = OSG::alignOffset( 4, bo);
1379 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = data.value07;
1380 bo = ao + sizeof(OSG::Int32);
1382 ao = OSG::alignOffset( 4, bo);
1383 *(reinterpret_cast<OSG::Int32*>(&buffer[0] + ao)) = data.value08;
1384 bo = ao + sizeof(OSG::Int32);
1386 ao = OSG::alignOffset( 4, bo);
1387 *(reinterpret_cast<OSG::UInt32*>(&buffer[0] + ao)) = data.value09;
1388 bo = ao + sizeof(OSG::UInt32);
1390 ao = OSG::alignOffset( 4, bo);
1391 *(reinterpret_cast<OSG::UInt32*>(&buffer[0] + ao)) = data.value10;
1392 bo = ao + sizeof(OSG::UInt32);
1394 ao = OSG::alignOffset(16, bo);
1395 memcpy(&buffer[0] + ao, &data.value11[0], sizeof(OSG::Vec3i));
1396 bo = ao + sizeof(OSG::Vec3i);
1398 ao = OSG::alignOffset(16, bo);
1399 memcpy(&buffer[0] + ao, &data.value12[0], sizeof(OSG::Vec3u));
1400 bo = ao + sizeof(OSG::Vec3u);
1402 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1404 ao = OSG::alignOffset( 4, bo);
1405 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = data.value13[i];
1406 bo = ao + sizeof(OSG::Real32);
1408 ao = OSG::alignOffset( 4, bo); bo = ao;
1410 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1412 ao = OSG::alignOffset( 4, bo);
1413 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = data.value14[i];
1414 bo = ao + sizeof(OSG::Real32);
1416 ao = OSG::alignOffset( 4, bo); bo = ao;
1418 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1420 ao = OSG::alignOffset( 4, bo);
1421 *(reinterpret_cast<OSG::UInt32*>(&buffer[0] + ao)) = data.value15[i];
1422 bo = ao + sizeof(OSG::UInt32);
1424 ao = OSG::alignOffset( 4, bo); bo = ao;
1426 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1428 ao = OSG::alignOffset(16, bo);
1429 memcpy(&buffer[0] + ao, &data.value16[i][0], sizeof(OSG::Vec3f));
1430 bo = ao + sizeof(OSG::Vec3f);
1432 ao = OSG::alignOffset(16, bo); bo = ao;
1434 for (OSG::UInt32 i = 0; i < TestData::num_array_elements; ++i)
1436 ao = OSG::alignOffset(16, bo);
1437 memcpy(&buffer[0] + ao, &data.value17[i][0], sizeof(OSG::Vec3f));
1438 bo = ao + sizeof(OSG::Vec3f);
1440 ao = OSG::alignOffset(16, bo); bo = ao;
1442 return buffer;
1445 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_test_data(const TestData& data)
1447 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1449 std::vector<OSG::UInt8> buffer = create_test_data_buffer(data);
1451 ssbo->editMFBuffer()->setValues(buffer);
1452 ssbo->setUsage(GL_DYNAMIC_DRAW);
1454 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
1457 void update_test_data(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const TestData& data)
1459 if (ssbo) {
1460 std::vector<OSG::UInt8> buffer = create_test_data_buffer(data);
1461 ssbo->editMFBuffer()->setValues(buffer);
1466 // The light grid is basically an image represented by a TexureImageChunk and TextureObjChunk
1468 OSG::ImageTransitPtr create_image(OSG::UInt32 width,
1469 OSG::UInt32 height,
1470 OSG::UInt32 depth,
1471 bool allocate_memory)
1473 OSG::ImageRefPtr image = OSG::Image::create();
1474 image->set(
1475 GL_RG, // pixel format
1476 width, // width in pixel
1477 height, // height in pixel
1478 depth, // depth in pixel
1479 1, // mipmap count
1480 1, // frame count
1481 0.0, // frame delay
1482 NULL, // data
1483 OSG::Image::OSG_UINT32_IMAGEDATA, // type
1484 allocate_memory, // allocate memory
1485 1 // side count
1487 return OSG::ImageTransitPtr(image);
1490 void update_image(
1491 OSG::Image* image,
1492 OSG::UInt32 width,
1493 OSG::UInt32 height,
1494 OSG::UInt32 depth,
1495 bool allocate_memory)
1497 image->set(
1498 GL_RG, // pixel format
1499 width, // width in pixel
1500 height, // height in pixel
1501 depth, // depth in pixel
1502 1, // mipmap count
1503 1, // frame count
1504 0.0, // frame delay
1505 NULL, // data
1506 OSG::Image::OSG_UINT32_IMAGEDATA, // type
1507 allocate_memory, // allocate memory
1508 1 // side count
1512 void update_image_data(OSG::Image* image, const VecImageDataT& imageData)
1514 OSG::UInt8* data = image->editData();
1516 std::size_t ao = 0; // aligned offset
1517 std::size_t bo = 0; // base offset
1519 for (std::size_t i = 0; i < imageData.size(); ++i)
1521 OSG::UInt32 offset = imageData[i].first;
1522 OSG::UInt32 index = imageData[i].second;
1524 ao = OSG::alignOffset(4, bo);
1525 *(reinterpret_cast<OSG::UInt32*>(data + ao)) = offset;
1526 bo = ao + sizeof(OSG::UInt32);
1528 ao = OSG::alignOffset(4, bo);
1529 *(reinterpret_cast<OSG::UInt32*>(data + ao)) = index;
1530 bo = ao + sizeof(OSG::UInt32);
1534 void write_image_data(
1535 OSG::UInt32 i,
1536 OSG::UInt32 j,
1537 OSG::UInt32 k,
1538 const OSG::Vec3u& dimensions,
1539 const std::pair<OSG::UInt32, OSG::UInt32>& data,
1540 VecImageDataT& imageData)
1542 OSG_ASSERT(i < dimensions.x());
1543 OSG_ASSERT(j < dimensions.y());
1544 OSG_ASSERT(k < dimensions.z());
1546 std::size_t idx = k * dimensions.x() * dimensions.y() + j * dimensions.x() + i;
1548 imageData[idx] = data;
1551 OSG::TextureObjChunkTransitPtr create_texture_state(OSG::Image* image)
1553 OSG::TextureObjChunkRefPtr texObjChunk = OSG::TextureObjChunk::create();
1555 texObjChunk->setTarget(GL_TEXTURE_2D_ARRAY);
1556 texObjChunk->setScale(false);
1557 texObjChunk->setInternalFormat(GL_RG32UI);
1558 texObjChunk->setExternalFormat(GL_RG_INTEGER);
1559 texObjChunk->setMinFilter(GL_NEAREST);
1560 texObjChunk->setMagFilter(GL_NEAREST);
1561 texObjChunk->setImage(image);
1563 return OSG::TextureObjChunkTransitPtr(texObjChunk);
1566 void update_texture_state(OSG::TextureObjChunk* texObjChunk)
1568 texObjChunk->imageContentChanged();
1571 OSG::TextureImageChunkTransitPtr create_texture_image_state(
1572 OSG::TextureObjChunk* texObjChunk,
1573 const GLenum access)
1575 OSG::TextureImageChunkRefPtr texImageChunk = OSG::TextureImageChunk::create();
1576 texImageChunk->setTexture(texObjChunk);
1577 texImageChunk->setAccess(access);
1578 texImageChunk->setFormat(GL_RG32UI);
1579 texImageChunk->setLayer(-1);
1581 return OSG::TextureImageChunkTransitPtr(texImageChunk);
1584 void update_light_grid_image(
1585 const OSG::Vec4u& viewport,
1586 OSG::Image* image,
1587 bool allocate_memory)
1589 OSG::Real32 w = static_cast<OSG::Real32>(viewport[2]);
1590 OSG::Real32 h = static_cast<OSG::Real32>(viewport[3]);
1592 OSG::UInt32 numHorizontalTiles = OSG::UInt32(OSG::osgCeil(w / tile_size));
1593 OSG::UInt32 numVerticalTiles = OSG::UInt32(OSG::osgCeil(h / tile_size));
1595 update_image(image , numHorizontalTiles, numVerticalTiles, num_cluster_z, allocate_memory);
1598 void fill_test_data_light_grid_image(
1599 const OSG::Vec4u& viewport,
1600 OSG::Image* image)
1602 OSG::Real32 w = static_cast<OSG::Real32>(viewport[2]);
1603 OSG::Real32 h = static_cast<OSG::Real32>(viewport[3]);
1605 OSG::UInt32 sz_i = OSG::UInt32(OSG::osgCeil(w / tile_size));
1606 OSG::UInt32 sz_j = OSG::UInt32(OSG::osgCeil(h / tile_size));
1607 OSG::UInt32 sz_k = num_cluster_z;
1609 OSG::Vec3u dimensions(sz_i, sz_j, sz_k);
1610 OSG::UInt32 sz = dimensions.x() * dimensions.y() * dimensions.z();
1612 VecImageDataT imageData(sz, std::make_pair(0,0));
1614 const OSG::UInt32 uiHeatMapColor0 = 0; // Black
1615 const OSG::UInt32 uiHeatMapColor1 = 1; // DarkSlateGray
1616 const OSG::UInt32 uiHeatMapColor2 = 2; // Navy
1617 const OSG::UInt32 uiHeatMapColor3 = 3; // Blue
1618 const OSG::UInt32 uiHeatMapColor4 = 4; // RoyalBlue
1619 const OSG::UInt32 uiHeatMapColor5 = 5; // DodgerBlue
1620 const OSG::UInt32 uiHeatMapColor6 = 6; // DeepSkyBlue
1621 const OSG::UInt32 uiHeatMapColor7 = 7; // Turquoise
1622 const OSG::UInt32 uiHeatMapColor8 = 8; // Aquamarine
1623 const OSG::UInt32 uiHeatMapColor9 = 9; // Cyan
1624 const OSG::UInt32 uiHeatMapColor10 = 10; // DarkGreen
1625 const OSG::UInt32 uiHeatMapColor11 = 11; // Green
1626 const OSG::UInt32 uiHeatMapColor12 = 12; // SpringGreen
1627 const OSG::UInt32 uiHeatMapColor13 = 13; // Lime
1628 const OSG::UInt32 uiHeatMapColor14 = 14; // Chartreuse
1629 const OSG::UInt32 uiHeatMapColor15 = 15; // GreenYellow
1630 const OSG::UInt32 uiHeatMapColor16 = 16; // Yellow
1631 const OSG::UInt32 uiHeatMapColor17 = 17; // Gold
1632 const OSG::UInt32 uiHeatMapColor18 = 18; // DarkOrange
1633 const OSG::UInt32 uiHeatMapColor19 = 19; // OrangeRed
1634 const OSG::UInt32 uiHeatMapColor20 = 20; // Red
1635 const OSG::UInt32 uiHeatMapColor21 = 21; // FireBrick
1636 const OSG::UInt32 uiHeatMapColor22 = 22; // DarkRed
1637 const OSG::UInt32 uiHeatMapColor23 = 23; // BlueViolet
1638 const OSG::UInt32 uiHeatMapColor24 = 24; // Fuchsia
1639 const OSG::UInt32 uiHeatMapColor25 = 25; // DeepPink
1640 const OSG::UInt32 uiHeatMapColor26 = 26; // HotPink
1641 const OSG::UInt32 uiHeatMapColor27 = 27; // Pink
1642 const OSG::UInt32 uiHeatMapColor28 = 28; // MistyRose
1643 const OSG::UInt32 uiHeatMapColor29 = 29; // LavenderBlush
1644 const OSG::UInt32 uiHeatMapColor30 = 30; // Seashell
1645 const OSG::UInt32 uiHeatMapColor31 = 31; // White
1647 for (OSG::UInt32 k = 0; k < dimensions.z(); ++k)
1649 for (OSG::UInt32 j = 0; j < dimensions.y(); ++j)
1651 for (OSG::UInt32 i = 0; i < dimensions.x(); ++i)
1653 OSG::UInt32 light_start_offset, light_count;
1655 if (i == 0 && j == 0)
1657 light_start_offset = 7345698 + uiHeatMapColor13;
1658 light_count = 563472981 + k;
1660 else if (i == dimensions.x()-1 && j == dimensions.y()-1)
1662 light_start_offset = 7345698 + uiHeatMapColor13;
1663 light_count = 563472981 + uiHeatMapColor8;
1665 else
1667 light_start_offset = 7345698 + uiHeatMapColor13;
1668 light_count = 563472981 + k;
1671 //int rnd = classic_die()*classic_die()*classic_die() + classic_die()*classic_die() + classic_die();
1673 write_image_data(i, j, k, dimensions, std::make_pair(light_start_offset, light_count), imageData);
1678 update_image_data(image, imageData);
1682 // simple frustum with only left, right, top and bottom planes. Front and back
1683 // planes are calculated differently.
1685 struct Frustum
1687 OSG::Plane planes[4];
1689 static bool visualize;
1692 bool Frustum::visualize = false;
1694 typedef std::vector<Frustum> VecFrustumsT;
1696 VecFrustumsT frustums_cpu(1);
1698 OSG::Pnt4f NdcFromScreen(
1699 const OSG::Pnt3f& p_w,
1700 const OSG::Vec4u& viewport,
1701 OSG::Real32 zNear,
1702 OSG::Real32 zFar)
1704 OSG::Real32 x_v = static_cast<OSG::Real32>(viewport[0]);
1705 OSG::Real32 y_v = static_cast<OSG::Real32>(viewport[1]);
1706 OSG::Real32 w = static_cast<OSG::Real32>(viewport[2]);
1707 OSG::Real32 h = static_cast<OSG::Real32>(viewport[3]);
1709 OSG::Pnt4f p_n(
1710 2.f * (p_w.x() - x_v) / w - 1.f,
1711 2.f * (p_w.y() - y_v) / h - 1.f,
1712 2.f * (p_w.z() - zFar - zNear) / (zFar - zNear),
1715 return p_n;
1718 OSG::Pnt4f NdcFromScreen(
1719 const OSG::Pnt3f& p_w, // with z-coord already given in ndc coords!
1720 const OSG::Vec4u& viewport)
1722 OSG::Real32 x_v = static_cast<OSG::Real32>(viewport[0]);
1723 OSG::Real32 y_v = static_cast<OSG::Real32>(viewport[1]);
1724 OSG::Real32 w = static_cast<OSG::Real32>(viewport[2]);
1725 OSG::Real32 h = static_cast<OSG::Real32>(viewport[3]);
1727 OSG::Pnt4f p_n(
1728 2.f * (p_w.x() - x_v) / w - 1.f,
1729 2.f * (p_w.y() - y_v) / h - 1.f,
1730 p_w.z(),
1733 return p_n;
1736 OSG::Pnt4f ClipFromNdc(const OSG::Pnt4f& p_n, const OSG::Matrix& matProjection)
1738 // Mathematically: m(row x col)
1739 // ----------------------------
1740 // columns: c0 c1 c2 c3
1741 // (m00 m01 m02 m03) // row 0 ( 1 2 3 4 )
1742 // M = (m10 m11 m12 m13) // row 1 M = ( 5 6 7 8 )
1743 // (m20 m21 m22 m23) // row 2 ( 9 10 11 12 )
1744 // (m30 m31 m32 m33) // row 3 (13 14 15 16 )
1746 // col 0 col 1 col 2 col 3
1747 //OSG::Real32 m00 = 1, m01 = 2, m02 = 3, m03 = 4, // row 0
1748 // m10 = 5, m11 = 6, m12 = 7, m13 = 8, // row 1
1749 // m20 = 9, m21 =10, m22 =11, m23 =12, // row 2
1750 // m30 =13, m31 =14, m32 =15, m33 =16; // row 3
1752 // OpenSG stores internally the transposed of the matrix as 4 row vectors
1754 // ( _matrix[0] ) ( _matrix[0][0] _matrix[0][1] _matrix[0][2] _matrix[0][3] )
1755 // Matrix = ( _matrix[1] ) = ( _matrix[1][0] _matrix[1][1] _matrix[1][2] _matrix[1][3] )
1756 // ( _matrix[2] ) ( _matrix[2][0] _matrix[2][1] _matrix[2][2] _matrix[2][3] )
1757 // ( _matrix[3] ) ( _matrix[3][0] _matrix[3][1] _matrix[3][2] _matrix[3][3] )
1759 // ( _matrix[0][0]=m00 _matrix[0][1]=m10 _matrix[0][2]=m20 _matrix[0][3]=m30 )
1760 // = ( _matrix[1][0]=m01 _matrix[1][1]=m11 _matrix[1][2]=m21 _matrix[1][3]=m31 )
1761 // ( _matrix[2][0]=m02 _matrix[2][1]=m12 _matrix[2][2]=m22 _matrix[2][3]=m32 )
1762 // ( _matrix[3][0]=m03 _matrix[3][1]=m13 _matrix[3][2]=m23 _matrix[3][3]=m33 )
1764 // ( m00 m10 m20 m30 ) T
1765 // = ( m01 m11 m21 m31 ) = M
1766 // ( m02 m12 m22 m32 )
1767 // ( m03 m13 m23 m33 )
1769 // That is, the vectors _matrix[i] represent the column vectors of the original matrix M!
1772 // w_c = M34/(z_n - M33/M43)
1774 OSG::Real32 w_c = matProjection[4][3] / (p_n.z() - matProjection[3][3]/matProjection[3][4]);
1775 OSG::Pnt4f p_c = w_c * p_n;
1777 return p_c;
1780 OSG::Pnt3f EyeFromClip(const OSG::Pnt4f& p_c, const OSG::Matrix& matInvProjection)
1782 OSG::Pnt4f p_e;
1783 matInvProjection.mult(p_c, p_e);
1784 p_e /= p_e.w();
1785 return OSG::Pnt3f(p_e.x(), p_e.y(), p_e.z());
1788 OSG::Pnt3f EyeFromNdc(const OSG::Pnt4f& p_n, const OSG::Matrix& matInvProjection)
1790 OSG::Pnt4f p_e;
1791 matInvProjection.mult(p_n, p_e);
1792 p_e /= p_e.w();
1793 return OSG::Pnt3f(p_e.x(), p_e.y(), p_e.z());
1796 bool isOrthographicCamera(OSG::Camera* cam, OSG::UInt32 width, OSG::UInt32 height)
1798 OSG::OrthographicCamera* orthoCam = dynamic_cast<OSG::OrthographicCamera*>(cam);
1799 if (orthoCam)
1800 return true;
1802 OSG::MatrixCamera* matrixCam = dynamic_cast<OSG::MatrixCamera*>(cam);
1803 if (matrixCam)
1805 OSG::Matrix matProjection;
1806 matrixCam->getProjection(matProjection, width, height);
1808 float m32 = matProjection[2][3];
1809 float m33 = matProjection[3][3];
1811 if (matProjection[2][3] == 0.f && matProjection[3][3] == 1.f)
1812 return true;
1815 return false;
1818 void calc_ortho_frustums_cpu(
1819 const OSG::Vec4u& viewport,
1820 const OSG::Matrix& matInvProjection,
1821 VecFrustumsT& frustums)
1823 OSG::Real32 x_v = static_cast<OSG::Real32>(viewport[0]);
1824 OSG::Real32 y_v = static_cast<OSG::Real32>(viewport[1]);
1825 OSG::Real32 w = static_cast<OSG::Real32>(viewport[2]);
1826 OSG::Real32 h = static_cast<OSG::Real32>(viewport[3]);
1828 OSG::UInt32 numHorizontalTiles = OSG::UInt32(OSG::osgCeil(w / tile_size));
1829 OSG::UInt32 numVerticalTiles = OSG::UInt32(OSG::osgCeil(h / tile_size));
1831 frustums.resize(numHorizontalTiles * numVerticalTiles);
1833 OSG::Pnt3f pnts_w[8];
1834 OSG::Pnt4f pnts_n[8];
1835 OSG::Pnt3f pnts_e[8];
1837 for (OSG::UInt32 j = 0; j < numVerticalTiles; ++j)
1839 OSG::Real32 y0 = y_v + j * tile_size;
1840 OSG::Real32 y1 = OSG::osgMin(y_v + (j+1) * tile_size, y_v + h);
1842 for (OSG::UInt32 i = 0; i < numHorizontalTiles; ++i)
1844 OSG::Real32 x0 = x_v + i * tile_size;
1845 OSG::Real32 x1 = OSG::osgMin(x_v + (i+1) * tile_size, x_v + w);
1847 pnts_w[0] = OSG::Pnt3f(x0, y0, 1.f);
1848 pnts_w[1] = OSG::Pnt3f(x1, y0, 1.f);
1849 pnts_w[2] = OSG::Pnt3f(x0, y1, 1.f);
1850 pnts_w[3] = OSG::Pnt3f(x1, y1, 1.f);
1852 pnts_w[4] = OSG::Pnt3f(x0, y0, -1.f);
1853 pnts_w[5] = OSG::Pnt3f(x1, y0, -1.f);
1854 pnts_w[6] = OSG::Pnt3f(x0, y1, -1.f);
1855 pnts_w[7] = OSG::Pnt3f(x1, y1, -1.f);
1857 for (OSG::UInt32 k = 0; k < 8; ++k)
1859 pnts_n[k] = NdcFromScreen(pnts_w[k], viewport);
1860 pnts_e[k] = EyeFromNdc (pnts_n[k], matInvProjection);
1863 OSG::UInt32 idx = j * numHorizontalTiles + i;
1865 frustums[idx].planes[0] = OSG::Plane(pnts_e[6], pnts_e[0], pnts_e[2]); // left plane
1866 frustums[idx].planes[1] = OSG::Plane(pnts_e[7], pnts_e[3], pnts_e[1]); // right plane
1867 frustums[idx].planes[2] = OSG::Plane(pnts_e[6], pnts_e[2], pnts_e[3]); // top plane
1868 frustums[idx].planes[3] = OSG::Plane(pnts_e[4], pnts_e[1], pnts_e[0]); // bottom plane
1873 void calc_persp_frustums_cpu(
1874 const OSG::Vec4u& viewport,
1875 const OSG::Matrix& matInvProjection,
1876 VecFrustumsT& frustums)
1878 OSG::Real32 x_v = static_cast<OSG::Real32>(viewport[0]);
1879 OSG::Real32 y_v = static_cast<OSG::Real32>(viewport[1]);
1880 OSG::Real32 w = static_cast<OSG::Real32>(viewport[2]);
1881 OSG::Real32 h = static_cast<OSG::Real32>(viewport[3]);
1883 OSG::UInt32 numHorizontalTiles = OSG::UInt32(OSG::osgCeil(w / tile_size));
1884 OSG::UInt32 numVerticalTiles = OSG::UInt32(OSG::osgCeil(h / tile_size));
1886 frustums.resize(numHorizontalTiles * numVerticalTiles);
1888 OSG::Pnt3f pEye = (0.f, 0.f, 0.f); // eye position in view space
1890 OSG::Pnt3f pnts_w[4];
1891 OSG::Pnt4f pnts_n[4];
1892 OSG::Pnt3f pnts_e[4];
1894 for (OSG::UInt32 j = 0; j < numVerticalTiles; ++j)
1896 OSG::Real32 y0 = y_v + j * tile_size;
1897 OSG::Real32 y1 = OSG::osgMin(y_v + (j+1) * tile_size, y_v + h);
1899 for (OSG::UInt32 i = 0; i < numHorizontalTiles; ++i)
1901 OSG::Real32 x0 = x_v + i * tile_size;
1902 OSG::Real32 x1 = OSG::osgMin(x_v + (i+1) * tile_size, x_v + w);
1904 pnts_w[0] = OSG::Pnt3f(x0, y0, -1.f);
1905 pnts_w[1] = OSG::Pnt3f(x1, y0, -1.f);
1906 pnts_w[2] = OSG::Pnt3f(x0, y1, -1.f);
1907 pnts_w[3] = OSG::Pnt3f(x1, y1, -1.f);
1909 for (OSG::UInt32 k = 0; k < 4; ++k)
1911 pnts_n[k] = NdcFromScreen(pnts_w[k], viewport);
1912 pnts_e[k] = EyeFromNdc (pnts_n[k], matInvProjection);
1915 OSG::UInt32 idx = j * numHorizontalTiles + i;
1917 frustums[idx].planes[0] = OSG::Plane(pEye, pnts_e[0], pnts_e[2]); // left plane
1918 frustums[idx].planes[1] = OSG::Plane(pEye, pnts_e[3], pnts_e[1]); // right plane
1919 frustums[idx].planes[2] = OSG::Plane(pEye, pnts_e[2], pnts_e[3]); // top plane
1920 frustums[idx].planes[3] = OSG::Plane(pEye, pnts_e[1], pnts_e[0]); // bottom plane
1925 std::size_t calc_frustum_buffer_size(const VecFrustumsT& vFrustums)
1927 std::size_t ao = 0; // aligned offset
1928 std::size_t bo = 0; // base offset
1930 for (std::size_t j = 0; j < 4; ++j)
1932 ao = OSG::alignOffset(16, bo); bo = ao + sizeof(OSG::Vec3f);
1933 ao = OSG::alignOffset( 4, bo); bo = ao + sizeof(OSG::Real32);
1934 ao = OSG::alignOffset(16, bo); bo = ao;
1937 ao *= vFrustums.size(); bo = ao; // array
1938 ao = OSG::alignOffset( 16, bo); bo = ao; // padding
1940 return ao;
1943 std::vector<OSG::UInt8> create_frustum_buffer(const VecFrustumsT& vFrustums)
1945 std::size_t size = calc_frustum_buffer_size(vFrustums);
1947 std::vector<OSG::UInt8> buffer(size);
1949 std::size_t ao = 0; // aligned offset
1950 std::size_t bo = 0; // base offset
1952 for (std::size_t i = 0; i < vFrustums.size(); ++i)
1954 for (std::size_t j = 0; j < 4; ++j)
1956 ao = OSG::alignOffset(16, bo);
1957 memcpy(&buffer[0] + ao, &vFrustums[i].planes[j].getNormal(), sizeof(OSG::Vec3f));
1958 bo = ao + sizeof(OSG::Vec3f);
1960 ao = OSG::alignOffset( 4, bo);
1961 *(reinterpret_cast<OSG::Real32*>(&buffer[0] + ao)) = vFrustums[i].planes[j].getDistanceFromOrigin();
1962 bo = ao + sizeof(OSG::Real32);
1964 ao = OSG::alignOffset(16, bo); bo = ao;
1967 ao = OSG::alignOffset( 16, bo); bo = ao; // padding
1970 return buffer;
1973 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_frustum_state(const VecFrustumsT& vFrustums)
1975 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
1977 std::vector<OSG::UInt8> buffer = create_frustum_buffer(vFrustums);
1979 ssbo->editMFBuffer()->setValues(buffer);
1980 ssbo->setUsage(GL_DYNAMIC_DRAW);
1982 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
1985 void update_frustum_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const VecFrustumsT& vFrustums)
1987 if (ssbo) {
1988 std::vector<OSG::UInt8> buffer = create_frustum_buffer(vFrustums);
1989 ssbo->editMFBuffer()->setValues(buffer);
1994 // Index lists
1996 std::size_t calc_light_index_buffer_size(const VecLightIndexT& vIndexList)
1998 return sizeof(OSG::UInt32) * vIndexList.size();
2001 std::vector<OSG::UInt8> create_light_index_buffer(const VecLightIndexT& vIndexList)
2003 std::size_t size = calc_light_index_buffer_size(vIndexList);
2005 std::vector<OSG::UInt8> buffer(size);
2007 std::size_t ao = 0; // aligned offset
2008 std::size_t bo = 0; // base offset
2010 for (std::size_t i = 0; i < vIndexList.size(); ++i)
2012 ao = OSG::alignOffset(4, bo);
2013 *(reinterpret_cast<OSG::UInt32*>(&buffer[0] + ao)) = vIndexList[i];
2014 bo = ao + sizeof(OSG::UInt32);
2017 ao = OSG::alignOffset( 4, bo); bo = ao; // padding
2019 return buffer;
2022 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_index_state(const VecLightIndexT& vIndexList)
2024 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
2026 std::vector<OSG::UInt8> buffer = create_light_index_buffer(vIndexList);
2028 ssbo->editMFBuffer()->setValues(buffer);
2029 ssbo->setUsage(GL_DYNAMIC_DRAW);
2031 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
2034 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_index_state(std::size_t sz)
2036 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
2038 std::vector<OSG::UInt8> buffer(sizeof(OSG::UInt32) * sz, 0);
2040 ssbo->editMFBuffer()->setValues(buffer);
2041 ssbo->setUsage(GL_DYNAMIC_DRAW);
2043 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
2046 void update_index_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, const VecLightIndexT& vIndexList)
2048 if (ssbo) {
2049 std::vector<OSG::UInt8> buffer = create_light_index_buffer(vIndexList);
2050 ssbo->editMFBuffer()->setValues(buffer);
2054 void clear_index_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo, std::size_t sz)
2056 if (ssbo) {
2057 std::vector<OSG::UInt8> buffer(sizeof(OSG::UInt32) * sz, 0);
2058 ssbo->editMFBuffer()->setValues(buffer);
2063 // Global light index counter state used for synchronization of the work groups of light culling compute shader
2065 OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr create_light_index_counter_state()
2067 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo = OSG::ShaderStorageBufferObjStdLayoutChunk::create();
2070 // The counter compromises exactly one UInt32 element
2072 std::vector<OSG::UInt8> buffer(sizeof(OSG::UInt32) * 1, 0);
2074 ssbo->editMFBuffer()->setValues(buffer);
2075 ssbo->setUsage(GL_DYNAMIC_DRAW);
2077 return OSG::ShaderStorageBufferObjStdLayoutChunkTransitPtr(ssbo);
2080 void clear_light_index_counter_state(OSG::ShaderStorageBufferObjStdLayoutChunk* ssbo)
2082 if (ssbo) {
2084 // The counter compromises exactly one UInt32 element
2086 std::vector<OSG::UInt8> buffer(sizeof(OSG::UInt32) * 1, 0);
2088 ssbo->editMFBuffer()->setValues(buffer);
2092 struct Sphere
2094 OSG::Pnt3f c; // Center point.
2095 OSG::Real32 r; // Radius.
2098 struct Cone
2100 OSG::Pnt3f T; // Cone tip.
2101 OSG::Real32 h; // Height of the cone.
2102 OSG::Vec3f d; // Direction of the cone.
2103 OSG::Real32 r; // bottom radius of the cone.
2107 // Check to see if a sphere is fully behind (inside the negative halfspace of) a plane.
2109 bool SphereInsidePlane(const Sphere& sphere, const OSG::Plane& plane)
2111 OSG::Real32 val = plane.getNormal().dot(sphere.c) - plane.getDistanceFromOrigin();
2112 return val < -sphere.r;
2116 // Check to see of a light is partially contained within the frustum.
2118 bool SphereInsideFrustum(const Sphere& sphere, const Frustum& frustum, OSG::Real32 zNear, OSG::Real32 zFar)
2120 bool result = true;
2122 if (sphere.c.z() - sphere.r > zNear || zFar > sphere.c.z() + sphere.r)
2124 result = false;
2127 for (int i = 0; i < 4 && result; i++)
2129 if (SphereInsidePlane(sphere, frustum.planes[i]))
2131 result = false;
2135 return result;
2139 // Check to see if a point is fully behind (inside the negative halfspace of) a plane.
2141 bool PointInsidePlane(const OSG::Pnt3f& p, const OSG::Plane& plane)
2143 OSG::Real32 val = plane.getNormal().dot(p) - plane.getDistanceFromOrigin();
2144 return val < 0;
2148 // Check to see if a cone if fully behind (inside the negative halfspace of) a plane.
2150 bool ConeInsidePlane(const Cone& cone, const OSG::Plane& plane)
2152 // Compute the farthest point on the end of the cone to the positive space of the plane.
2153 OSG::Vec3f m = plane.getNormal().cross(cone.d).cross(cone.d);
2154 OSG::Pnt3f Q = cone.T + cone.d * cone.h - m * cone.r;
2156 // The cone is in the negative halfspace of the plane if both
2157 // the tip of the cone and the farthest point on the end of the cone to the
2158 // positive halfspace of the plane are both inside the negative halfspace
2159 // of the plane.
2160 return PointInsidePlane(cone.T, plane) && PointInsidePlane(Q, plane);
2163 bool ConeInsideFrustum(const Cone& cone, const Frustum& frustum, OSG::Real32 zNear, OSG::Real32 zFar)
2165 bool result = true;
2167 OSG::Plane nearPlane(OSG::Vec3f(0, 0,-1),-zNear);
2168 OSG::Plane farPlane (OSG::Vec3f(0, 0, 1), zFar );
2170 if (ConeInsidePlane(cone, nearPlane) || ConeInsidePlane(cone, farPlane))
2172 result = false;
2175 for (int i = 0; i < 4 && result; i++)
2177 if (ConeInsidePlane(cone, frustum.planes[i]))
2179 result = false;
2183 return result;
2187 // simple light data structure
2189 struct Light
2191 enum Type
2193 directional_light = OSG::MultiLight::DIRECTIONAL_LIGHT,
2194 point_light = OSG::MultiLight::POINT_LIGHT,
2195 spot_light = OSG::MultiLight::SPOT_LIGHT,
2196 cinema_light = OSG::MultiLight::CINEMA_LIGHT
2199 OSG::MultiLight::Type getType() const { return static_cast<OSG::MultiLight::Type>(type); }
2201 explicit Light(Type e);
2202 ~Light();
2204 static Light create_light(Type e, OSG::Int32 test_dir_light_type = -1);
2206 void create_light_geometry(OSG::UInt32 material_idx);
2208 OSG::Pnt3f position; // light position in object space for point and spot lights
2209 OSG::Vec3f direction; // direction of directional light or spot light in object space
2210 OSG::Color3f color; // the color of the light
2211 OSG::Real32 intensity; // the intensity of the light
2212 OSG::Real32 range; // the range of the light, i.e. the light sphere radius of influence
2213 OSG::Real32 spotlightAngle; // the cone angle in case of a spot light
2214 OSG::Real32 innerSuperEllipsesWidth; // cinema light parameter
2215 OSG::Real32 innerSuperEllipsesHeight; // cinema light parameter
2216 OSG::Real32 outerSuperEllipsesWidth; // cinema light parameter
2217 OSG::Real32 outerSuperEllipsesHeight; // cinema light parameter
2218 OSG::Real32 superEllipsesRoundness; // cinema light parameter
2219 OSG::Real32 superEllipsesTwist; // cinema light parameter
2220 OSG::Int32 type; // the type of light: see OSG::MultiLight::LightType
2221 bool enabled; // on/off state of the light
2223 OSG::NodeRefPtr beacon; // the light beacon that if defined evaluates the position parameter
2224 OSG::TransformRefPtr transform; // the beacons transform core
2225 SmoothCubicBezierSpline curve; // the path that the light will follow
2228 // Eye space position and direction are calculated on the fly for CPU light culling
2229 // in order to speed up performance.
2230 // These are not used for the GPU culling process currently.
2232 mutable OSG::Pnt3f position_es; // light position in eye space for point and spot lights
2233 mutable OSG::Vec3f direction_es; // direction of directional light or spot light in eye space
2235 static bool cpu_cull_lights;
2236 static bool add_dir_test_lights;
2237 static bool correct_light_geometry;
2238 static bool use_light_index_list;
2239 static bool show_spot_dir_line;
2240 static int force_spot_dir;
2241 static OSG::Vec3f dir_test_case_6;
2242 static OSG::Vec3f dir_test_case_7;
2243 static OSG::Vec3f dir_test_case_8;
2246 bool Light::cpu_cull_lights = false;
2247 bool Light::add_dir_test_lights = false;
2248 bool Light::correct_light_geometry = false;
2249 bool Light::use_light_index_list = true;
2250 bool Light::show_spot_dir_line = false;
2251 int Light::force_spot_dir = 0;
2252 OSG::Vec3f Light::dir_test_case_6 = OSG::Vec3f(0,0,-1);
2253 OSG::Vec3f Light::dir_test_case_7 = OSG::Vec3f(0,0,-1);
2254 OSG::Vec3f Light::dir_test_case_8 = OSG::Vec3f(0,0,-1);
2256 typedef std::vector<Light> VecLightsT; // multiple lights
2257 VecLightsT lights; // the lights of the scene
2259 Light::Light(Type e)
2260 : position(0.f, 0.f, 0.f)
2261 , direction(0.f, 0.f, 1.f)
2262 , color(1.f,1.f,1.f)
2263 , intensity(1.f)
2264 , range(1.f)
2265 , spotlightAngle(20.f)
2266 , innerSuperEllipsesWidth(1.f)
2267 , innerSuperEllipsesHeight(1.f)
2268 , outerSuperEllipsesWidth(1.3f)
2269 , outerSuperEllipsesHeight(1.3f)
2270 , superEllipsesRoundness(1.0f)
2271 , superEllipsesTwist(0.f)
2272 , type(e)
2273 , enabled(true)
2274 , beacon(NULL)
2275 , transform(NULL)
2276 , curve(dice_knots(true))
2279 Light::~Light()
2281 beacon = NULL;
2282 transform = NULL;
2285 void transformToEyeSpace(
2286 OSG::Node* beacon,
2287 const OSG::Pnt3f& position_bs,
2288 const OSG::Vec3f& direction_bs,
2289 OSG::Pnt3f& position_es,
2290 OSG::Vec3f& direction_es)
2292 if (!mgr || !mgr->getWindow() || mgr->getWindow()->getMFPort()->size() == 0)
2293 return;
2295 OSG::Matrix matWsFromBS;
2297 if(beacon != NULL)
2299 beacon->getToWorld(matWsFromBS);
2301 else
2303 matWsFromBS.setIdentity();
2306 OSG::Viewport* pPort = mgr->getWindow()->getPort(0);
2308 OSG::Int16 width = pPort->calcPixelWidth();
2309 OSG::Int16 height = pPort->calcPixelHeight();
2311 OSG::Matrix mat; // matEsFromWs;
2312 pPort->getCamera()->getViewing(mat, width, height);
2314 mat.mult(matWsFromBS); // matEsFromBs
2316 mat.multFull( position_bs, position_es);
2317 mat.multFull(direction_bs, direction_es);
2320 bool PointLightInsideFrustum(const Light& light, const Frustum& frustum, OSG::Real32 n, OSG::Real32 f)
2322 Sphere sphere;
2323 sphere.c = light.position_es;
2324 sphere.r = light.range;
2326 return SphereInsideFrustum(sphere, frustum, n, f);
2329 bool SpotLightInsideFrustum(const Light& light, const Frustum& frustum, OSG::Real32 n, OSG::Real32 f)
2331 Cone cone;
2332 cone.T = light.position_es;
2333 cone.d = light.direction_es;
2334 cone.h = light.range;
2335 cone.r = OSG::osgTan( OSG::osgDegree2Rad(light.spotlightAngle)) * cone.h;
2337 return ConeInsideFrustum(cone, frustum, n, f);
2343 // cluster_k and cluster_z functions without near plane offset
2345 OSG::UInt32 cluster_k_verbose(
2346 OSG::Real32 z_e, // eye space z-position, z_e < 0
2347 OSG::Real32 n, // near plane distance from viewer n > 0
2348 OSG::Real32 f, // far plane distance from viewer f > n > 0
2349 OSG::UInt32 c) // number of cluster planes
2351 if (z_e >= -n) return 0;
2352 if (z_e <= -f) return c-1;
2354 OSG::Real32 s = (c-1) * log2(z_e/-n) / log2(f/n);
2355 OSG::UInt32 k = OSG::UInt32(OSG::osgFloor(s));
2356 return k;
2359 OSG::Real32 cluster_z_verbose(
2360 OSG::UInt32 k, // cluster coordinate, 0 <= k <= c
2361 OSG::Real32 n, // near plane distance from viewer n > 0
2362 OSG::Real32 f, // far plane distance from viewer f > n > 0
2363 OSG::UInt32 c) // number of cluster planes
2365 if (k > c-1) return -f;
2367 OSG::Real32 z_e = -n*exp2(static_cast<OSG::Real32>(k)/(c-1)*log2(f/n));
2368 return z_e;
2372 // cluster_k and cluster_z functions with near plane offset
2374 OSG::UInt32 cluster_k_verbose(
2375 OSG::Real32 z_e, // eye space z-position, z_e < 0
2376 OSG::Real32 n, // near plane distance from viewer n > 0
2377 OSG::Real32 f, // far plane distance from viewer f > n > 0
2378 OSG::Real32 D, // near plane offset
2379 OSG::UInt32 c) // number of cluster planes
2381 if (z_e >= -(n+D)) return 0;
2382 if (z_e <= -f) return c-1;
2384 OSG::Real32 s = 1 + ((c-1) / log2(f/(n+D))) * (log2(-z_e) - log2(n+D));
2385 OSG::UInt32 k = OSG::UInt32(OSG::osgFloor(s));
2387 return OSG::osgClamp(0U, k, c-1);
2390 OSG::Real32 cluster_z_verbose(
2391 OSG::UInt32 k, // cluster coordinate, 0 <= k <= c
2392 OSG::Real32 n, // near plane distance from viewer n > 0
2393 OSG::Real32 f, // far plane distance from viewer f > n > 0
2394 OSG::Real32 D, // near plane offset
2395 OSG::UInt32 c) // number of cluster planes
2397 if (k == 0) return -n;
2398 if (k > c-1) return -f;
2400 OSG::Real32 z_e = -(n+D)*exp2(static_cast<OSG::Real32>(k-1) * (log2(f/(n+D))/(c-1)));
2401 return z_e;
2405 OSG::UInt32 cluster_k(
2406 OSG::Real32 z_e, // eye space z-position, z_e < 0
2407 OSG::Real32 nD, // near plane distance from viewer plus offset, nD = n+D with n > 0, D > 0
2408 OSG::Real32 lg_nD, // log2(nD)
2409 OSG::Real32 f, // far plane distance from viewer f > n > 0
2410 OSG::Real32 a, // factor (c-1)/log2(f/nD)
2411 OSG::UInt32 c_1) // number of cluster planes
2413 if (z_e >= -nD) return 0;
2414 if (z_e <= -f) return c_1;
2416 OSG::Real32 s = 1 + a * (log2(-z_e) - lg_nD);
2417 OSG::UInt32 k = OSG::UInt32(s);
2418 return OSG::osgClamp(0U, k, c_1);
2421 OSG::Real32 cluster_z(
2422 OSG::UInt32 k, // cluster coordinate, 0 <= k <= c
2423 OSG::Real32 n, // near plane distance from viewer n > 0
2424 OSG::Real32 f, // far plane distance from viewer f > n > 0
2425 OSG::Real32 nD, // near plane distance from viewer plus offset, nD = n+D with n > 0, D > 0
2426 OSG::Real32 b, // factor log2(f/(n+D))/(c-1)
2427 OSG::UInt32 c_1) // number of cluster planes
2429 if (k == 0) return -n;
2430 if (k > c_1) return -f;
2432 OSG::Real32 z_e = -nD*exp2(static_cast<OSG::Real32>(k-1) * b);
2433 return z_e;
2437 void cluster_test(
2438 OSG::Real32 zNear, // near plane distance from viewer zNear > 0
2439 OSG::Real32 zFar) // far plane distance from viewer zFar > n > 0
2441 OSG::Real32 eps = OSG::Eps;
2443 OSG::UInt32 c = 32;
2444 OSG::UInt32 k, k_verbose;
2445 OSG::Real32 z_e, z_e_verbose;
2447 OSG::Real32 d = zFar-zNear;
2448 OSG::Real32 D = 5.f;
2450 OSG::UInt32 c_1 = c-1;
2451 OSG::Real32 zNearD = zNear + D;
2452 OSG::Real32 lg_zNearD = log2(zNearD);
2453 OSG::Real32 a = (c-1)/log2(zFar/zNearD);
2454 OSG::Real32 b = log2(zFar/zNearD)/(c-1);
2456 z_e = -zNear; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2457 z_e = -zNear-D; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2458 z_e = -zNear-D+0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2459 z_e = -zNear-D-0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2460 z_e = -zFar; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2462 z_e = -zNear + 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2463 z_e = -zNear + 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2464 z_e = -zNear + 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2465 z_e = -zNear + 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2466 z_e = -zNear + 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2467 z_e = -zNear + 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2468 z_e = -zNear + 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2469 z_e = -zNear + 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2470 z_e = -zNear + 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2471 z_e = -zNear + 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2472 z_e = -zNear + 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2473 z_e = -zNear; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2474 z_e = -zNear - 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2475 z_e = -zNear - 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2476 z_e = -zNear - 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2477 z_e = -zNear - 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2478 z_e = -zNear - 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2479 z_e = -zNear - 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2480 z_e = -zNear - 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2481 z_e = -zNear - 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2482 z_e = -zNear - 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2483 z_e = -zNear - 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2484 z_e = -zNear - 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2485 z_e = -zNear - d/48; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2486 z_e = -zNear - d/24; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2487 z_e = -zNear - d/12; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2488 z_e = -zNear - d/ 6; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2489 z_e = -zNear - d/ 2; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2490 z_e = -zNear - d/ 1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2491 z_e = -zNearD + 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2492 z_e = -zNearD + 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2493 z_e = -zNearD + 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2494 z_e = -zNearD + 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2495 z_e = -zNearD + 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2496 z_e = -zNearD + 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2497 z_e = -zNearD + 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2498 z_e = -zNearD + 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2499 z_e = -zNearD + 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2500 z_e = -zNearD + 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2501 z_e = -zNearD + 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2502 z_e = -zNearD; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2503 z_e = -zNearD - 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2504 z_e = -zNearD - 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2505 z_e = -zNearD - 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2506 z_e = -zNearD - 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2507 z_e = -zNearD - 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2508 z_e = -zNearD - 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2509 z_e = -zNearD - 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2510 z_e = -zNearD - 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2511 z_e = -zNearD - 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2512 z_e = -zNearD - 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2513 z_e = -zNearD - 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2514 z_e = -zNearD - d/48; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2515 z_e = -zNearD - d/24; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2516 z_e = -zNearD - d/12; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2517 z_e = -zNearD - d/ 6; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2518 z_e = -zNearD - d/ 2; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2519 z_e = -zNearD - d/ 1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2520 z_e = -zFar + 100.; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2521 z_e = -zFar + 10.; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2522 z_e = -zFar + 1.; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2523 z_e = -zFar + 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2524 z_e = -zFar + 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2525 z_e = -zFar + 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2526 z_e = -zFar + 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2527 z_e = -zFar + 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2528 z_e = -zFar + 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2529 z_e = -zFar; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2530 z_e = -zFar- 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2531 z_e = -zFar- 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2532 z_e = -zFar- 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2533 z_e = -zFar- 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2534 z_e = -zFar- 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2535 z_e = -zFar- 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2536 z_e = -zFar- 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2537 z_e = -zFar- 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2538 z_e = -zFar- 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2539 z_e = -zFar- 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2540 z_e = -zFar- 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2542 k = 0; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2543 k = 1; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2544 k = 2; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2545 k = 3; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2546 k = 4; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2547 k = 5; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2548 k = 6; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2549 k = 7; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2550 k = 8; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2551 k = 9; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2552 k = 10; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2553 k = 11; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2554 k = 12; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2555 k = 13; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2556 k = 14; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2557 k = 15; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2558 k = 16; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2559 k = 17; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2560 k = 18; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2561 k = 19; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2562 k = 20; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2563 k = 21; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2564 k = 22; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2565 k = 23; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2566 k = 24; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2567 k = 25; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2568 k = 26; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2569 k = 27; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2570 k = 28; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2571 k = 29; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2572 k = 30; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2573 k = 31; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2574 k = 32; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2575 k = 33; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2576 k = 65; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2578 zNear = 0.01f;
2579 zFar = 30000.0f;
2581 zNearD = zNear + D;
2582 lg_zNearD = log2(zNearD);
2583 a = (c-1)/log2(zFar/zNearD);
2584 b = log2(zFar/zNearD)/(c-1);
2586 z_e = -zNear; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2587 z_e = -zFar; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2589 z_e = -zNear + 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2590 z_e = -zNear + 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2591 z_e = -zNear + 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2592 z_e = -zNear + 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2593 z_e = -zNear + 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2594 z_e = -zNear + 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2595 z_e = -zNear + 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2596 z_e = -zNear + 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2597 z_e = -zNear + 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2598 z_e = -zNear + 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2599 z_e = -zNear + 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2600 z_e = -zNear; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2601 z_e = -zNear - 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2602 z_e = -zNear - 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2603 z_e = -zNear - 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2604 z_e = -zNear - 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2605 z_e = -zNear - 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2606 z_e = -zNear - 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2607 z_e = -zNear - 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2608 z_e = -zNear - 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2609 z_e = -zNear - 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2610 z_e = -zNear - 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2611 z_e = -zNear - 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2612 z_e = -zNear - d/48; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2613 z_e = -zNear - d/24; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2614 z_e = -zNear - d/12; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2615 z_e = -zNear - d/ 6; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2616 z_e = -zNear - d/ 2; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2617 z_e = -zNear - d/ 1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2618 z_e = -zNearD + 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2619 z_e = -zNearD + 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2620 z_e = -zNearD + 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2621 z_e = -zNearD + 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2622 z_e = -zNearD + 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2623 z_e = -zNearD + 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2624 z_e = -zNearD + 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2625 z_e = -zNearD + 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2626 z_e = -zNearD + 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2627 z_e = -zNearD + 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2628 z_e = -zNearD + 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2629 z_e = -zNearD; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2630 z_e = -zNearD - 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2631 z_e = -zNearD - 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2632 z_e = -zNearD - 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2633 z_e = -zNearD - 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2634 z_e = -zNearD - 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2635 z_e = -zNearD - 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2636 z_e = -zNearD - 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2637 z_e = -zNearD - 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2638 z_e = -zNearD - 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2639 z_e = -zNearD - 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2640 z_e = -zNearD - 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2641 z_e = -zNearD - d/48; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2642 z_e = -zNearD - d/24; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2643 z_e = -zNearD - d/12; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2644 z_e = -zNearD - d/ 6; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2645 z_e = -zNearD - d/ 2; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2646 z_e = -zNearD - d/ 1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2647 z_e = -zFar + 100.; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2648 z_e = -zFar + 10.; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2649 z_e = -zFar + 1.; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2650 z_e = -zFar + 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2651 z_e = -zFar + 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2652 z_e = -zFar + 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2653 z_e = -zFar + 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2654 z_e = -zFar + 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2655 z_e = -zFar + 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2656 z_e = -zFar; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2657 z_e = -zFar- 0.000001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2658 z_e = -zFar- 0.00001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2659 z_e = -zFar- 0.0001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2660 z_e = -zFar- 0.001; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2661 z_e = -zFar- 0.01; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2662 z_e = -zFar- 0.1; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2663 z_e = -zFar- 1.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2664 z_e = -zFar- 10.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2665 z_e = -zFar- 100.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2666 z_e = -zFar- 1000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2667 z_e = -zFar- 10000.0; k_verbose = cluster_k_verbose(z_e, zNear, zFar, D, c); k = cluster_k(z_e, zNearD, lg_zNearD, zFar, a, c_1); assert(k == k_verbose);
2669 k = 0; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2670 k = 1; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2671 k = 2; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2672 k = 3; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2673 k = 4; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2674 k = 5; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2675 k = 6; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2676 k = 7; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2677 k = 8; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2678 k = 9; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2679 k = 10; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2680 k = 11; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2681 k = 12; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2682 k = 13; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2683 k = 14; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2684 k = 15; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2685 k = 16; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2686 k = 17; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2687 k = 18; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2688 k = 19; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2689 k = 20; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2690 k = 21; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2691 k = 22; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2692 k = 23; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2693 k = 24; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2694 k = 25; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2695 k = 26; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2696 k = 27; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2697 k = 28; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2698 k = 29; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2699 k = 30; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2700 k = 31; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2701 k = 32; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2702 k = 33; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2703 k = 65; z_e_verbose = cluster_z_verbose(k, zNear, zFar, D, c); z_e = cluster_z(k, zNear, zFar, zNearD, b, c_1); assert(OSG::osgAbs(z_e_verbose - z_e) < eps);
2706 void calcAffectedLights(
2707 const VecLightsT& lights, // in light list
2708 const OSG::Matrix& matEyeFromWorld, // in transform from world to eye space
2709 OSG::FrustumVolume volViewFrustum, // in the view frustum volume in world space used for pre test
2710 VecLightIndexT& vecAffectedLights) // out the affected light index list
2713 // We test the light against the view frustum to get only affected lights.
2714 // Since all of out tests happens in eye space we must transform the world space view
2715 // frustum to eye space first.
2717 volViewFrustum.transform(matEyeFromWorld);
2719 Frustum frustum;
2720 frustum.planes[0] = volViewFrustum.getPlane(OSG::FrustumVolume::PLANE_LEFT);
2721 frustum.planes[1] = volViewFrustum.getPlane(OSG::FrustumVolume::PLANE_RIGHT);
2722 frustum.planes[2] = volViewFrustum.getPlane(OSG::FrustumVolume::PLANE_TOP);
2723 frustum.planes[3] = volViewFrustum.getPlane(OSG::FrustumVolume::PLANE_BOTTOM);
2725 OSG::Pnt3f nlt = volViewFrustum.getCorner(OSG::FrustumVolume::NEAR_LEFT_TOP);
2726 OSG::Pnt3f flt = volViewFrustum.getCorner(OSG::FrustumVolume:: FAR_LEFT_TOP);
2728 OSG::Real32 n = nlt.z();
2729 OSG::Real32 f = flt.z();
2731 for (std::size_t i = 0; i < lights.size(); ++i)
2733 bool affected = false;
2735 const Light& light = lights[i];
2737 if (light.enabled)
2739 switch (light.type)
2741 case Light::directional_light:
2743 affected = true;
2745 break;
2746 case Light::point_light:
2747 case Light::cinema_light:
2749 transformToEyeSpace(light.beacon, light.position, light.direction, light.position_es, light.direction_es);
2751 if (PointLightInsideFrustum(light, frustum, n, f))
2753 affected = true;
2756 break;
2757 case Light::spot_light:
2759 transformToEyeSpace(light.beacon, light.position, light.direction, light.position_es, light.direction_es);
2761 if (SpotLightInsideFrustum(light, frustum, n, f))
2763 affected = true;
2766 break;
2770 if (affected)
2771 vecAffectedLights.push_back(OSG::UInt32(i));
2775 std::size_t frustumAccessor(
2776 OSG::UInt32 i,
2777 OSG::UInt32 j,
2778 const OSG::Vec3u& dimensions)
2780 return j * dimensions.x() + i;
2783 void cullLights(
2784 const VecLightsT& lights, // in light list
2785 const VecLightIndexT& vecAffectedLights, // in the lights that are actually contributing to the view frustum shading
2786 const VecFrustumsT& frustums, // in frustums list
2787 const OSG::Vec3u& dimensions, // in the cluster dimentsions
2788 const OSG::Matrix& matEyeFromWorld, // in transform from world to eye space
2789 OSG::Real32 zNear, // in distance of near plane from eye point
2790 OSG::Real32 zFar, // in distance of far plane from eye point
2791 OSG::Real32 D, // in distance offset for near plane
2792 VecImageDataT& gridData, // out the raw grid data
2793 VecLightIndexT& lightIndexList) // out the index list
2795 gridData.clear();
2796 lightIndexList.clear();
2798 gridData.resize(dimensions.x() * dimensions.y() * dimensions.z());
2800 OSG::UInt32 c_1 = dimensions.z()-1;
2801 OSG::Real32 zNearD = zNear + D;
2802 OSG::Real32 b = log2(zFar/zNearD)/(c_1);
2805 // Test
2807 for (std::size_t l = 0; l < vecAffectedLights.size(); ++l)
2809 std::size_t light_index = vecAffectedLights[l];
2811 const Light& light = lights[light_index];
2813 //globalTestData.value16[light_index] = light.position_es.subZero();
2814 //globalTestData.value17[light_index] = light.direction_es;
2817 for (OSG::UInt32 k = 0; k < dimensions.z(); ++k)
2819 OSG::Real32 n = cluster_z(k, zNear, zFar, zNearD, b, c_1);
2820 OSG::Real32 f = cluster_z(k+1, zNear, zFar, zNearD, b, c_1);
2822 //OSG::Real32 n = cluster_z_verbose(k, zNear, zFar, D, dimensions.z());
2823 //OSG::Real32 f = cluster_z_verbose(k+1, zNear, zFar, D, dimensions.z());
2825 //globalTestData.value13[k] = n;
2826 //globalTestData.value14[k] = f;
2828 for (OSG::UInt32 j = 0; j < dimensions.y(); ++j)
2830 for (OSG::UInt32 i = 0; i < dimensions.x(); ++i)
2832 std::size_t tile = frustumAccessor(i, j, dimensions);
2833 const Frustum& frustum = frustums[tile];
2835 OSG::UInt32 light_count = 0;
2836 OSG::UInt32 light_start_offset = OSG::UInt32(lightIndexList.size());
2838 std::size_t num_affected_lights = vecAffectedLights.size();
2840 for (std::size_t l = 0; l < num_affected_lights; ++l)
2842 std::size_t light_index = vecAffectedLights[l];
2844 //OSG::UInt32 test_idx = l * dimensions.x() * dimensions.y() * dimensions.z()
2845 // + k * dimensions.x() * dimensions.y()
2846 // + j * dimensions.x()
2847 // + i;
2849 //globalTestData.value15[test_idx] = 0;
2851 const Light& light = lights[light_index];
2853 if (light.enabled)
2855 switch (light.type)
2857 case Light::directional_light:
2859 light_count += 1;
2860 lightIndexList.push_back(OSG::UInt32(light_index));
2862 //globalTestData.value15[test_idx] = test_idx;
2864 break;
2865 case Light::point_light:
2866 case Light::cinema_light:
2868 if (PointLightInsideFrustum(light, frustum, n, f))
2870 light_count += 1;
2871 lightIndexList.push_back(OSG::UInt32(light_index));
2873 //globalTestData.value15[test_idx] = test_idx;
2876 break;
2877 case Light::spot_light:
2879 if (SpotLightInsideFrustum(light, frustum, n, f))
2881 light_count += 1;
2882 lightIndexList.push_back(OSG::UInt32(light_index));
2884 //globalTestData.value15[test_idx] = test_idx;
2887 break;
2892 write_image_data(i, j, k, dimensions, std::make_pair(light_start_offset, light_count), gridData);
2900 // Simple material data structure
2902 struct Material
2904 Material()
2905 : ambient (0.f, 0.f, 0.f)
2906 , diffuse (0.f, 0.f, 0.f)
2907 , specular(0.f, 0.f, 0.f)
2908 , emissive(0.f, 0.f, 0.f)
2909 , opacity(1.f)
2910 , shininess(100.f)
2913 OSG::Color3f ambient;
2914 OSG::Color3f diffuse;
2915 OSG::Color3f specular;
2916 OSG::Color3f emissive;
2918 OSG::Real32 opacity;
2919 OSG::Real32 shininess;
2921 static OSG::UInt32 ambient_id;
2922 static OSG::UInt32 diffuse_id;
2923 static OSG::UInt32 specular_id;
2924 static OSG::UInt32 emissive_id;
2925 static OSG::UInt32 opacity_id;
2926 static OSG::UInt32 shininess_id;
2929 OSG::UInt32 Material:: ambient_id = 0;
2930 OSG::UInt32 Material:: diffuse_id = 0;
2931 OSG::UInt32 Material:: specular_id = 0;
2932 OSG::UInt32 Material:: emissive_id = 0;
2933 OSG::UInt32 Material:: opacity_id = 0;
2934 OSG::UInt32 Material::shininess_id = 0;
2936 typedef std::vector<Material> VecMaterialsT; // multiple materials
2938 VecMaterialsT initialize_materials(std::size_t num) // helper to create materials
2940 OSG_ASSERT(num > max_num_lights + 1);
2942 VecMaterialsT mat(num);
2944 for (std::size_t i = max_num_lights+1; i < num; ++i)
2946 mat[i].ambient = OSG::Color3f(0.001f, 0.001f, 0.001f);
2947 mat[i].diffuse.setRandom();
2948 mat[i].specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
2949 mat[i].emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
2950 mat[i].opacity = 1.f;
2951 mat[i].shininess = 320.f * small_die();
2953 //int r = classic_die();
2954 //if (r <= 3)
2955 // mat[i].opacity = small_die();
2959 // special grey material for box
2961 mat[0].ambient = OSG::Color3f(0.001f, 0.001f, 0.001f);
2962 mat[0].diffuse = OSG::Color3f(0.7f, 0.7f, 0.7f);
2963 mat[0].specular = OSG::Color3f(0.9f, 0.9f, 0.9f);
2964 mat[0].emissive = OSG::Color3f(0.0f, 0.0f, 0.0f);
2965 mat[0].opacity = 1.f;
2966 mat[0].shininess = 100.f;
2968 return mat;
2971 VecMaterialsT materials = initialize_materials(num_materials); // the material database
2974 // we reserve the first max_num_lights + 1 materials for the light simulation and
2975 // the grey box.
2977 boost::uniform_int<OSG::UInt32> material_dist(max_num_lights+1, num_materials-1);
2978 boost::variate_generator<RNGType, boost::uniform_int<OSG::UInt32> > material_idx_die(rng, material_dist);
2981 // Simple geometry state data structure
2983 struct GeomState
2985 GeomState()
2986 : material_index(0)
2989 OSG::UInt32 material_index;
2991 static OSG::UInt32 material_index_id;
2994 OSG::UInt32 GeomState::material_index_id = 0;
2996 // ============================================================================
2998 // Part: Creation and update of the light state
3000 // ============================================================================
3002 OSG::MultiLightChunkTransitPtr create_light_state(const VecLightsT& vLights)
3004 OSG::MultiLightChunkRefPtr lightChunk = OSG::MultiLightChunk::create();
3006 lightChunk->setUsage(GL_DYNAMIC_DRAW);
3007 lightChunk->setLayoutType(OSG::MultiLight::SIMPLE_LAYOUT | OSG::MultiLight::CINEMA_LAYOUT);
3009 lightChunk->setHasEyeToLightSpaceMatrix(true); // provide a struct entry for the transform from view space to light space
3010 lightChunk->setHasCosSpotlightAngle (true); // provide a struct entry for the cosine of the spot light angle (defaults to true)
3011 lightChunk->setHasSpotlightAngle (true); // provide a struct entry for the spot light angle itself (defaults to false)
3013 //lightChunk->setEyeSpace(true);
3015 BOOST_FOREACH(const Light& light, vLights)
3017 OSG::UInt32 idx = lightChunk->addLight(light.getType());
3019 lightChunk->setPosition (idx, light.position);
3020 lightChunk->setDirection (idx, light.direction);
3021 lightChunk->setColor (idx, light.color);
3022 lightChunk->setIntensity (idx, light.intensity);
3023 lightChunk->setRange (idx, light.range);
3024 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
3025 lightChunk->setInnerSuperEllipsesWidth (idx, light.innerSuperEllipsesWidth);
3026 lightChunk->setInnerSuperEllipsesHeight (idx, light.innerSuperEllipsesHeight);
3027 lightChunk->setOuterSuperEllipsesWidth (idx, light.outerSuperEllipsesWidth);
3028 lightChunk->setOuterSuperEllipsesHeight (idx, light.outerSuperEllipsesHeight);
3029 lightChunk->setSuperEllipsesRoundness (idx, light.superEllipsesRoundness);
3030 lightChunk->setSuperEllipsesTwist (idx, light.superEllipsesTwist);
3031 lightChunk->setType (idx, light.getType());
3032 lightChunk->setEnabled (idx, light.enabled);
3033 lightChunk->setBeacon (idx, light.beacon);
3036 return OSG::MultiLightChunkTransitPtr(lightChunk);
3039 void update_light_state(OSG::MultiLightChunk* lightChunk, const VecLightsT& vLights)
3041 if (lightChunk)
3043 if (lightChunk->numLights() != vLights.size())
3045 lightChunk->clearLights();
3047 BOOST_FOREACH(const Light& light, vLights)
3049 OSG::UInt32 idx = lightChunk->addLight(light.getType());
3051 lightChunk->setPosition (idx, light.position);
3052 lightChunk->setDirection (idx, light.direction);
3053 lightChunk->setColor (idx, light.color);
3054 lightChunk->setIntensity (idx, light.intensity);
3055 lightChunk->setRange (idx, light.range);
3056 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
3057 lightChunk->setInnerSuperEllipsesWidth (idx, light.innerSuperEllipsesWidth);
3058 lightChunk->setInnerSuperEllipsesHeight (idx, light.innerSuperEllipsesHeight);
3059 lightChunk->setOuterSuperEllipsesWidth (idx, light.outerSuperEllipsesWidth);
3060 lightChunk->setOuterSuperEllipsesHeight (idx, light.outerSuperEllipsesHeight);
3061 lightChunk->setSuperEllipsesRoundness (idx, light.superEllipsesRoundness);
3062 lightChunk->setSuperEllipsesTwist (idx, light.superEllipsesTwist);
3063 lightChunk->setType (idx, light.getType());
3064 lightChunk->setEnabled (idx, light.enabled);
3065 lightChunk->setBeacon (idx, light.beacon);
3068 else
3070 for (OSG::UInt32 idx = 0; idx < vLights.size(); ++idx)
3072 const Light& light = vLights[idx];
3074 lightChunk->setPosition (idx, light.position);
3075 lightChunk->setDirection (idx, light.direction);
3076 lightChunk->setColor (idx, light.color);
3077 lightChunk->setIntensity (idx, light.intensity);
3078 lightChunk->setRange (idx, light.range);
3079 lightChunk->setSpotlightAngle (idx, light.spotlightAngle);
3080 lightChunk->setInnerSuperEllipsesWidth (idx, light.innerSuperEllipsesWidth);
3081 lightChunk->setInnerSuperEllipsesHeight (idx, light.innerSuperEllipsesHeight);
3082 lightChunk->setOuterSuperEllipsesWidth (idx, light.outerSuperEllipsesWidth);
3083 lightChunk->setOuterSuperEllipsesHeight (idx, light.outerSuperEllipsesHeight);
3084 lightChunk->setSuperEllipsesRoundness (idx, light.superEllipsesRoundness);
3085 lightChunk->setSuperEllipsesTwist (idx, light.superEllipsesTwist);
3086 lightChunk->setType (idx, light.getType());
3087 lightChunk->setEnabled (idx, light.enabled);
3088 lightChunk->setBeacon (idx, light.beacon);
3094 // ============================================================================
3096 // Part: Some routines for handling of the memory buffer and the the
3097 // creation on the MultiPropertySSBOChunk objects:
3099 // i) create_material_database_state,
3100 // update_material_database_state
3102 // ii) create_geometry_material_state,
3103 // update_geometry_material_state
3105 // ============================================================================
3108 // i) the material shader storage buffer object
3110 OSG::MultiPropertySSBOChunkTransitPtr create_material_database_state(const VecMaterialsT& vMaterials)
3112 OSG::MultiPropertySSBOChunkRefPtr materialChunk = OSG::MultiPropertySSBOChunk::create();
3114 OSG::UInt32 vec3_id, float_id;
3116 vec3_id = materialChunk->addMember(OSG::MultiPropertySSBOChunk:: VEC3_T, 4);
3117 float_id = materialChunk->addMember(OSG::MultiPropertySSBOChunk::FLOAT_T, 2);
3119 materialChunk->setUsage(GL_STATIC_DRAW);
3121 Material:: ambient_id = vec3_id++;
3122 Material:: diffuse_id = vec3_id++;
3123 Material:: specular_id = vec3_id++;
3124 Material:: emissive_id = vec3_id;
3126 Material:: opacity_id = float_id++;
3127 Material::shininess_id = float_id;
3129 BOOST_FOREACH(const Material& mat, vMaterials)
3131 OSG::UInt32 idx = materialChunk->addProperty();
3133 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
3134 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
3135 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
3136 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
3138 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
3139 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
3142 return OSG::MultiPropertySSBOChunkTransitPtr(materialChunk);
3145 void update_material_database_state(OSG::MultiPropertySSBOChunk* materialChunk, const VecMaterialsT& vMaterials)
3147 if (materialChunk)
3149 if (materialChunk->getNumProperties() != vMaterials.size())
3151 materialChunk->clearProperties();
3153 BOOST_FOREACH(const Material& mat, vMaterials)
3155 OSG::UInt32 idx = materialChunk->addProperty();
3157 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
3158 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
3159 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
3160 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
3162 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
3163 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
3166 else
3168 for (OSG::UInt32 idx = 0; idx < vMaterials.size(); ++idx)
3170 const Material& mat = vMaterials[idx];
3172 materialChunk->setVec3Property (idx, Material:: ambient_id, mat.ambient);
3173 materialChunk->setVec3Property (idx, Material:: diffuse_id, mat.diffuse);
3174 materialChunk->setVec3Property (idx, Material:: specular_id, mat.specular);
3175 materialChunk->setVec3Property (idx, Material:: emissive_id, mat.emissive);
3177 materialChunk->setFloatProperty(idx, Material:: opacity_id, mat.opacity);
3178 materialChunk->setFloatProperty(idx, Material::shininess_id, mat.shininess);
3185 // ii) the geomertry shader storage buffer object
3187 OSG::MultiPropertyUBOChunkTransitPtr create_geometry_material_state(const GeomState& geomState)
3189 OSG::MultiPropertyUBOChunkRefPtr geomStateChunk = OSG::MultiPropertyUBOChunk::create();
3191 GeomState::material_index_id = geomStateChunk->addMember(OSG::MultiPropertyUBOChunk::UINT_T, 1);
3192 geomStateChunk->setUsage(GL_DYNAMIC_DRAW);
3194 OSG::UInt32 idx = geomStateChunk->addProperty();
3195 geomStateChunk->setUIntProperty(idx, GeomState::material_index_id, geomState.material_index);
3197 return OSG::MultiPropertyUBOChunkTransitPtr(geomStateChunk);
3200 void update_geometry_material_state(OSG::MultiPropertyUBOChunk* geomStateChunk, const GeomState& geomState)
3202 if (geomStateChunk)
3204 if (geomStateChunk->getNumProperties() != 1)
3206 geomStateChunk->clearProperties();
3208 OSG::UInt32 idx = geomStateChunk->addProperty();
3209 geomStateChunk->setUIntProperty(idx, GeomState::material_index_id, geomState.material_index);
3211 else
3213 geomStateChunk->setUIntProperty( 0, GeomState::material_index_id, geomState.material_index);
3218 // ============================================================================
3220 // Part: The application finally starts here
3222 // ============================================================================
3224 // UBO block binding points
3225 const OSG::UInt32 geom_binding_point = 0;
3226 const OSG::UInt32 dispatch_data_binding_point = 1;
3227 const OSG::UInt32 clustering_data_binding_point = 2;
3229 // SSBO block binding points
3230 const OSG::UInt32 material_binding_point = 0;
3231 const OSG::UInt32 light_binding_point = 1;
3232 const OSG::UInt32 affected_light_index_binding_point = 2;
3233 const OSG::UInt32 frustum_binding_point = 3;
3234 const OSG::UInt32 light_index_binding_point = 4;
3235 const OSG::UInt32 light_index_counter_binding_point = 5;
3237 const OSG::UInt32 cpu_frustum_binding_point = 6;
3238 const OSG::UInt32 test_data_binding_point = 7;
3240 // Texture binding points
3241 const OSG::UInt32 light_grid_binding_point = 0;
3242 const OSG::UInt32 cpu_light_grid_binding_point = 1;
3245 // shader programs.
3247 std::string get_persp_frustum_cp_program();
3248 std::string get_ortho_frustum_cp_program();
3249 std::string get_light_culling_cp_program();
3250 std::string get_vp_program();
3251 std::string get_fp_program();
3253 OSG::ShaderProgramRefPtr frag_shader = NULL;
3256 // The scene
3258 OSG::NodeRefPtr scene_node = NULL;
3261 // Frustum compute node
3263 OSG::NodeRefPtr compute_frustum_node = NULL;
3264 OSG::ShaderProgramRefPtr compute_frustum_shader = NULL;
3265 OSG::ComputeShaderAlgorithmRefPtr compute_frustum_shader_algorithm = NULL;
3268 // Cluster visualisation root node
3270 OSG::NodeRefPtr cluster_geometry_root_node = NULL;
3273 // Light culling compute node
3275 OSG::NodeRefPtr compute_light_culling_node = NULL;
3276 OSG::ShaderProgramRefPtr compute_light_culling_shader = NULL;
3277 OSG::ComputeShaderAlgorithmRefPtr compute_light_culling_shader_algorithm = NULL;
3280 // A HDR stage core
3282 OSG::HDR2StageRefPtr hdr_stage = NULL;
3283 OSG::NodeRefPtr hdr_node = NULL;
3286 // The material database for all visible geometry: objects, lights, stage box
3288 OSG::MultiPropertySSBOChunkRefPtr ssbo_material_database = NULL;
3290 OSG::UniformBufferObjChunkRefPtr ubo_frustum_dispatch_data = NULL;
3291 OSG::UniformBufferObjChunkRefPtr ubo_light_culling_dispatch_data = NULL;
3293 OSG::UniformBufferObjChunkRefPtr ubo_clustering_data = NULL;
3296 // The frustum planes calculated by the computation shader
3298 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_frustums = NULL;
3299 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_frustums_cpu = NULL;
3302 // Test data for various test
3304 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_test_data = NULL;
3307 // The global light lists
3309 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_affected_light_index_list = NULL;
3310 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_light_index_list = NULL;
3313 // Light culling compute shader global light index counter
3315 OSG::ShaderStorageBufferObjStdLayoutChunkRefPtr ssbo_light_index_counter = NULL;
3318 // Light grid
3320 OSG::ImageRefPtr light_grid_image = NULL;
3321 OSG::ImageRefPtr light_grid_image_cpu = NULL;
3323 OSG::TextureObjChunkRefPtr light_grid_texture_object = NULL;
3324 OSG::TextureObjChunkRefPtr light_grid_texture_object_cpu = NULL;
3326 OSG::TextureImageChunkRefPtr light_grid_texture_image_cs = NULL;
3327 OSG::TextureImageChunkRefPtr light_grid_texture_image_fs = NULL;
3328 OSG::TextureImageChunkRefPtr light_grid_texture_image_cpu = NULL;
3331 // The mulit light chunk
3333 OSG::MultiLightChunkRefPtr multi_light_chunk = NULL;
3336 // The shader program variable chunk for the geom state
3338 OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = NULL;
3341 // Shader Storage buffer objects corresponding to transient shader blocks
3343 std::vector<OSG::MultiPropertyUBOChunkRefPtr> ubo_geom_states;
3346 // A separate transformation for each object and a spline for the trajectory
3348 std::vector<OSG::NodeRefPtr> geom_nodes;
3349 std::vector<OSG::TransformRefPtr> geom_trafos;
3350 std::vector<SmoothCubicBezierSpline> geom_curves;
3353 // Simulate some movement in the scene
3355 void update_simulation()
3358 // Simulation code: If enough time has passed perform a simulation step.
3361 if (time_stamp == 0) time_stamp = OSG::getTimeStamp();
3363 OSG::Time elapsed = OSG::getTimeStampMsecs(OSG::getTimeStamp() - time_stamp);
3365 if (elapsed > elapse_time_limit)
3367 OSG::Matrix matSimulation;
3369 simulation_param += simulation_delta;
3370 if (simulation_param >= 1.f)
3371 simulation_param = 0.f;
3373 if (simulate_geometry)
3375 std::size_t numCurves = geom_curves.size();
3377 OSG_ASSERT(numCurves == geom_trafos.size());
3379 for (std::size_t i = 0; i < numCurves; ++i)
3381 matSimulation = geom_curves[i].frame(simulation_param);
3382 geom_trafos[i]->setMatrix(matSimulation);
3386 if (simulate_lights)
3388 BOOST_FOREACH(Light& light, lights)
3390 matSimulation = light.curve.frame(simulation_param, true);
3391 light.transform->setMatrix(matSimulation);
3396 time_stamp = OSG::getTimeStamp();
3401 // HDR stage ...
3403 void setup_hdr_stage()
3405 if (hdr_stage)
3407 hdr_stage->setApplyGamma (true);
3408 hdr_stage->setAccurateGamma (true);
3410 hdr_stage->setAdjustLuminance (false);
3412 hdr_stage->setPerformBloom (false);
3413 hdr_stage->setBloomBackground (false);
3415 hdr_stage->setForceBackground (true);
3416 hdr_stage->setUse_ITU_R_BT_709 (true);
3417 hdr_stage->setMipmapLevel (-1);
3419 hdr_stage->setTarget (OSG::HDR2Stage::COMPOSITE_TEXTURE);
3420 hdr_stage->setCarryDepth (true);
3422 hdr_stage->setColorBufferInternalFormat (GL_RGBA16F);
3423 hdr_stage->setColorBufferPixelFormat (GL_RGBA);
3424 hdr_stage->setColorBufferType (GL_FLOAT);
3426 hdr_stage->setDepthBufferInternalFormat (GL_DEPTH24_STENCIL8);
3427 hdr_stage->setDepthBufferPixelFormat (GL_DEPTH_STENCIL);
3428 hdr_stage->setDepthBufferType (GL_UNSIGNED_INT_24_8);
3430 hdr_stage->setLumBufferInternalFormat (GL_R32F);
3431 hdr_stage->setLumBufferPixelFormat (GL_RED);
3432 hdr_stage->setLumBufferType (GL_FLOAT);
3434 hdr_stage->setImageBufferInternalFormat (GL_RGB16F);
3435 hdr_stage->setImageBufferPixelFormat (GL_RGB);
3436 hdr_stage->setImageBufferType (GL_FLOAT);
3438 hdr_stage->setNumSamples (0);
3440 hdr_stage->setBloomThreshold (2.0f);
3441 hdr_stage->setBloomMagnitude (0.0f);
3442 hdr_stage->setToneMappingMode (OSG::HDR2Stage::REINHARD_TONE_MAPPING);
3443 hdr_stage->setExposure (0.0f);
3444 hdr_stage->setKeyValue (0.18f);
3445 hdr_stage->setAutoExposureMode (OSG::HDR2Stage::MANUAL);
3446 hdr_stage->setWhiteLevel (5.0f);
3447 hdr_stage->setFilmicShoulderStrenght (0.15f);
3448 hdr_stage->setFilmicLinearStrength (0.5f);
3449 hdr_stage->setFilmicLinearAngle (0.1f);
3450 hdr_stage->setFilmicToeStrength (0.2f);
3451 hdr_stage->setFilmicToeNumerator (0.02f);
3452 hdr_stage->setFilmicToeDenominator (0.3f);
3453 hdr_stage->setFilmicLinearWhite (11.2f);
3454 hdr_stage->setSaturation (1.0f);
3455 hdr_stage->setDragoBias (0.85f);
3456 hdr_stage->setTau (1.25f);
3457 hdr_stage->setNumTaps (4);
3458 hdr_stage->setBlurGaussSigma (0.8f);
3459 hdr_stage->setUseLinChromCorrection (true);
3463 void removeHDRStage()
3465 OSG::GroupRefPtr group = OSG::Group::create();
3466 hdr_node->setCore(group);
3468 hdr_stage = NULL;
3471 void createHDRStage()
3473 if (!hdr_stage)
3475 hdr_stage = OSG::HDR2Stage::create();
3476 setup_hdr_stage();
3479 if (hdr_node)
3480 hdr_node->setCore(hdr_stage);
3483 OSG::AlgorithmComputeElementTransitPtr createFrustumComputation()
3485 ubo_frustum_dispatch_data = create_dispatch_data(DispatchData());
3487 OSG::ChunkMaterialRefPtr chunkMaterial = OSG::ChunkMaterial::create();
3488 chunkMaterial->addChunk(ubo_frustum_dispatch_data, dispatch_data_binding_point);
3489 chunkMaterial->addChunk(ssbo_frustums, frustum_binding_point);
3491 compute_frustum_shader = OSG::ShaderProgram::create();
3492 compute_frustum_shader->setShaderType(GL_COMPUTE_SHADER);
3493 compute_frustum_shader->setProgram(use_ortho_camera ? get_ortho_frustum_cp_program() : get_persp_frustum_cp_program());
3494 compute_frustum_shader->addUniformBlock ("DispatchData", dispatch_data_binding_point);
3495 compute_frustum_shader->addShaderStorageBlock("Frustums", frustum_binding_point);
3497 OSG::ComputeShaderChunkRefPtr compShaderChunk = OSG::ComputeShaderChunk::create();
3498 compShaderChunk->addComputeShader(compute_frustum_shader);
3499 compShaderChunk->setVariables(compute_frustum_shader->getVariables());
3501 compute_frustum_shader_algorithm = OSG::ComputeShaderAlgorithm::create();
3502 compute_frustum_shader_algorithm->setUseMemoryBarrier(true);
3503 compute_frustum_shader_algorithm->setMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
3504 compute_frustum_shader_algorithm->setComputeShader(compShaderChunk);
3506 OSG::Vec3i work_group_count(1,1,1);
3507 compute_frustum_shader_algorithm->setDispatchConfig(work_group_count);
3508 compute_frustum_shader_algorithm->setChunkMaterial(chunkMaterial);
3510 OSG::AlgorithmComputeElementRefPtr algoCompElement = OSG::AlgorithmComputeElement::create();
3511 algoCompElement->setAlgorithm(compute_frustum_shader_algorithm);
3513 return OSG::AlgorithmComputeElementTransitPtr(algoCompElement);
3516 OSG::AlgorithmComputeElementTransitPtr createLightCullingComputation()
3518 ubo_light_culling_dispatch_data = create_dispatch_data(DispatchData());
3520 ssbo_light_index_counter = create_light_index_counter_state();
3522 OSG::ChunkMaterialRefPtr chunkMaterial = OSG::ChunkMaterial::create();
3523 chunkMaterial->addChunk(light_grid_texture_image_cs, light_grid_binding_point);
3524 chunkMaterial->addChunk(multi_light_chunk, light_binding_point);
3525 chunkMaterial->addChunk(ubo_light_culling_dispatch_data, dispatch_data_binding_point);
3526 chunkMaterial->addChunk(ubo_clustering_data, clustering_data_binding_point);
3527 //chunkMaterial->addChunk(ssbo_test_data, test_data_binding_point);
3528 chunkMaterial->addChunk(ssbo_frustums, frustum_binding_point);
3529 chunkMaterial->addChunk(ssbo_affected_light_index_list, affected_light_index_binding_point);
3530 chunkMaterial->addChunk(ssbo_light_index_list, light_index_binding_point);
3531 chunkMaterial->addChunk(ssbo_light_index_counter, light_index_counter_binding_point);
3532 //chunkMaterial->addChunk(ssbo_frustums_cpu, cpu_frustum_binding_point);
3534 compute_light_culling_shader = OSG::ShaderProgram::create();
3535 compute_light_culling_shader->setShaderType(GL_COMPUTE_SHADER);
3536 compute_light_culling_shader->setProgram(get_light_culling_cp_program());
3537 compute_light_culling_shader->addShaderStorageBlock("Lights", light_binding_point);
3538 compute_light_culling_shader->addUniformBlock ("DispatchData", dispatch_data_binding_point);
3539 compute_light_culling_shader->addUniformBlock ("ClusteringData", clustering_data_binding_point);
3540 //compute_light_culling_shader->addShaderStorageBlock("TestData", test_data_binding_point);
3541 compute_light_culling_shader->addShaderStorageBlock("Frustums", frustum_binding_point);
3542 compute_light_culling_shader->addShaderStorageBlock("AffectedLightIndexList", affected_light_index_binding_point);
3543 compute_light_culling_shader->addShaderStorageBlock("LightIndexList", light_index_binding_point);
3544 compute_light_culling_shader->addShaderStorageBlock("LightIndexCounter", light_index_counter_binding_point);
3545 //compute_light_culling_shader->addShaderStorageBlock("CPUFrustums", cpu_frustum_binding_point);
3547 OSG::ComputeShaderChunkRefPtr compShaderChunk = OSG::ComputeShaderChunk::create();
3548 compShaderChunk->addComputeShader(compute_light_culling_shader);
3549 compShaderChunk->setVariables(compute_light_culling_shader->getVariables());
3551 compute_light_culling_shader_algorithm = OSG::ComputeShaderAlgorithm::create();
3552 compute_light_culling_shader_algorithm->setUseMemoryBarrier(true);
3553 compute_light_culling_shader_algorithm->setMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
3554 compute_light_culling_shader_algorithm->setComputeShader(compShaderChunk);
3556 OSG::Vec3i work_group_count(1,1,1);
3557 compute_light_culling_shader_algorithm->setDispatchConfig(work_group_count);
3558 compute_light_culling_shader_algorithm->setChunkMaterial(chunkMaterial);
3560 OSG::AlgorithmComputeElementRefPtr algoCompElement = OSG::AlgorithmComputeElement::create();
3561 algoCompElement->setAlgorithm(compute_light_culling_shader_algorithm);
3563 return OSG::AlgorithmComputeElementTransitPtr(algoCompElement);
3566 void updateDispatchConfigFrustums(
3567 const OSG::Vec4u& viewport,
3568 const OSG::Matrix& matInvProjection)
3570 OSG::Real32 x_v = static_cast<OSG::Real32>(viewport[0]);
3571 OSG::Real32 y_v = static_cast<OSG::Real32>(viewport[1]);
3572 OSG::Real32 w = static_cast<OSG::Real32>(viewport[2]);
3573 OSG::Real32 h = static_cast<OSG::Real32>(viewport[3]);
3576 // width in pixel divided by tile size in pixel, e.g. 1280 / 16 = 80
3577 // height in pixel divided by tile size in pixel, e.g. 720 / 16 = 45
3579 OSG::Real32 numHorizontalTiles = OSG::osgCeil(w / tile_size);
3580 OSG::Real32 numVerticalTiles = OSG::osgCeil(h / tile_size);
3582 DispatchData data;
3583 data.matTransf = matInvProjection;
3584 data.viewport = viewport;
3585 data.numTiles = OSG::Vec2i( OSG::Int32(numHorizontalTiles), OSG::Int32(numVerticalTiles) ); // e.g. (80, 45)
3587 VecFrustumsT vFrustums(data.numTiles.x() * data.numTiles.y()); // e.g. 80 * 45 = 3600
3588 update_frustum_state(ssbo_frustums, vFrustums);
3589 update_dispatch_data(ubo_frustum_dispatch_data, data);
3591 OSG::UInt32 szX = OSG::UInt32(OSG::osgCeil(numHorizontalTiles / work_group_size.x())); // e.g. 80 / 16 ~ 5
3592 OSG::UInt32 szY = OSG::UInt32(OSG::osgCeil( numVerticalTiles / work_group_size.y())); // e.g. 45 / 16 ~ 3
3593 OSG::UInt32 szZ = 1;
3595 OSG::Vec3i work_group_count = OSG::Vec3i(szX, szY, szZ); // e.g. (5,3,1)
3596 compute_frustum_shader_algorithm->setDispatchConfig(work_group_count);
3599 void updateDispatchConfigCullLights(
3600 const OSG::Vec4u& viewport,
3601 const OSG::Matrix& matViewing)
3603 OSG::Real32 x_v = static_cast<OSG::Real32>(viewport[0]);
3604 OSG::Real32 y_v = static_cast<OSG::Real32>(viewport[1]);
3605 OSG::Real32 w = static_cast<OSG::Real32>(viewport[2]);
3606 OSG::Real32 h = static_cast<OSG::Real32>(viewport[3]);
3609 // width in pixel divided by tile size in pixel, e.g. 1280 / 16 = 80
3610 // height in pixel divided by tile size in pixel, e.g. 720 / 16 = 45
3612 OSG::Real32 numHorizontalTiles = OSG::osgCeil(w / tile_size);
3613 OSG::Real32 numVerticalTiles = OSG::osgCeil(h / tile_size);
3615 DispatchData data;
3616 data.matTransf = matViewing;
3617 data.viewport = viewport;
3618 data.numTiles = OSG::Vec2i( OSG::Int32(numHorizontalTiles), OSG::Int32(numVerticalTiles) ); // e.g. (80, 45)
3620 update_dispatch_data(ubo_light_culling_dispatch_data, data);
3622 OSG::Vec3i work_group_count = OSG::Vec3i(numHorizontalTiles, numVerticalTiles, num_cluster_z); // e.g. (80,45,32)
3623 compute_light_culling_shader_algorithm->setDispatchConfig(work_group_count);
3627 // Lights...
3629 void deinitialize_lights()
3631 BOOST_FOREACH(const Light& light, lights)
3633 scene_node->subChild(light.beacon);
3636 lights.clear();
3639 void initialize_lights(OSG::UInt32 num) // helper to create lights
3641 deinitialize_lights();
3643 for (OSG::UInt32 i = 0; i < num; ++i)
3646 int n = classic_die();
3647 Light::Type type;
3649 switch (n)
3651 case 1:
3652 case 2:
3653 type = Light::point_light;
3654 break;
3655 case 3:
3656 case 4:
3657 type = Light::spot_light;
3658 break;
3659 case 5:
3660 case 6:
3661 type = Light::cinema_light;
3662 break;
3665 lights.push_back(Light::create_light(type));
3667 lights[i].create_light_geometry(i+1);
3669 scene_node->addChild(lights[i].beacon);
3672 if (Light::add_dir_test_lights)
3674 lights.push_back(Light::create_light(Light::directional_light, 0));
3675 lights.push_back(Light::create_light(Light::directional_light, 1));
3679 void change_spot_dir_lights()
3681 for (std::size_t i = 0; i < lights.size(); ++i)
3683 Light& light = lights[i];
3685 switch (Light::force_spot_dir)
3687 case 0: light.direction = dice_unit_vector(); break;
3688 case 1: light.direction = OSG::Vec3f(0, 0,-1); break;
3689 case 2: light.direction = OSG::Vec3f(1, 0, 0); break;
3690 case 3: light.direction = OSG::Vec3f(0,-1, 0); break;
3691 case 4: light.direction = OSG::Vec3f(1, 0,-1); break;
3692 case 5: light.direction = OSG::Vec3f(1,-1,-1); break;
3693 case 6:
3695 static bool increase_flag = true;
3697 light.direction = Light::dir_test_case_6;
3698 light.direction.normalize();
3700 OSG::Vec3f e1(1,0,-1);
3701 OSG::Vec3f e2(0,0,-1);
3703 if (Light::dir_test_case_6.equals(e1, OSG::Eps))
3704 increase_flag = false;
3705 if (Light::dir_test_case_6.equals(e2, OSG::Eps))
3706 increase_flag = true;
3708 if (increase_flag)
3709 Light::dir_test_case_6 += OSG::Vec3f(0.1f, 0.f, 0.f);
3710 else
3711 Light::dir_test_case_6 -= OSG::Vec3f(0.1f, 0.f, 0.f);
3713 break;
3714 case 7:
3716 static bool increase_flag = true;
3718 light.direction = Light::dir_test_case_7;
3719 light.direction.normalize();
3721 OSG::Vec3f e1(1,-1,-1);
3722 OSG::Vec3f e2(0,0,-1);
3724 if (Light::dir_test_case_7.equals(e1, OSG::Eps))
3725 increase_flag = false;
3726 if (Light::dir_test_case_7.equals(e2, OSG::Eps))
3727 increase_flag = true;
3729 if (increase_flag)
3730 Light::dir_test_case_7 += OSG::Vec3f(0.1f, -0.1f, 0.f);
3731 else
3732 Light::dir_test_case_7 -= OSG::Vec3f(0.1f, -0.1f, 0.f);
3734 break;
3736 case 8:
3738 static bool increase_flag = true;
3740 light.direction = Light::dir_test_case_8;
3741 light.direction.normalize();
3743 OSG::Vec3f e1(0,-1, 0);
3744 OSG::Vec3f e2(0, 0,-1);
3746 if (Light::dir_test_case_8.equals(e1, OSG::Eps))
3747 increase_flag = false;
3748 if (Light::dir_test_case_8.equals(e2, OSG::Eps))
3749 increase_flag = true;
3751 if (increase_flag)
3752 Light::dir_test_case_8 += OSG::Vec3f(0.f, -0.1f, 0.1f);
3753 else
3754 Light::dir_test_case_8 -= OSG::Vec3f(0.f, -0.1f, 0.1f);
3756 break;
3758 case 9:
3761 break;
3764 lights[i].create_light_geometry(OSG::UInt32(i+1));
3768 Light Light::create_light(
3769 Type e, // type of the light
3770 OSG::Int32 test_dir_light_type) // for special testing directional lights
3772 Light l(e);
3774 l.beacon = OSG::makeCoredNode<OSG::Transform>(&l.transform);
3775 l.transform->setMatrix(OSG::Matrix::identity());
3777 OSG::Real32 L = box_factor * world_size;
3779 switch (Light::force_spot_dir)
3781 case 0: l.direction = dice_unit_vector(); break;
3782 case 1: l.direction = OSG::Vec3f(0, 0,-1); break;
3783 case 2: l.direction = OSG::Vec3f(1, 0, 0); break;
3784 case 3: l.direction = OSG::Vec3f(0,-1, 0); break;
3785 case 4: l.direction = OSG::Vec3f(1, 0,-1); break;
3786 case 5: l.direction = OSG::Vec3f(1,-1,-1); break;
3787 case 6: l.direction = OSG::Vec3f(0, 0,-1); break;
3788 case 7: l.direction = OSG::Vec3f(0, 0,-1); break;
3789 case 8: l.direction = OSG::Vec3f(0, 0,-1); break;
3790 case 9: break;
3793 Light::dir_test_case_6 = OSG::Vec3f(0,0,-1);
3794 Light::dir_test_case_7 = OSG::Vec3f(0,0,-1);
3795 Light::dir_test_case_8 = OSG::Vec3f(0,0,-1);
3797 l.color.setRandom();
3798 l.intensity = max_light_power * small_die();
3799 l.range = L * light_range_die();
3801 switch (e)
3803 case point_light:
3806 break;
3808 case directional_light:
3810 if (Light::add_dir_test_lights)
3812 if (test_dir_light_type == 0)
3813 l.direction = OSG::Vec3f(0,0,-1);
3814 if (test_dir_light_type == 1)
3815 l.direction = OSG::Vec3f(0,0,1);
3817 l.intensity = 0.1f;
3820 break;
3822 case spot_light:
3824 l.spotlightAngle = spot_die();
3826 break;
3828 case cinema_light:
3830 l.innerSuperEllipsesWidth = light_ellipsis_radius_die();
3831 l.innerSuperEllipsesHeight = light_ellipsis_radius_die();
3833 float f = light_ellipsis_radius_ratio_die();
3835 l.outerSuperEllipsesWidth = f * l.innerSuperEllipsesWidth;
3836 l.outerSuperEllipsesHeight = f * l.innerSuperEllipsesHeight;
3838 int n = classic_die();
3839 switch (n)
3841 case 1:
3842 case 2:
3843 l.superEllipsesRoundness = light_ellipsis_roundness_die1();
3844 break;
3845 case 3:
3846 case 4:
3847 l.superEllipsesRoundness = light_ellipsis_roundness_die2();
3848 break;
3849 case 5:
3850 case 6:
3851 l.superEllipsesRoundness = light_ellipsis_roundness_die3();
3852 break;
3855 l.superEllipsesTwist = light_ellipsis_twist_die();
3857 //std::cout << "d = (" << l.direction.x() << ", " << l.direction.y() << ", " << l.direction.z() << ")" << std::endl;
3858 //std::cout << "a = " << l.innerSuperEllipsesWidth << std::endl;
3859 //std::cout << "b = " << l.innerSuperEllipsesHeight << std::endl;
3860 //std::cout << "A = " << l.outerSuperEllipsesWidth << std::endl;
3861 //std::cout << "B = " << l.outerSuperEllipsesHeight << std::endl;
3862 //std::cout << "r = " << l.superEllipsesRoundness << std::endl;
3863 //std::cout << "w = " << l.superEllipsesTwist << std::endl;
3865 break;
3867 default:
3868 break;
3871 return l;
3874 void Light::create_light_geometry(OSG::UInt32 material_idx)
3876 if (!beacon) return;
3878 beacon->clearChildren();
3880 Material mat;
3881 mat.emissive = color;
3882 mat.opacity = 0.7f;
3884 materials[material_idx] = mat;
3886 OSG::ChunkMaterialRefPtr geomState = OSG::ChunkMaterial::create();
3888 OSG::Real32 R = range;
3890 if (!correct_light_geometry)
3891 R = 0.5;
3893 switch (type)
3895 case point_light:
3897 OSG::GeometryRefPtr geometry = OSG::makeSphereGeo(3, R);
3898 OSG::NodeRefPtr node = OSG::makeNodeFor(geometry);
3900 GeomState geom; geom.material_index = material_idx; // material index used for light animiation
3901 OSG::MultiPropertyUBOChunkRefPtr uboGeomState = create_geometry_material_state(geom);
3902 geomState->addChunk(uboGeomState, geom_binding_point); // buffer binding point
3903 geomState->addChunk(shader_var_chunk); // block binding point
3905 geometry->setMaterial(geomState);
3907 beacon->addChild(node);
3910 // Test: Add mini sphere at the origin of the point light sphere
3913 // OSG::GeometryRefPtr geometry = OSG::makeSphereGeo(6, 0.1);
3914 // OSG::NodeRefPtr node = OSG::makeNodeFor(geometry);
3916 // GeomState geom; geom.material_index = material_idx; // material index used for light animiation
3917 // OSG::MultiPropertyUBOChunkRefPtr uboGeomState = create_geometry_material_state(geom);
3918 // geomState->addChunk(uboGeomState, geom_binding_point); // buffer binding point
3919 // geomState->addChunk(shader_var_chunk); // block binding point
3921 // geometry->setMaterial(geomState);
3923 // beacon->addChild(node);
3926 break;
3928 case directional_light:
3931 break;
3933 case spot_light:
3935 GeomState geom; geom.material_index = material_idx; // material index used for light animiation
3936 OSG::MultiPropertyUBOChunkRefPtr uboGeomState = create_geometry_material_state(geom);
3937 geomState->addChunk(uboGeomState, geom_binding_point); // buffer binding point
3938 geomState->addChunk(shader_var_chunk); // block binding point
3940 OSG::Real32 h = R;
3942 OSG::GeometryRefPtr geometry = makeSpotGeo(h, spotlightAngle, 24, 24);
3943 geometry->setMaterial(geomState);
3946 // Test code
3948 //OSG::Vec3f a, b, c; OSG::Matrix t;
3949 //a = OSG::Vec3f(0.f, 1.f, 0.f); b = OSG::Vec3f(0.f, 1.f, 0.f); c = OSG::Vec3f(0,0,0);
3950 //t = rotate_a_into_direction_b(a, b);
3951 //t.mult(a, c);
3953 //a = OSG::Vec3f(0.f, 1.f, 0.f); b = OSG::Vec3f(0.f, -1.f, 0.f); c = OSG::Vec3f(0,0,0);
3954 //t = rotate_a_into_direction_b(a, b);
3955 //t.mult(a, c);
3957 //a = OSG::Vec3f(15.f, 61.f, 53.f); b = OSG::Vec3f(15.f, 61.f, 53.f); c = OSG::Vec3f(0,0,0);
3958 //t = rotate_a_into_direction_b(a, b);
3959 //t.mult(a, c);
3961 //a = OSG::Vec3f(15.f, 61.f, 53.f); b = OSG::Vec3f(-15.f, -61.f, -53.f); c = OSG::Vec3f(0,0,0);
3962 //t = rotate_a_into_direction_b(a, b);
3963 //t.mult(a, c);
3965 //a = OSG::Vec3f(745.f, 23.f, -153.f); b = OSG::Vec3f(-135.f, 561.f, 253.f); c = OSG::Vec3f(0,0,0);
3966 //t = rotate_a_into_direction_b(a, b);
3967 //t.mult(a, c);
3968 //b.normalize();
3969 //c.normalize();
3971 //a = OSG::Vec3f(745.f, 23.f, -153.f); b = OSG::Vec3f(-135.f, 561.f, 253.f); c = OSG::Vec3f(0,0,0);
3972 //a.normalize(); b.normalize();
3973 //t = rotate_a_into_direction_b(a, b);
3974 //t.mult(a, c);
3976 //a = OSG::Vec3f(745.f, 23.f, -153.f); b = OSG::Vec3f(-135.f, 561.f, 253.f); c = OSG::Vec3f(0,0,0);
3977 //a.normalize(); b.normalize();
3978 //t = rotate_a_into_direction_b(a, b);
3979 //a.negate();
3980 //t.mult(a, c);
3982 //a = OSG::Vec3f(-3.f, 1.f, 7.f); b = OSG::Vec3f(-4.f, -1.f, 5.f); c = OSG::Vec3f(0,0,0);
3983 //b.normalize();
3984 //t = rotate_a_into_direction_b(a, b);
3985 //a = OSG::Vec3f(4.f, -2.f, 0.6f); a.normalize();
3986 //t.mult(a, c);
3987 //OSG::Real32 L = c.length();
3989 OSG::TransformRefPtr coneTrans = OSG::Transform::create();
3991 OSG::Matrix rotMat = rotate_a_into_direction_b(OSG::Vec3f(0.f, 1.f, 0.f), direction);
3992 coneTrans->setMatrix(rotMat);
3994 OSG::NodeRefPtr coneTransNode = OSG::makeNodeFor(coneTrans);
3995 OSG::NodeRefPtr coneNode = OSG::makeNodeFor(geometry);
3997 beacon->addChild(coneTransNode);
3998 coneTransNode->addChild(coneNode);
4001 // Create a help line to visualize the spot hit point on the wall
4003 if (Light::show_spot_dir_line)
4005 OSG::GeometryRefPtr line_geometry = OSG::makeCylinderGeo(30, 0.1f, 24, true, true, true );
4006 line_geometry->setMaterial(geomState);
4008 OSG::TransformRefPtr line_translation = OSG::Transform::create();
4009 OSG::Matrix matLineTrans;
4010 matLineTrans.setTranslate(OSG::Vec3f(0,-15,0));
4011 line_translation->setMatrix(matLineTrans);
4013 OSG::TransformRefPtr line_rotation = OSG::Transform::create();
4014 OSG::Matrix matLineRot;
4015 matLineRot.setRotate(OSG::Quaternion(OSG::Vec3f(1,0,0), OSG::Pi));
4016 line_rotation->setMatrix(matLineRot);
4018 OSG::NodeRefPtr lineRotationNode = OSG::makeNodeFor(line_rotation);
4019 OSG::NodeRefPtr lineTranslationNode = OSG::makeNodeFor(line_translation);
4020 OSG::NodeRefPtr lineGeometryNode = OSG::makeNodeFor(line_geometry);
4021 coneTransNode ->addChild(lineRotationNode);
4022 lineRotationNode ->addChild(lineTranslationNode);
4023 lineTranslationNode->addChild(lineGeometryNode);
4026 break;
4028 case cinema_light:
4030 GeomState geom; geom.material_index = material_idx; // material index used for light animiation
4031 OSG::MultiPropertyUBOChunkRefPtr uboGeomState = create_geometry_material_state(geom);
4032 geomState->addChunk(uboGeomState, geom_binding_point); // buffer binding point
4033 geomState->addChunk(shader_var_chunk); // block binding point
4035 OSG::Real32 h = R;
4037 OSG::GeometryRefPtr geometry = makeCinemaGeo(
4038 outerSuperEllipsesWidth,
4039 outerSuperEllipsesHeight,
4040 superEllipsesRoundness,
4041 OSG::osgDegree2Rad(superEllipsesTwist),
4042 h, 48, 48);
4043 geometry->setMaterial(geomState);
4045 OSG::Matrix matLSFromWS;
4047 OSG::Matrix matLightPos;
4048 matLightPos.setTranslate(position);
4050 OSG::Matrix matLightDir;
4051 OSG::Quaternion rotLightDir(OSG::Vec3f(0.f, 0.f, 1.f), -direction);
4052 matLightDir.setRotate(rotLightDir);
4054 matLSFromWS.mult (matLightPos);
4055 matLSFromWS.mult (matLightDir);
4057 OSG::Matrix matRot;
4058 matRot.setRotate(OSG::Quaternion(OSG::Vec3f(1,0,0), -0.5*OSG::Pi));
4060 matLSFromWS.mult(matRot);
4062 OSG::TransformRefPtr coneTrans = OSG::Transform::create();
4063 coneTrans->setMatrix(matLSFromWS);
4065 //OSG::TransformRefPtr coneTrans = OSG::Transform::create();
4066 //OSG::Matrix rotMat = rotate_a_into_direction_b(OSG::Vec3f(0.f, 1.f, 0.f), direction);
4067 //coneTrans->setMatrix(rotMat);
4069 OSG::NodeRefPtr coneTransNode = OSG::makeNodeFor(coneTrans);
4070 OSG::NodeRefPtr coneNode = OSG::makeNodeFor(geometry);
4072 beacon->addChild(coneTransNode);
4073 coneTransNode->addChild(coneNode);
4076 // Create a help line to visualize the spot hit point on the wall
4078 if (Light::show_spot_dir_line)
4080 OSG::GeometryRefPtr line_geometry = OSG::makeCylinderGeo(30, 0.1f, 24, true, true, true );
4081 line_geometry->setMaterial(geomState);
4083 OSG::TransformRefPtr line_translation = OSG::Transform::create();
4084 OSG::Matrix matLineTrans;
4085 matLineTrans.setTranslate(OSG::Vec3f(0,-15,0));
4086 line_translation->setMatrix(matLineTrans);
4088 OSG::TransformRefPtr line_rotation = OSG::Transform::create();
4089 OSG::Matrix matLineRot;
4090 matLineRot.setRotate(OSG::Quaternion(OSG::Vec3f(1,0,0), OSG::Pi));
4091 line_rotation->setMatrix(matLineRot);
4093 OSG::NodeRefPtr lineRotationNode = OSG::makeNodeFor(line_rotation);
4094 OSG::NodeRefPtr lineTranslationNode = OSG::makeNodeFor(line_translation);
4095 OSG::NodeRefPtr lineGeometryNode = OSG::makeNodeFor(line_geometry);
4096 coneTransNode ->addChild(lineRotationNode);
4097 lineRotationNode ->addChild(lineTranslationNode);
4098 lineTranslationNode->addChild(lineGeometryNode);
4101 break;
4103 default:
4104 break;
4107 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
4108 polygonChunk->setFrontMode(GL_SMOOTH);
4109 polygonChunk->setBackMode(GL_SMOOTH);
4110 polygonChunk->setOffsetFactor(1.f);
4111 polygonChunk->setOffsetBias(1.f);
4112 polygonChunk->setOffsetFill(true);
4114 if (mat.opacity < 1.f)
4116 polygonChunk->setCullFace(GL_BACK);
4118 OSG::BlendChunkRefPtr blendChunk = OSG::BlendChunk::create();
4119 blendChunk->setSrcFactor (GL_SRC_ALPHA);
4120 blendChunk->setDestFactor(GL_ONE_MINUS_SRC_ALPHA);
4121 geomState->addChunk(blendChunk);
4122 geomState->setTransparencyMode(OSG::Material::TransparencyForceTransparent);
4124 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk = OSG::TwoSidedLightingChunk::create();
4125 geomState->addChunk(twoSidedLightingChunk);
4127 } else {
4128 polygonChunk->setCullFace(GL_BACK);
4129 geomState->setTransparencyMode(OSG::Material::TransparencyForceOpaque);
4132 geomState->addChunk(polygonChunk);
4135 OSG::NodeTransitPtr createBox()
4137 OSG::NodeRefPtr boxRoot = OSG::makeCoredNode<OSG::Group>();
4139 OSG::Real32 L = box_factor * world_size;
4140 OSG::GeometryRefPtr boxPlane = OSG::makePlaneGeo(2.f*L, 2.f*L, 128, 128);
4142 OSG::NodeRefPtr boxBottom = OSG::makeNodeFor(boxPlane);
4143 OSG::NodeRefPtr boxLeft = OSG::makeNodeFor(boxPlane);
4144 OSG::NodeRefPtr boxRight = OSG::makeNodeFor(boxPlane);
4145 OSG::NodeRefPtr boxFar = OSG::makeNodeFor(boxPlane);
4147 OSG::TransformRefPtr boxBottomTrans = OSG::Transform::create();
4148 OSG::TransformRefPtr boxLeftTrans = OSG::Transform::create();
4149 OSG::TransformRefPtr boxRightTrans = OSG::Transform::create();
4150 OSG::TransformRefPtr boxFarTrans = OSG::Transform::create();
4152 OSG::Matrix matBottom, matLeft, matRight, matFar;
4154 matBottom.setTransform(OSG::Vec3f(0.f, -L, 0.f), OSG::Quaternion( OSG::Vec3f(1, 0, 0), OSG::osgDegree2Rad(270.f)));
4155 matLeft .setTransform(OSG::Vec3f( -L, 0.f, 0.f), OSG::Quaternion( OSG::Vec3f(0, 1, 0), OSG::osgDegree2Rad(90.f)));
4156 matRight .setTransform(OSG::Vec3f( L, 0.f, 0.f), OSG::Quaternion( OSG::Vec3f(0, 1, 0), OSG::osgDegree2Rad(270.f)));
4157 matFar .setTransform(OSG::Vec3f(0.f, 0.f, -L), OSG::Quaternion( OSG::Vec3f(0, 0, 1), OSG::osgDegree2Rad( 0.f)));
4159 boxBottomTrans ->setMatrix(matBottom);
4160 boxLeftTrans ->setMatrix(matLeft);
4161 boxRightTrans ->setMatrix(matRight);
4162 boxFarTrans ->setMatrix(matFar);
4164 OSG::NodeRefPtr boxBottomTransNode = OSG::makeNodeFor(boxBottomTrans);
4165 OSG::NodeRefPtr boxLeftTransNode = OSG::makeNodeFor(boxLeftTrans);
4166 OSG::NodeRefPtr boxRightTransNode = OSG::makeNodeFor(boxRightTrans);
4167 OSG::NodeRefPtr boxFarTransNode = OSG::makeNodeFor(boxFarTrans);
4169 boxBottomTransNode ->addChild(boxBottom);
4170 boxLeftTransNode ->addChild(boxLeft);
4171 boxRightTransNode ->addChild(boxRight);
4172 boxFarTransNode ->addChild(boxFar);
4174 boxRoot->addChild(boxBottomTransNode);
4175 boxRoot->addChild(boxLeftTransNode);
4176 boxRoot->addChild(boxRightTransNode);
4177 boxRoot->addChild(boxFarTransNode);
4179 GeomState geom; geom.material_index = 0; // grey box material index
4180 OSG::ChunkMaterialRefPtr geomState = OSG::ChunkMaterial::create();
4181 OSG::MultiPropertyUBOChunkRefPtr uboGeomState = create_geometry_material_state(geom);
4182 geomState->addChunk(uboGeomState, geom_binding_point); // buffer binding point
4183 geomState->addChunk(shader_var_chunk); // block binding point
4185 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
4186 polygonChunk->setFrontMode(GL_SMOOTH);
4187 polygonChunk->setBackMode(GL_SMOOTH);
4188 polygonChunk->setOffsetFactor(1.f);
4189 polygonChunk->setOffsetBias(1.f);
4190 polygonChunk->setOffsetFill(true);
4191 polygonChunk->setCullFace(GL_NONE);
4192 geomState->addChunk(polygonChunk);
4194 geomState->setTransparencyMode(OSG::Material::TransparencyForceOpaque);
4196 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk = OSG::TwoSidedLightingChunk::create();
4197 geomState->addChunk(twoSidedLightingChunk);
4199 boxPlane->setMaterial(geomState);
4201 return OSG::NodeTransitPtr(boxRoot);
4204 OSG::NodeTransitPtr createPyramidGeometry(
4205 const OSG::Pnt3f& nlt, const OSG::Pnt3f& nlb,
4206 const OSG::Pnt3f& nrt, const OSG::Pnt3f& nrb,
4207 const OSG::Pnt3f& flt, const OSG::Pnt3f& flb,
4208 const OSG::Pnt3f& frt, const OSG::Pnt3f& frb)
4210 OSG::GeometryRefPtr geometry = makePyramidGeo(nlt, nlb, nrt, nrb, flt, flb, frt, frb);
4212 OSG::NodeRefPtr geomNode = OSG::makeNodeFor(geometry);
4214 GeomState geom; geom.material_index = material_idx_die();
4215 OSG::ChunkMaterialRefPtr geomState = OSG::ChunkMaterial::create();
4216 OSG::MultiPropertyUBOChunkRefPtr uboGeomState = create_geometry_material_state(geom);
4217 geomState->addChunk(uboGeomState, geom_binding_point); // buffer binding point
4218 geomState->addChunk(shader_var_chunk); // block binding point
4220 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
4221 polygonChunk->setFrontMode(GL_SMOOTH);
4222 polygonChunk->setBackMode(GL_SMOOTH);
4223 polygonChunk->setOffsetFactor(1.f);
4224 polygonChunk->setOffsetBias(1.f);
4225 polygonChunk->setOffsetFill(true);
4227 OSG::Real32 opacity = materials[geom.material_index].opacity;
4228 if (opacity < 1.f)
4230 polygonChunk->setCullFace(GL_BACK);
4232 OSG::BlendChunkRefPtr blendChunk = OSG::BlendChunk::create();
4233 blendChunk->setSrcFactor (GL_SRC_ALPHA);
4234 blendChunk->setDestFactor(GL_ONE_MINUS_SRC_ALPHA);
4235 geomState->addChunk(blendChunk);
4236 geomState->setTransparencyMode(OSG::Material::TransparencyForceTransparent);
4238 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk = OSG::TwoSidedLightingChunk::create();
4239 geomState->addChunk(twoSidedLightingChunk);
4241 } else {
4242 polygonChunk->setCullFace(GL_BACK);
4243 geomState->setTransparencyMode(OSG::Material::TransparencyForceOpaque);
4246 geomState->addChunk(polygonChunk);
4247 geometry->setMaterial(geomState);
4249 return OSG::NodeTransitPtr(geomNode);
4252 OSG::NodeTransitPtr createFrustumGeometry(const OSG::FrustumVolume& vol, const OSG::Matrix& m = OSG::Matrix())
4254 OSG::Pnt3f nlt = vol.getCorner(OSG::FrustumVolume::NEAR_LEFT_TOP);
4255 OSG::Pnt3f nlb = vol.getCorner(OSG::FrustumVolume::NEAR_LEFT_BOTTOM);
4256 OSG::Pnt3f nrt = vol.getCorner(OSG::FrustumVolume::NEAR_RIGHT_TOP);
4257 OSG::Pnt3f nrb = vol.getCorner(OSG::FrustumVolume::NEAR_RIGHT_BOTTOM);
4258 OSG::Pnt3f flt = vol.getCorner(OSG::FrustumVolume::FAR_LEFT_TOP);
4259 OSG::Pnt3f flb = vol.getCorner(OSG::FrustumVolume::FAR_LEFT_BOTTOM);
4260 OSG::Pnt3f frt = vol.getCorner(OSG::FrustumVolume::FAR_RIGHT_TOP);
4261 OSG::Pnt3f frb = vol.getCorner(OSG::FrustumVolume::FAR_RIGHT_BOTTOM);
4263 m.multFull(nlt, nlt);
4264 m.multFull(nlb, nlb);
4265 m.multFull(nrt, nrt);
4266 m.multFull(nrb, nrb);
4267 m.multFull(flt, flt);
4268 m.multFull(flb, flb);
4269 m.multFull(frt, frt);
4270 m.multFull(frb, frb);
4272 return createPyramidGeometry(nlt, nlb, nrt, nrb, flt, flb, frt, frb);
4275 void visualize_frustum_cpu(
4276 OSG::Matrix matEyeFromWorld,
4277 const VecFrustumsT& frustums,
4278 OSG::Real32 zNear,
4279 OSG::Real32 zFar)
4281 cluster_geometry_root_node->clearChildren();
4283 if (Frustum::visualize)
4286 // Test 1: simple frustum in world space
4288 //OSG::Pnt3f pz1(0,0, -10);
4289 //OSG::Pnt3f pz2(0,0, -30);
4291 //OSG::Pnt3f nlb(10,10,pz1.z()); OSG::Pnt3f nrb(20,10,pz1.z()); OSG::Pnt3f nlt(10,20,pz1.z()); OSG::Pnt3f nrt(20,20,pz1.z());
4292 //OSG::Pnt3f flb( 5, 5,pz2.z()); OSG::Pnt3f frb(25, 5,pz2.z()); OSG::Pnt3f flt( 5,25,pz2.z()); OSG::Pnt3f frt(25,25,pz2.z());
4294 //cluster_geometry_root_node->addChild(createPyramidGeometry(nlt, nlb, nrt, nrb, flt, flb, frt, frb));
4297 // Test 2: simple frustum but with world space z calculated from eye space zNear and zFar
4299 //OSG::Matrix matWorldFromEye1;
4300 //matEyeFromWorld.inverse(matWorldFromEye1);
4302 //OSG::Pnt3f pz1(0,0,-0.3);
4303 //OSG::Pnt3f pz2(0,0,-300.0);
4305 //matWorldFromEye1.multFull(pz1,pz1);
4306 //matWorldFromEye1.multFull(pz2,pz2);
4308 //OSG::Pnt3f nlb(10,10,pz1.z()); OSG::Pnt3f nrb(20,10,pz1.z()); OSG::Pnt3f nlt(10,20,pz1.z()); OSG::Pnt3f nrt(20,20,pz1.z());
4309 //OSG::Pnt3f flb( 5, 5,pz2.z()); OSG::Pnt3f frb(25, 5,pz2.z()); OSG::Pnt3f flt( 5,25,pz2.z()); OSG::Pnt3f frt(25,25,pz2.z());
4311 //OSG::FrustumVolume vol;
4312 //vol.setPlanes(nlt, nlb, nrt, nrb, flt, flb, frt, frb);
4314 //cluster_geometry_root_node->addChild(createFrustumGeometry(vol));
4317 // Test 3: the view frustum
4319 //OSG::FrustumVolume vol = mgr->getCamera()->calcFrustumVal(*mgr->getWindow()->getPort(0));
4320 //cluster_geometry_root_node->addChild(createFrustumGeometry(vol));
4323 // The actual frustum visualization code
4325 matEyeFromWorld.invert(); // now matWorldFromEye
4326 OSG::Matrix& matWorldFromEye = matEyeFromWorld;
4328 std::size_t sz = frustums.size();
4329 std::size_t i = 0;
4330 BOOST_FOREACH(const Frustum& frustum, frustums)
4332 OSG::Plane nearPlane(OSG::Vec3f(0, 0, 1), -zNear);
4333 OSG::Plane farPlane (OSG::Vec3f(0, 0, 1), -zFar);
4335 OSG::FrustumVolume vol(nearPlane, farPlane, frustum.planes[0], frustum.planes[1], frustum.planes[2], frustum.planes[3]);
4337 //if (i==0 || i == sz-1)
4338 cluster_geometry_root_node->addChild(createFrustumGeometry(vol, matWorldFromEye));
4339 //++i;
4344 OSG::NodeTransitPtr createGeometry()
4346 int idx = geom_idx_die();
4348 OSG::GeometryRefPtr geometry;
4350 switch (idx)
4352 case 0: // cone
4353 geometry = OSG::makeConeGeo(3.f * small_die(), 1.f * small_die(), 24, true, true);
4354 break;
4355 case 1: // box
4356 geometry = OSG::makeBoxGeo(3.f * small_die(), 3.f * small_die(), 3.f * small_die(), 1, 1, 1);
4357 break;
4358 case 2: // cylinder
4359 geometry = OSG::makeCylinderGeo(3.f * small_die(), .3f, 24, true, true, true );
4360 break;
4361 case 3: // sphere
4362 geometry = OSG::makeSphereGeo(6, 3.f * small_die());
4363 break;
4364 case 4: // torus
4365 geometry = OSG::makeTorusGeo(0.6f * small_die(), 2.f * small_die(), 24, 36);
4366 break;
4367 case 5: // ellipsoide
4368 geometry = OSG::makeLatLongEllipsoidGeo(24, 36, 2.f * small_die(), 1.f * small_die());
4369 break;
4370 case 6: // frustum
4371 geometry = OSG::makeConicalFrustumGeo(2.f * small_die(), 2.f * small_die(), 2.f * small_die(), 6, true, true, true);
4372 break;
4373 case 7: // teapot
4374 geometry = OSG::makeTeapotGeo(24, 1.f * small_die());
4375 break;
4378 OSG::NodeRefPtr geomNode = OSG::makeNodeFor(geometry);
4380 OSG::TransformRefPtr trafoCore = OSG::Transform::create();
4381 OSG::NodeRefPtr transNode = OSG::makeNodeFor(trafoCore);
4382 transNode->addChild(geomNode);
4384 GeomState geom; geom.material_index = material_idx_die();
4385 OSG::ChunkMaterialRefPtr geomState = OSG::ChunkMaterial::create();
4386 OSG::MultiPropertyUBOChunkRefPtr uboGeomState = create_geometry_material_state(geom);
4387 geomState->addChunk(uboGeomState, geom_binding_point); // buffer binding point
4388 geomState->addChunk(shader_var_chunk); // block binding point
4390 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
4391 polygonChunk->setFrontMode(GL_SMOOTH);
4392 polygonChunk->setBackMode(GL_SMOOTH);
4393 polygonChunk->setOffsetFactor(1.f);
4394 polygonChunk->setOffsetBias(1.f);
4395 polygonChunk->setOffsetFill(true);
4397 OSG::Real32 opacity = materials[geom.material_index].opacity;
4398 if (opacity < 1.f)
4400 polygonChunk->setCullFace(GL_BACK);
4402 OSG::BlendChunkRefPtr blendChunk = OSG::BlendChunk::create();
4403 blendChunk->setSrcFactor (GL_SRC_ALPHA);
4404 blendChunk->setDestFactor(GL_ONE_MINUS_SRC_ALPHA);
4405 geomState->addChunk(blendChunk);
4406 geomState->setTransparencyMode(OSG::Material::TransparencyForceTransparent);
4408 OSG::TwoSidedLightingChunkRefPtr twoSidedLightingChunk = OSG::TwoSidedLightingChunk::create();
4409 geomState->addChunk(twoSidedLightingChunk);
4411 } else {
4412 polygonChunk->setCullFace(GL_BACK);
4413 geomState->setTransparencyMode(OSG::Material::TransparencyForceOpaque);
4416 geomState->addChunk(polygonChunk);
4418 geometry->setMaterial(geomState);
4420 geom_nodes.push_back(transNode);
4421 geom_trafos.push_back(trafoCore);
4422 ubo_geom_states.push_back(uboGeomState);
4424 geom_curves.push_back(SmoothCubicBezierSpline(dice_knots(true)));
4426 return OSG::NodeTransitPtr(transNode);
4430 // forward declaration so we can have the interesting stuff upfront
4432 int setupGLUT (int *argc, char *argv[]);
4433 void print_state();
4434 void print_help();
4435 void releaseGLUT();
4438 // Initialize GLUT & OpenSG and set up the scene
4440 int main(int argc, char **argv)
4442 // OSG init
4443 OSG::osgInit(argc,argv);
4445 // GLUT init
4446 int winid = setupGLUT(&argc, argv);
4448 print_help();
4450 // open a new scope, because the pointers below should go out of scope
4451 // before entering glutMainLoop.
4452 // Otherwise OpenSG will complain about objects being alive after shutdown.
4454 // the connection between GLUT and OpenSG
4455 OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
4456 gwin->setGlutId(winid);
4457 gwin->init();
4459 // create the SimpleSceneManager helper
4460 mgr = OSG::SimpleSceneManager::create();
4461 mgr->setWindow(gwin);
4463 TestData test_data;
4464 ssbo_test_data = create_test_data(test_data);
4466 VecFrustumsT vFrustums(1);
4468 ssbo_frustums = create_frustum_state(vFrustums);
4469 ssbo_frustums_cpu = create_frustum_state(vFrustums);
4471 light_grid_image = create_image(1,1,1, false);
4472 light_grid_image_cpu = create_image(1,1,1, true);
4474 light_grid_texture_object = create_texture_state(light_grid_image);
4475 light_grid_texture_object_cpu = create_texture_state(light_grid_image_cpu);
4477 light_grid_texture_image_cs = create_texture_image_state(light_grid_texture_object, GL_WRITE_ONLY);
4478 light_grid_texture_image_fs = create_texture_image_state(light_grid_texture_object, GL_READ_ONLY);
4479 light_grid_texture_image_cpu = create_texture_image_state(light_grid_texture_object_cpu, GL_READ_ONLY);
4481 ssbo_affected_light_index_list = create_index_state(1);
4482 ssbo_light_index_list = create_index_state(light_index_list_size);
4484 ubo_clustering_data = create_clustering_data(ClusteringData());
4487 // create the shader program
4489 OSG::ShaderProgramChunkRefPtr progChunk = OSG::ShaderProgramChunk::create();
4490 OSG::ShaderProgramRefPtr vertShader = OSG::ShaderProgram::createVertexShader();
4491 frag_shader = OSG::ShaderProgram::createFragmentShader();
4493 vertShader->setProgram(get_vp_program());
4494 frag_shader->setProgram(get_fp_program());
4496 frag_shader->addOSGVariable("OSGViewMatrix");
4499 // binding the shader storage block to a buffer binding point can be performed
4500 // either by calling the shaders's addShaderStorageBlock method or by
4501 // adding a 'buffer block' variable to a ShaderProgramVariableChunk.
4502 // In the following we use both variants for illustration.
4504 frag_shader->addShaderStorageBlock("Materials", material_binding_point);
4505 frag_shader->addShaderStorageBlock("Lights", light_binding_point);
4506 frag_shader->addShaderStorageBlock("AffectedLightIndexList", affected_light_index_binding_point);
4507 frag_shader->addShaderStorageBlock("LightIndexList", light_index_binding_point);
4508 frag_shader->addShaderStorageBlock("Frustums", frustum_binding_point);
4509 //frag_shader->addShaderStorageBlock("CPUFrustums", cpu_frustum_binding_point);
4510 //frag_shader->addShaderStorageBlock("TestData", test_data_binding_point);
4512 frag_shader->addUniformBlock ("ClusteringData", clustering_data_binding_point);
4516 // The following is replaced by adding ShaderProgramVariableChunk objects
4517 // to the chunk material. See below...
4519 // frag_shader->addShaderStorageBlock("GeomState", geom_binding_point);
4521 progChunk->addShader( vertShader);
4522 progChunk->addShader(frag_shader);
4525 // The block binding is added to each ChunkMaterial in order to provide the state
4526 // shader uniform block for the geometery shown in the scene
4528 shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
4529 shader_var_chunk->addUniformBlock("GeomState", geom_binding_point); // block binding point
4532 // The scene does contain all visible rendering. It will be append to the hdr node.
4534 scene_node = OSG::makeCoredNode<OSG::Group>();
4537 // Because we animate the lights by simple geometry, the lights initialization must be happens
4538 // after the creation of the 'shader_var_chunk' and after the creation of the scene node that
4539 // actually contains the geometry. Additionally, it must happens before we call 'create_light_state',
4540 // since here we do need the already defined lights.
4542 initialize_lights(init_num_lights);
4545 // create shader storage buffer objects and corresponding materials
4547 ssbo_material_database = create_material_database_state(materials);
4548 multi_light_chunk = create_light_state(lights);
4550 OSG::PolygonChunkRefPtr polygonChunk = OSG::PolygonChunk::create();
4551 polygonChunk->setFrontMode(GL_FILL);
4552 polygonChunk->setBackMode(GL_FILL);
4553 polygonChunk->setCullFace(GL_BACK);
4555 OSG::DepthChunkRefPtr depthChunk = OSG::DepthChunk::create();
4556 depthChunk->setEnable(true);
4558 OSG::ChunkMaterialRefPtr progState = OSG::ChunkMaterial::create();
4559 progState->addChunk(ssbo_material_database, material_binding_point);
4560 progState->addChunk(multi_light_chunk, light_binding_point);
4561 progState->addChunk(ssbo_affected_light_index_list, affected_light_index_binding_point);
4562 progState->addChunk(ssbo_light_index_list, light_index_binding_point);
4563 progState->addChunk(ssbo_frustums, frustum_binding_point);
4564 //progState->addChunk(ssbo_frustums_cpu, cpu_frustum_binding_point);
4565 progState->addChunk(ubo_clustering_data, clustering_data_binding_point);
4566 //progState->addChunk(ssbo_test_data, test_data_binding_point);
4567 progState->addChunk(light_grid_texture_image_fs, light_grid_binding_point);
4568 //progState->addChunk(light_grid_texture_image_cpu, cpu_light_grid_binding_point);
4570 progState->addChunk(progChunk);
4571 progState->addChunk(polygonChunk);
4572 progState->addChunk(depthChunk);
4575 // The scene graph
4577 compute_frustum_node = OSG::makeNodeFor(createFrustumComputation()); // OSG::Group::create());
4578 compute_light_culling_node = OSG::makeNodeFor(createLightCullingComputation()); // OSG::Group::create());
4579 hdr_node = OSG::makeCoredNode<OSG::Group>();
4581 mgr->setRoot(compute_frustum_node);
4583 if (use_ortho_camera)
4585 OSG::OrthographicCameraRefPtr orthoCamera = OSG::OrthographicCamera::create();
4586 mgr->setCamera(orthoCamera);
4589 compute_frustum_node ->addChild(compute_light_culling_node);
4590 compute_light_culling_node->addChild(hdr_node);
4591 hdr_node ->addChild(scene_node);
4593 createHDRStage();
4595 scene_node->addChild(createBox());
4597 cluster_geometry_root_node = OSG::makeCoredNode<OSG::Group>();
4598 scene_node->addChild(cluster_geometry_root_node);
4600 for (OSG::Int32 i = 0; i < init_num_geometries; ++i)
4601 scene_node->addChild(createGeometry());
4603 OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
4604 mgrp->setMaterial(progState);
4605 scene_node->setCore(mgrp);
4607 OSG::commitChanges();
4609 print_state();
4611 // show the whole scene
4612 mgr->showAll();
4615 // GLUT main loop
4616 glutMainLoop();
4618 return 0;
4622 // GLUT callback functions
4626 // redraw the window
4628 void display(void)
4630 if (!mgr) return;
4633 // Simulation code
4635 update_simulation();
4638 // Common data that is used below
4640 OSG::Real32 x_vp = mgr->getWindow()->getPort(0)->calcPixelLeft();
4641 OSG::Real32 y_vp = mgr->getWindow()->getPort(0)->calcPixelBottom();
4643 OSG::Real32 width = mgr->getWindow()->getPort(0)->calcPixelWidth();
4644 OSG::Real32 height = mgr->getWindow()->getPort(0)->calcPixelHeight();
4646 OSG::Real32 zNear = mgr->getCamera()->getNear();
4647 OSG::Real32 zFar = mgr->getCamera()->getFar ();
4649 OSG::UInt32 num_cluster_x = OSG::UInt32(OSG::osgCeil(width / tile_size));
4650 OSG::UInt32 num_cluster_y = OSG::UInt32(OSG::osgCeil(height / tile_size));
4652 OSG::Matrix matEyeFromWorld;
4653 mgr->getCamera()->getViewing(matEyeFromWorld, width, height);
4655 OSG::FrustumVolume viewVolume;
4656 mgr->getCamera()->getFrustum(viewVolume, width, height);
4658 OSG::Vec4u viewport(x_vp, y_vp, width, height);
4661 // Clear the CPU test data
4663 globalTestData.clear();
4666 // We have to update the view matrix for the light culling compute shader
4668 updateDispatchConfigCullLights(viewport, matEyeFromWorld);
4671 // We determine an index list of all lights that are actually contributing to the
4672 // shading of the complete visible view frustum.
4674 VecLightIndexT vecAffectedLights;
4676 calcAffectedLights(
4677 lights, // in light list
4678 matEyeFromWorld, // in transform from world to eye space
4679 viewVolume, // in the view frustum volume in world space
4680 vecAffectedLights); // out the index list
4682 update_index_state(ssbo_affected_light_index_list, vecAffectedLights);
4685 // We clear the global light index list. This, however is strictly not
4686 // necessary and we do it currently for security reasons.
4688 // ToDo: Must work without clearing of the global light index list
4690 //clear_index_state(ssbo_light_index_list, light_index_list_size);
4693 // Clearing of the global light index counter is necessary!
4695 clear_light_index_counter_state(ssbo_light_index_counter);
4698 // Classic light culling only for testing. The real culling is performed in a
4699 // compute shader, but that result can be tested against the result of this classic
4700 // culling in the fragment shader.
4702 //if (Light::cpu_cull_lights)
4704 // OSG::Vec4u viewport(x_vp, y_vp, width, height);
4705 // fill_test_data_light_grid_image(viewport, light_grid_image_cpu);
4707 // update_texture_state(light_grid_texture_object_cpu);
4709 // Light::cpu_cull_lights = false;
4712 if (Light::cpu_cull_lights)
4715 // These are the results of the light culling procedure below. We will fill these
4716 // raw data into appropriate SSBO so that they are available in the fragment shader
4717 // for evaluation.
4719 VecImageDataT gridData; // tuples of offset and cound integers: { o1,c1, o2,c2, o3,c3,...}
4720 VecLightIndexT lightIndexList; // pointers into the lights array.
4722 OSG::Vec3u dimensions(num_cluster_x, num_cluster_y, num_cluster_z);
4724 cullLights(
4725 lights, // in light list
4726 vecAffectedLights, // in the lights that are actually contributing to the view frustum shading
4727 frustums_cpu, // in frustums list
4728 dimensions, // in cluster dimensions
4729 matEyeFromWorld, // in transform from world to eye space
4730 zNear, // in distance of near plane from eye point
4731 zFar, // in distance of far plane from eye point
4732 near_plane_offset, // in distance offset for near plane
4733 gridData, // out the raw grid data
4734 lightIndexList); // out the index list
4737 // Fill gridData to image and inform texture object about change
4739 update_image_data(light_grid_image_cpu, gridData);
4740 update_texture_state(light_grid_texture_object_cpu);
4743 // Fill lightIndexList to SSBO:
4745 // This is only to be used if the light culling compute shader is not used, because the very same
4746 // shader storage buffer is filled. The update_index_state, however, does resize the buffer which
4747 // could yield in memory access problems in the compute shader. In the final implementation the
4748 // it should be possible to switch between usage of compute shaders and a CPU based code path.
4750 // For testing it is not possible to compare the compute shaders and CPU based generated light
4751 // index lists, because of the parallel computations that are performed which always generate
4752 // differing sortings of the list.
4754 // update_index_state(ssbo_light_index_list, lightIndexList);
4758 // Update the clustering data used in the light cull and fragment shader
4760 ClusteringData clusteringData;
4761 clusteringData.zNear = zNear; // positive near plane distance from eye zNear > 0
4762 clusteringData.zFar = zFar; // positive far plane distance from eye zFar > zNear > 0
4763 //clusteringData.D = near_plane_offset; // positive near plane offset D >= 0
4764 clusteringData.nD = zNear + near_plane_offset; // zNear + D : shader optimization
4765 clusteringData.lg_nD = log2(clusteringData.nD); // log2(nD) : shader optimization
4766 clusteringData.a = (num_cluster_z-1)/log2(zFar/clusteringData.nD); // precalculated factor (c-1)/log2(f/(n+D))
4767 clusteringData.b = 1.f/clusteringData.a; // precalculated factor log2(f/(n+D))/(c-1)
4768 //clusteringData.c = num_cluster_z; // number of cluster planes
4769 clusteringData.c_1 = num_cluster_z - 1; // number of cluster planes minus one : shader optimization
4770 clusteringData.p_v = OSG::Vec2i(x_vp, y_vp); // viewport corner points
4771 //clusteringData.n_c = OSG::Vec3i(num_cluster_x, num_cluster_y, num_cluster_z); // number of clusters
4773 if (Light::use_light_index_list)
4774 clusteringData.t_v = 0; // test dependent content
4775 else
4776 clusteringData.t_v = 1; // test dependent content
4778 update_clustering_data(ubo_clustering_data, clusteringData);
4780 //update_test_data(ssbo_test_data, globalTestData);
4782 OSG::commitChanges();
4784 mgr->redraw();
4788 // react to size changes
4790 void reshape(int w, int h)
4792 mgr->resize(w, h);
4793 mgr->update();
4795 OSG::Real32 x_vp = mgr->getWindow()->getPort(0)->calcPixelLeft();
4796 OSG::Real32 y_vp = mgr->getWindow()->getPort(0)->calcPixelBottom();
4798 OSG::Real32 width = mgr->getWindow()->getPort(0)->calcPixelWidth();
4799 OSG::Real32 height = mgr->getWindow()->getPort(0)->calcPixelHeight();
4801 OSG::Real32 zNear = mgr->getCamera()->getNear();
4802 OSG::Real32 zFar = mgr->getCamera()->getFar ();
4804 OSG_ASSERT(w == width);
4805 OSG_ASSERT(h == height);
4807 OSG::Matrix matProjection, matInverseProjection, matProjectionTranslation, matEyeFromWorld;
4809 mgr->getCamera()->getProjection (matProjection, width, height);
4810 mgr->getCamera()->getProjectionTranslation(matProjectionTranslation, width, height);
4811 mgr->getCamera()->getViewing (matEyeFromWorld, width, height);
4813 matProjection.mult(matProjectionTranslation);
4814 matProjection.inverse(matInverseProjection);
4816 OSG::Vec4u viewport(x_vp, y_vp, width, height);
4819 // First, CPU clustering
4823 // resize the cpu light grid image and allocate appropriate memory
4825 update_light_grid_image(viewport, light_grid_image_cpu, true);
4828 // Currently we fill pseudo data into the image to test if they are
4829 // available in the fragment shader on the GPU.
4831 //fill_test_data_light_grid_image(viewport, light_grid_image_cpu);
4834 // The image content has changed and we have to inform the texture object
4835 // so that the new content is available in the shader.
4837 // To be removed, I have read that the image size change is tracked by another route
4839 update_texture_state(light_grid_texture_object_cpu);
4842 // That is at the heard of things: the actual cpu frustum generation process.
4844 if (isOrthographicCamera(mgr->getCamera(), width, height))
4845 calc_ortho_frustums_cpu(viewport, matInverseProjection, frustums_cpu);
4846 else
4847 calc_persp_frustums_cpu(viewport, matInverseProjection, frustums_cpu);
4850 // The following function generates geometry for the current tile frustums (not the clusters).
4852 visualize_frustum_cpu(matEyeFromWorld, frustums_cpu, zNear, zFar);
4855 // In order to check the cpu vs. the gpu generated frustums we make them available in the
4856 // fragment shader. The following function loads the cpu frustums into a SSBO that is
4857 // binded to the fragment shader.
4859 update_frustum_state(ssbo_frustums_cpu, frustums_cpu);
4863 // Second, GPU clustering
4867 // The light grid image size must be adapted. But no CPU memory is needed!
4869 update_light_grid_image(viewport, light_grid_image, false);
4872 // The tile frustums are calculated on the GPU by a compute shader. This is done
4873 // on the rendering pass due to the AlgorithmComputeElement in the scene graph.
4875 // ToDo: Not each render pass should recompute the frustums, but only one after
4876 // the window resize.
4878 // Addidionally, a second compute shader performs the light culling on the GPU.
4879 // This is also performed in the rendering pass due to a second AlgorithmCompute-
4880 // Element core in the scene graph.
4882 // Both computations are goverend by their respective dispatch configurations. The
4883 // following call does setup these two configurations appropriately.
4885 // Also the GPU frustum SSBO must be resized and the DispatchData uniform buffer
4886 // object taking the viewport, the inverse projection and the number of tiles
4887 // must be updated. These task are also hidden in the next function call.
4889 updateDispatchConfigFrustums (viewport, matInverseProjection);
4890 updateDispatchConfigCullLights(viewport, matEyeFromWorld);
4894 // Cluster coordinate test
4896 cluster_test(zNear, zFar);
4898 glutPostRedisplay();
4902 // react to mouse button presses
4904 void mouse(int button, int state, int x, int y)
4906 if (state)
4907 mgr->mouseButtonRelease(button, x, y);
4908 else
4909 mgr->mouseButtonPress(button, x, y);
4911 glutPostRedisplay();
4915 // react to mouse motions with pressed buttons
4917 void motion(int x, int y)
4919 mgr->mouseMove(x, y);
4920 glutPostRedisplay();
4924 // react to keys
4926 void keyboard(unsigned char k, int x, int y)
4928 switch(k)
4930 case 27: // ESC
4932 // clean up global variables
4933 mgr = NULL;
4935 frag_shader = NULL;
4937 scene_node = NULL;
4938 cluster_geometry_root_node = NULL;
4940 compute_frustum_node = NULL;
4941 compute_frustum_shader = NULL;
4942 compute_frustum_shader_algorithm = NULL;
4944 compute_light_culling_node = NULL;
4945 compute_light_culling_shader = NULL;
4946 compute_light_culling_shader_algorithm = NULL;
4948 hdr_stage = NULL;
4949 hdr_node = NULL;
4951 ubo_frustum_dispatch_data = NULL;
4952 ubo_light_culling_dispatch_data = NULL;
4953 ubo_clustering_data = NULL;
4955 ssbo_material_database = NULL;
4956 ssbo_frustums = NULL;
4957 ssbo_frustums_cpu = NULL;
4958 ssbo_affected_light_index_list = NULL;
4959 ssbo_light_index_counter = NULL;
4960 ssbo_light_index_list = NULL;
4962 ssbo_test_data = NULL;
4964 light_grid_image = NULL;
4965 light_grid_image_cpu = NULL;
4967 light_grid_texture_object = NULL;
4968 light_grid_texture_object_cpu = NULL;
4970 light_grid_texture_image_cs = NULL;
4971 light_grid_texture_image_fs = NULL;
4972 light_grid_texture_image_cpu = NULL;
4974 multi_light_chunk = NULL;
4975 shader_var_chunk = NULL;
4977 geom_nodes.clear();
4978 geom_trafos.clear();
4979 geom_curves.clear();
4981 ubo_geom_states.clear();
4983 materials.clear();
4984 lights.clear();
4986 releaseGLUT();
4988 OSG::osgExit();
4989 exit(0);
4991 break;
4993 case 32: // Space
4995 simulate_geometry = !simulate_geometry;
4996 std::cout << "simulate_geometry = " << simulate_geometry << std::endl;
4998 break;
5000 case '1':
5002 initialize_lights(1);
5003 update_light_state(multi_light_chunk, lights);
5004 update_material_database_state(ssbo_material_database, materials);
5005 glutPostRedisplay();
5007 break;
5009 case '2':
5011 if (lights.size() > 1)
5013 OSG::UInt32 num = static_cast<OSG::UInt32>(lights.size() / 2);
5014 initialize_lights(num);
5015 update_light_state(multi_light_chunk, lights);
5016 update_material_database_state(ssbo_material_database, materials);
5018 std::cout << "number if lights = " << num << std::endl;
5020 glutPostRedisplay();
5022 else
5024 std::cout << "minimal number if lights reached!" << std::endl;
5027 break;
5029 case '3':
5031 if (lights.size() <= max_num_lights)
5033 OSG::UInt32 num = static_cast<OSG::UInt32>(lights.size() * 2);
5034 initialize_lights(num);
5035 update_light_state(multi_light_chunk, lights);
5036 update_material_database_state(ssbo_material_database, materials);
5038 std::cout << "number if lights = " << num << std::endl;
5040 glutPostRedisplay();
5042 else
5044 std::cout << "maximal number if lights reached!" << std::endl;
5048 break;
5050 case '4':
5052 if (geom_nodes.size() > 1)
5054 OSG::UInt32 num = static_cast<OSG::UInt32>(geom_nodes.size() / 2);
5056 BOOST_FOREACH(OSG::Node* node, geom_nodes)
5057 scene_node->subChild(node);
5059 geom_nodes.clear();
5060 geom_trafos.clear();
5061 geom_curves.clear();
5062 ubo_geom_states.clear();
5064 for (OSG::UInt32 i = 0; i < num; ++i)
5065 scene_node->addChild(createGeometry());
5067 std::cout << "number if geometries = " << num << std::endl;
5069 glutPostRedisplay();
5071 else
5073 std::cout << "minimal number if geometries reached!" << std::endl;
5076 break;
5078 case '5':
5080 if (geom_nodes.size() <= max_num_geometries)
5082 OSG::UInt32 num = static_cast<OSG::UInt32>(geom_nodes.size() * 2);
5084 BOOST_FOREACH(OSG::Node* node, geom_nodes)
5085 scene_node->subChild(node);
5087 geom_nodes.clear();
5088 geom_trafos.clear();
5089 geom_curves.clear();
5090 ubo_geom_states.clear();
5092 for (OSG::UInt32 i = 0; i < num; ++i)
5093 scene_node->addChild(createGeometry());
5095 std::cout << "number if geometries = " << num << std::endl;
5097 glutPostRedisplay();
5099 else
5101 std::cout << "maximal number if geometries reached!" << std::endl;
5104 break;
5106 case 'a':
5108 Light::add_dir_test_lights = !Light::add_dir_test_lights;
5109 std::cout << "Light::add_dir_test_lights = " << Light::add_dir_test_lights << std::endl;
5111 initialize_lights(1);
5112 update_light_state(multi_light_chunk, lights);
5113 update_material_database_state(ssbo_material_database, materials);
5114 glutPostRedisplay();
5116 break;
5118 case 'b':
5120 Light::correct_light_geometry = !Light::correct_light_geometry;
5121 std::cout << "Light::correct_light_geometry = " << Light::correct_light_geometry << std::endl;
5123 for (std::size_t i = 0; i < lights.size(); ++i)
5125 Light& light = lights[i];
5126 light.create_light_geometry(OSG::UInt32(i+1));
5129 glutPostRedisplay();
5131 break;
5133 case 'c':
5135 Light::cpu_cull_lights = !Light::cpu_cull_lights;
5136 std::cout << "Light::cpu_cull_lights = " << Light::cpu_cull_lights << std::endl;
5138 break;
5140 case 'e':
5142 simulation_delta *= 2.f;
5144 break;
5146 case 'E':
5148 simulation_delta /= 2.f;
5150 break;
5152 case 'h':
5154 OSG::HDR2Stage* core = dynamic_cast<OSG::HDR2Stage*>(hdr_node->getCore());
5155 if (core)
5157 removeHDRStage();
5159 std::cout << "HDR is off" << std::endl;
5161 else
5163 createHDRStage();
5165 std::cout << "HDR is on" << std::endl;
5168 glutPostRedisplay();
5170 break;
5172 case 'i':
5174 BOOST_FOREACH(Light& light, lights)
5175 light.intensity *= 1.2f;
5177 update_light_state(multi_light_chunk, lights);
5178 glutPostRedisplay();
5180 break;
5182 case 'I':
5184 BOOST_FOREACH(Light& light, lights)
5185 if (light.range / intensityFactor >= OSG::Eps)
5186 light.intensity /= intensityFactor;
5188 update_light_state(multi_light_chunk, lights);
5189 glutPostRedisplay();
5191 break;
5193 case 'l':
5195 simulate_lights = !simulate_lights;
5196 std::cout << "simulate_lights = " << simulate_lights << std::endl;
5198 break;
5200 case 'm':
5202 BOOST_FOREACH(OSG::MultiPropertyUBOChunk* uboGeomState, ubo_geom_states)
5204 GeomState geom; geom.material_index = material_idx_die();
5205 update_geometry_material_state(uboGeomState, geom);
5208 glutPostRedisplay();
5210 break;
5212 case 'o':
5214 elapse_time_limit *= 2.f;
5216 break;
5218 case 'O':
5220 elapse_time_limit /= 2.f;
5222 break;
5224 case 'p':
5226 for (std::size_t i = 0; i < lights.size(); ++i)
5228 Light& light = lights[i];
5230 light.range *= rangeFactor;
5231 light.create_light_geometry(OSG::UInt32(i+1));
5234 update_light_state(multi_light_chunk, lights);
5235 glutPostRedisplay();
5237 break;
5239 case 'P':
5241 for (std::size_t i = 0; i < lights.size(); ++i)
5243 Light& light = lights[i];
5245 if (light.range / rangeFactor >= OSG::Eps)
5247 light.range /= rangeFactor;
5248 light.create_light_geometry(OSG::UInt32(i+1));
5252 update_light_state(multi_light_chunk, lights);
5253 glutPostRedisplay();
5255 break;
5257 case 'r':
5259 initialize_lights(init_num_lights);
5260 update_light_state(multi_light_chunk, lights);
5261 update_material_database_state(ssbo_material_database, materials);
5263 simulation_delta = 0.0001f;
5264 elapse_time_limit = 10.f;
5266 simulate_geometry = true;
5267 simulate_lights = true;
5269 std::cout << "example resetted" << std::endl;
5271 glutPostRedisplay();
5273 break;
5275 case 's':
5277 mgr->setStatistics(!mgr->getStatistics());
5279 break;
5281 case 't':
5283 Light::use_light_index_list = !Light::use_light_index_list;
5284 std::cout << "Light::use_light_index_list = " << Light::use_light_index_list << std::endl;
5286 break;
5288 case 'u':
5290 Light::show_spot_dir_line = !Light::show_spot_dir_line;
5291 std::cout << "Light::show_spot_dir_line = " << Light::show_spot_dir_line << std::endl;
5293 for (std::size_t i = 0; i < lights.size(); ++i)
5295 Light& light = lights[i];
5296 light.create_light_geometry(OSG::UInt32(i+1));
5299 glutPostRedisplay();
5301 break;
5303 case 'U':
5305 Light::force_spot_dir += 1;
5306 if (Light::force_spot_dir > 9)
5307 Light::force_spot_dir = 0;
5309 std::cout << "Light::force_spot_dir = ";
5311 switch (Light::force_spot_dir)
5313 case 0: std::cout << "dice"; break;
5314 case 1: std::cout << "(0, 0,-1)"; break;
5315 case 2: std::cout << "(1, 0, 0)"; break;
5316 case 3: std::cout << "(0,-1, 0)"; break;
5317 case 4: std::cout << "(1, 0,-1)"; break;
5318 case 5: std::cout << "(1,-1,-1)"; break;
5319 case 6: std::cout << "from (0,0,-1) to (1,0,-1)"; break;
5320 case 7: std::cout << "from (0,0,-1) to (1,-1,-1)"; break;
5321 case 8: std::cout << "from (0,0,-1) to (0,-1, 0)"; break;
5322 case 9: std::cout << "recreate"; break;
5325 std::cout << std::endl;
5327 break;
5329 case 'v':
5331 Frustum::visualize = !Frustum::visualize;
5332 std::cout << "Frustum::visualize = " << Frustum::visualize << std::endl;
5334 OSG::Real32 w = mgr->getWindow()->getPort(0)->calcPixelWidth();
5335 OSG::Real32 h = mgr->getWindow()->getPort(0)->calcPixelHeight();
5337 OSG::Real32 zNear = mgr->getCamera()->getNear();
5338 OSG::Real32 zFar = mgr->getCamera()->getFar ();
5340 visualize_frustum_cpu(mgr->getCamera()->getViewingVal(w, h), frustums_cpu, zNear, zFar);
5342 break;
5344 case 'x':
5346 change_spot_dir_lights();
5347 update_light_state(multi_light_chunk, lights);
5348 update_material_database_state(ssbo_material_database, materials);
5349 glutPostRedisplay();
5351 break;
5357 // setup the GLUT library which handles the windows for us
5359 int setupGLUT(int *argc, char *argv[])
5361 glutInit(argc, argv);
5362 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
5363 glutInitWindowSize(1000, 800);
5365 int winid = glutCreateWindow("OpenSG");
5367 glutReshapeFunc(reshape);
5368 glutDisplayFunc(display);
5369 glutMouseFunc(mouse);
5370 glutMotionFunc(motion);
5371 glutKeyboardFunc(keyboard);
5373 // call the redraw function whenever there's nothing else to do
5374 glutIdleFunc(display);
5376 return winid;
5379 void releaseGLUT()
5381 glutReshapeFunc(NULL);
5382 glutMouseFunc(NULL);
5383 glutMotionFunc(NULL);
5384 glutKeyboardFunc(NULL);
5385 glutIdleFunc(NULL);
5388 void print_state()
5390 std::cout << "simulate_geometry = " << simulate_geometry << std::endl;
5391 std::cout << "simulate_lights = " << simulate_lights << std::endl;
5392 std::cout << "number if lights = " << lights.size() << std::endl;
5393 std::cout << "number if geometries = " << geom_nodes.size() << std::endl;
5394 std::cout << "Light::use_light_index_list = " << Light::use_light_index_list << std::endl;
5395 std::cout << "Light::add_dir_test_lights = " << Light::add_dir_test_lights << std::endl;
5396 std::cout << "Light::correct_light_geometry = " << Light::correct_light_geometry << std::endl;
5397 std::cout << "Light::show_spot_dir_line = " << Light::show_spot_dir_line << std::endl;
5398 std::cout << "Light::cpu_cull_lights = " << Light::cpu_cull_lights << std::endl;
5399 std::cout << "HDR is " << (dynamic_cast<OSG::HDR2Stage*>(hdr_node->getCore()) != NULL ? "on" : "off") << std::endl;
5400 std::cout << "Frustum::visualize = " << Frustum::visualize << std::endl;
5403 void print_help()
5405 std::cout << "Esc : quit example" << std::endl;
5406 std::cout << "Space : toogle geometry simulation on/off" << std::endl;
5407 std::cout << "1 : only one light" << std::endl;
5408 std::cout << "2 : half number of lights" << std::endl;
5409 std::cout << "3 : double number of lights" << std::endl;
5410 std::cout << "4 : half number of geometry objects" << std::endl;
5411 std::cout << "5 : double number of geometry objects" << std::endl;
5412 std::cout << "a : add directional test lights" << std::endl;
5413 std::cout << "b : show correct light geometry" << std::endl;
5414 std::cout << "c : cull lights on cpu" << std::endl;
5415 std::cout << "e/E : speed up/down simulation" << std::endl;
5416 std::cout << "h : toogle HDR stage usage on/off" << std::endl;
5417 std::cout << "i/I : increase/decrease light intensity" << std::endl;
5418 std::cout << "l : toogle light simulation on/off" << std::endl;
5419 std::cout << "m : assign new color to geometry" << std::endl;
5420 std::cout << "o/O : double/half simulation time interval" << std::endl;
5421 std::cout << "p/P : increase/decrease light range" << std::endl;
5422 std::cout << "r : reset the example" << std::endl;
5423 std::cout << "s : toogle statistics on/off" << std::endl;
5424 std::cout << "t : toogle usage of cluster shading on/off" << std::endl;
5425 std::cout << "u : toggle spot direction line on/off" << std::endl;
5426 std::cout << "U : toggle special spot direction cases" << std::endl;
5427 std::cout << "v : toogle frustum visualization on/off" << std::endl;
5428 std::cout << "x : recreate the lights with current spot dir case" << std::endl;
5431 // ============================================================================
5433 // Part: Cubic Bezier spline curve implementation
5435 // ============================================================================
5437 CubicBezierCurve::CubicBezierCurve(
5438 const OSG::Pnt3f& p0,
5439 const OSG::Pnt3f& p1,
5440 const OSG::Pnt3f& p2,
5441 const OSG::Pnt3f& p3)
5443 p[0] = p0; p[1] = p1; p[2] = p2; p[3] = p3;
5446 CubicBezierCurve::CubicBezierCurve(const CubicBezierCurve& rhs)
5448 p[0] = rhs.p[0]; p[1] = rhs.p[1]; p[2] = rhs.p[2]; p[3] = rhs.p[3];
5451 CubicBezierCurve& CubicBezierCurve::operator=(const CubicBezierCurve& rhs)
5453 if (this != &rhs)
5455 p[0] = rhs.p[0]; p[1] = rhs.p[1]; p[2] = rhs.p[2]; p[3] = rhs.p[3];
5457 return *this;
5460 OSG::Pnt3f CubicBezierCurve::operator()(OSG::Real32 t) const
5462 OSG_ASSERT(0.f <= t && t <= 1.f);
5464 OSG::Real32 e = 1.f - t;
5465 OSG::Real32 sq_e = e * e;
5466 OSG::Real32 sq_t = t * t;
5468 return e * sq_e * p[0]
5469 + 3.f * t * sq_e * p[1].subZero()
5470 + 3.f * sq_t * e * p[2].subZero()
5471 + t * sq_t * p[3].subZero();
5474 OSG::Vec3f CubicBezierCurve::tangent(OSG::Real32 t) const
5476 OSG::Vec3f tangent = fst_derivative(t);
5477 tangent.normalize();
5479 return tangent;
5482 OSG::Vec3f CubicBezierCurve::normal(OSG::Real32 t) const
5484 OSG::Vec3f normal = binormal(t);
5485 normal.crossThis(tangent(t));
5486 normal.normalize();
5488 return normal;
5491 OSG::Vec3f CubicBezierCurve::binormal(OSG::Real32 t) const
5493 OSG::Vec3f binormal = fst_derivative(t);
5494 binormal.crossThis(sec_derivative(t));
5495 binormal.normalize();
5497 while (OSG::osgAbs(binormal.length() - 1.f) >= OSG::Eps)
5499 if (t + OSG::Eps <= 1.f)
5500 t += OSG::Eps;
5501 else if (t - OSG::Eps >= 0.f)
5502 t -= OSG::Eps;
5503 else
5504 OSG_ASSERT(false);
5506 binormal = fst_derivative(t);
5507 binormal.crossThis(sec_derivative(t));
5508 binormal.normalize();
5511 return binormal;
5514 OSG::Matrix CubicBezierCurve::frame(OSG::Real32 t, bool position_only) const
5516 OSG::Matrix mat;
5517 mat.identity();
5519 OSG::Vec3f P = (*this)(t).subZero();
5521 if (position_only)
5523 mat.setTranslate(P);
5525 else
5527 OSG::Vec3f T = tangent(t);
5528 OSG::Vec3f N = normal(t);
5529 OSG::Vec3f B = binormal(t);
5532 OSG::Real32 lT = T.length();
5533 OSG::Real32 lN = N.length();
5534 OSG::Real32 lB = B.length();
5536 OSG::Real32 v1 = T.dot(N);
5537 OSG::Real32 v2 = T.dot(B);
5538 OSG::Real32 v3 = N.dot(B);
5540 OSG_ASSERT(OSG::osgAbs(T.length() - 1.f) < OSG::Eps);
5541 OSG_ASSERT(OSG::osgAbs(N.length() - 1.f) < OSG::Eps);
5542 OSG_ASSERT(OSG::osgAbs(B.length() - 1.f) < OSG::Eps);
5544 mat.setValue(T,N,B,P);
5547 return mat;
5550 OSG::Real32 CubicBezierCurve::length(OSG::UInt32 numSeg) const
5552 OSG_ASSERT(numSeg >= 2);
5554 OSG::Real32 d = 1.f / numSeg;
5555 OSG::Real32 t = d;
5556 OSG::Real32 l = 0.f;
5558 OSG::Pnt3f p0 = operator()(0.f);
5560 while (t <= 1.f)
5562 OSG::Pnt3f p1 = operator()(t);
5564 l += (p1 - p0).length();
5565 t += d;
5568 return l;
5571 OSG::Vec3f CubicBezierCurve::fst_derivative(OSG::Real32 t) const
5573 OSG::Vec3f v10 = p[1] - p[0];
5574 OSG::Vec3f v21 = p[2] - p[1];
5575 OSG::Vec3f v32 = p[3] - p[2];
5577 OSG::Real32 e = 1.f - t;
5578 OSG::Real32 sq_e = e * e;
5579 OSG::Real32 sq_t = t * t;
5581 return 3.f * sq_e * v10 + 6.f * e * t * v21 + 3.f * sq_t * v32;
5584 OSG::Vec3f CubicBezierCurve::sec_derivative(OSG::Real32 t) const
5586 OSG::Vec3f v210 = p[2] - 2.f * p[1] + p[0].subZero();
5587 OSG::Vec3f v321 = p[3] - 2.f * p[2] + p[1].subZero();
5589 OSG::Real32 e = 1.f - t;
5591 return 6.f * e * v210 + 6.f * t * v321;
5594 OSG::Vec3f CubicBezierCurve::thr_devivative(OSG::Real32 t) const
5596 OSG::Vec3f v21 = p[2] - p[1];
5597 OSG::Vec3f v30 = p[3] - p[0];
5599 return -18.f * v21 + 6.f * v30;
5603 SmoothCubicBezierSpline::SmoothCubicBezierSpline(const std::vector<OSG::Pnt3f>& knots)
5604 : knots(knots)
5606 OSG_ASSERT(knots.size() > 3);
5608 points_t p1, p2;
5610 calc_ctrl_pnts(p1, p2);
5612 std::size_t n = knots.size() - 1;
5614 std::vector<OSG::Real32> lengths(n);
5615 OSG::Real32 L = 0.f;
5617 for (std::size_t i = 0; i < n; ++i)
5619 curves.push_back(CubicBezierCurve(knots[i], p1[i], p2[i], knots[i+1]));
5621 lengths[i] = curves[i].length();
5622 L += lengths[i];
5625 OSG_ASSERT(L > 0.f);
5627 OSG::Real32 d = 1.f / L;
5629 intervals.resize(n);
5631 intervals[0] = d * lengths[0];
5633 for (std::size_t i = 1; i < n-1; ++i)
5635 intervals[i] = intervals[i-1] + d * lengths[i];
5638 intervals[n-1] = 1.f;
5641 SmoothCubicBezierSpline::SmoothCubicBezierSpline(const SmoothCubicBezierSpline& rhs)
5642 : knots(rhs.knots)
5643 , intervals(rhs.intervals)
5644 , curves(rhs.curves)
5648 SmoothCubicBezierSpline& SmoothCubicBezierSpline::operator=(const SmoothCubicBezierSpline& rhs)
5650 if (this != &rhs)
5652 knots = rhs.knots;
5653 intervals = rhs.intervals;
5654 curves = rhs.curves;
5656 return *this;
5659 OSG::Pnt3f SmoothCubicBezierSpline::operator()(OSG::Real32 t) const
5661 std::size_t idx = index(t);
5662 return curves[idx](t_(t, idx));
5665 OSG::Vec3f SmoothCubicBezierSpline::tangent(OSG::Real32 t) const
5667 std::size_t idx = index(t);
5668 return curves[idx].tangent(t_(t, idx));
5671 OSG::Vec3f SmoothCubicBezierSpline::normal(OSG::Real32 t) const
5673 std::size_t idx = index(t);
5674 return curves[idx].normal(t_(t, idx));
5677 OSG::Vec3f SmoothCubicBezierSpline::binormal(OSG::Real32 t) const
5679 std::size_t idx = index(t);
5680 return curves[idx].binormal(t_(t, idx));
5683 OSG::Matrix SmoothCubicBezierSpline::frame(OSG::Real32 t, bool position_only) const
5685 std::size_t idx = index(t);
5686 return curves[idx].frame(t_(t, idx), position_only);
5689 OSG::Real32 SmoothCubicBezierSpline::length(OSG::UInt32 numSeg) const
5691 OSG::Real32 l = 0.f;
5692 BOOST_FOREACH(const CubicBezierCurve& c, curves)
5694 l += c.length(numSeg);
5696 return l;
5699 void SmoothCubicBezierSpline::calc_ctrl_pnts(points_t& p1, points_t& p2) const
5701 namespace tp = boost::tuples;
5702 typedef tp::tuple<OSG::Real32, OSG::Real32, OSG::Real32> tuple_t;
5703 typedef std::vector<tuple_t> tuples_t;
5705 std::size_t n = knots.size()-1;
5707 p1.resize(n);
5708 p2.resize(n);
5710 tuples_t a(n), b(n), c(n), d(n);
5712 a[0] = tp::make_tuple(0.f, 0.f, 0.f);
5713 b[0] = tp::make_tuple(2.f, 2.f, 2.f);
5714 c[0] = tp::make_tuple(1.f, 1.f, 1.f);
5715 d[0] = tp::make_tuple(
5716 knots[0].x() + 2.f * knots[1].x(),
5717 knots[0].y() + 2.f * knots[1].y(),
5718 knots[0].z() + 2.f * knots[1].z());
5720 for (std::size_t i = 1; i < n-1; ++i)
5722 a[i] = tp::make_tuple(1.f, 1.f, 1.f);
5723 b[i] = tp::make_tuple(4.f, 4.f, 4.f);
5724 c[i] = tp::make_tuple(1.f, 1.f, 1.f);
5725 d[i] = tp::make_tuple(
5726 4.f * knots[i].x() + 2.f * knots[i+1].x(),
5727 4.f * knots[i].y() + 2.f * knots[i+1].y(),
5728 4.f * knots[i].z() + 2.f * knots[i+1].z());
5731 a[n-1] = tp::make_tuple(2.f, 2.f, 2.f);
5732 b[n-1] = tp::make_tuple(7.f, 7.f, 7.f);
5733 c[n-1] = tp::make_tuple(0.f, 0.f, 0.f);
5734 d[n-1] = tp::make_tuple(
5735 8.f * knots[n-1].x() + 2.f * knots[n].x(),
5736 8.f * knots[n-1].y() + 2.f * knots[n].y(),
5737 8.f * knots[n-1].z() + 2.f * knots[n].z());
5739 for (std::size_t i = 1; i < n; ++i)
5741 tuple_t m = tp::make_tuple(
5742 a[i].get<0>() / b[i-1].get<0>(),
5743 a[i].get<1>() / b[i-1].get<1>(),
5744 a[i].get<2>() / b[i-1].get<2>());
5746 b[i] = tp::make_tuple(
5747 b[i].get<0>() - m.get<0>() * c[i-1].get<0>(),
5748 b[i].get<1>() - m.get<1>() * c[i-1].get<1>(),
5749 b[i].get<2>() - m.get<2>() * c[i-1].get<2>());
5751 d[i] = tp::make_tuple(
5752 d[i].get<0>() - m.get<0>() * d[i-1].get<0>(),
5753 d[i].get<1>() - m.get<1>() * d[i-1].get<1>(),
5754 d[i].get<2>() - m.get<2>() * d[i-1].get<2>());
5757 p1[n-1].setValues(
5758 d[n-1].get<0>() / b[n-1].get<0>(),
5759 d[n-1].get<1>() / b[n-1].get<1>(),
5760 d[n-1].get<2>() / b[n-1].get<2>());
5762 for (long long i = n-2; i >= 0; --i)
5764 p1[i].setValues(
5765 (d[i].get<0>() - c[i].get<0>() * p1[i+1].x()) / b[i].get<0>(),
5766 (d[i].get<1>() - c[i].get<1>() * p1[i+1].y()) / b[i].get<1>(),
5767 (d[i].get<2>() - c[i].get<2>() * p1[i+1].z()) / b[i].get<2>());
5770 for (std::size_t i = 0; i < n-1; ++i)
5772 p2[i].setValues(
5773 2.f * knots[i+1].x() - p1[i+1].x(),
5774 2.f * knots[i+1].y() - p1[i+1].y(),
5775 2.f * knots[i+1].z() - p1[i+1].z());
5778 p2[n-1].setValues(
5779 0.5f * knots[n].x() - p1[n-1].x(),
5780 0.5f * knots[n].y() - p1[n-1].y(),
5781 0.5f * knots[n].z() - p1[n-1].z());
5784 std::size_t SmoothCubicBezierSpline::index(OSG::Real32 t) const
5786 OSG_ASSERT(0.f <= t && t <= 1.f);
5788 std::vector<OSG::Real32>::const_iterator iter = std::lower_bound(intervals.begin(), intervals.end(), t);
5789 std::size_t r = iter - intervals.begin();
5790 return r;
5793 OSG::Real32 SmoothCubicBezierSpline::t_(OSG::Real32 t, std::size_t idx) const
5795 OSG_ASSERT(idx < intervals.size());
5797 OSG::Real32 t0 = 0.f;
5798 OSG::Real32 t1 = 1.f;
5800 if (idx > 0) t0 = intervals[idx-1];
5801 t1 = intervals[idx];
5803 OSG::Real32 r = (t - t0) / (t1 - t0);
5805 return r;
5808 // ============================================================================
5810 // Part: dice_knots helper implementation
5812 // ============================================================================
5814 typedef boost::tuples::tuple<int, int, int> index_t;
5816 struct index_hash_t : public std::unary_function<index_t, std::size_t>
5818 std::size_t operator()(const index_t& v) const
5820 std::size_t seed = 0;
5821 boost::hash_combine(seed, v.get<0>());
5822 boost::hash_combine(seed, v.get<1>());
5823 boost::hash_combine(seed, v.get<2>());
5824 return seed;
5828 std::vector<OSG::Pnt3f> dice_knots(bool close_curve)
5831 // idea: sample a number if different cube boxes from the scene and
5832 // take randomly one point from each cube. That guarantees that
5833 // the knot points do not clump and that they are all unequal.
5835 namespace tp = boost::tuples;
5837 boost::unordered_set<index_t, index_hash_t> indices;
5839 while (indices.size() < num_curve_knots)
5841 indices.insert(tp::make_tuple(box_idx_die(), box_idx_die(), box_idx_die()));
5844 OSG::Real32 l = 2 * world_size / num_grid_boxes;
5846 std::vector<OSG::Pnt3f> knots;
5848 BOOST_FOREACH(const index_t& idx, indices)
5850 OSG::Pnt3f p;
5851 p[0] = -world_size + idx.get<0>() * l + unit_die() * l;
5852 p[1] = -world_size + idx.get<1>() * l + unit_die() * l;
5853 p[2] = -world_size + idx.get<2>() * l + unit_die() * l;
5855 knots.push_back(p);
5858 if (close_curve)
5859 knots.push_back(knots.front());
5861 return knots;
5864 // ============================================================================
5866 // Part: The shader programs
5868 // ============================================================================
5870 std::string add_test_colors()
5872 using namespace std;
5874 stringstream ost;
5877 << endl << "const vec4 IndianRed = vec4(0.804, 0.361, 0.361, 1.0);"
5878 << endl << "const vec4 LightCoral = vec4(0.941, 0.502, 0.502, 1.0);"
5879 << endl << "const vec4 Salmon = vec4(0.980, 0.502, 0.447, 1.0);"
5880 << endl << "const vec4 DarkSalmon = vec4(0.914, 0.588, 0.478, 1.0);"
5881 << endl << "const vec4 LightSalmon = vec4(1.000, 0.627, 0.478, 1.0);"
5882 << endl << "const vec4 Crimson = vec4(0.863, 0.078, 0.235, 1.0);"
5883 << endl << "const vec4 Red = vec4(1.000, 0.000, 0.000, 1.0);"
5884 << endl << "const vec4 FireBrick = vec4(0.698, 0.133, 0.133, 1.0);"
5885 << endl << "const vec4 DarkRed = vec4(0.545, 0.000, 0.000, 1.0);"
5886 << endl << "const vec4 Pink = vec4(1.000, 0.753, 0.796, 1.0);"
5887 << endl << "const vec4 LightPink = vec4(1.000, 0.714, 0.757, 1.0);"
5888 << endl << "const vec4 HotPink = vec4(1.000, 0.412, 0.706, 1.0);"
5889 << endl << "const vec4 DeepPink = vec4(1.000, 0.078, 0.576, 1.0);"
5890 << endl << "const vec4 MediumVioletRed = vec4(0.780, 0.082, 0.522, 1.0);"
5891 << endl << "const vec4 PaleVioletRed = vec4(0.859, 0.439, 0.576, 1.0);"
5892 << endl << "const vec4 Coral = vec4(1.000, 0.498, 0.314, 1.0);"
5893 << endl << "const vec4 Tomato = vec4(1.000, 0.388, 0.278, 1.0);"
5894 << endl << "const vec4 OrangeRed = vec4(1.000, 0.271, 0.000, 1.0);"
5895 << endl << "const vec4 DarkOrange = vec4(1.000, 0.549, 0.000, 1.0);"
5896 << endl << "const vec4 Orange = vec4(1.000, 0.647, 0.000, 1.0);"
5897 << endl << "const vec4 Gold = vec4(1.000, 0.843, 0.000, 1.0);"
5898 << endl << "const vec4 Yellow = vec4(1.000, 1.000, 0.000, 1.0);"
5899 << endl << "const vec4 LightYellow = vec4(1.000, 1.000, 0.878, 1.0);"
5900 << endl << "const vec4 LemonChion = vec4(1.000, 0.980, 0.804, 1.0);"
5901 << endl << "const vec4 LightGoldenrodYellow = vec4(0.980, 0.980, 0.824, 1.0);"
5902 << endl << "const vec4 PapayaWhip = vec4(1.000, 0.937, 0.835, 1.0);"
5903 << endl << "const vec4 Moccasin = vec4(1.000, 0.894, 0.710, 1.0);"
5904 << endl << "const vec4 PeachPu = vec4(1.000, 0.855, 0.725, 1.0);"
5905 << endl << "const vec4 PaleGoldenrod = vec4(0.933, 0.910, 0.667, 1.0);"
5906 << endl << "const vec4 Khaki = vec4(0.941, 0.902, 0.549, 1.0);"
5907 << endl << "const vec4 DarkKhaki = vec4(0.741, 0.718, 0.420, 1.0);"
5908 << endl << "const vec4 Lavender = vec4(0.902, 0.902, 0.980, 1.0);"
5909 << endl << "const vec4 Thistle = vec4(0.847, 0.749, 0.847, 1.0);"
5910 << endl << "const vec4 Plum = vec4(0.867, 0.627, 0.867, 1.0);"
5911 << endl << "const vec4 Violet = vec4(0.933, 0.510, 0.933, 1.0);"
5912 << endl << "const vec4 Orchid = vec4(0.855, 0.439, 0.839, 1.0);"
5913 << endl << "const vec4 Fuchsia = vec4(1.000, 0.000, 1.000, 1.0);"
5914 << endl << "const vec4 Magenta = vec4(1.000, 0.000, 1.000, 1.0);"
5915 << endl << "const vec4 MediumOrchid = vec4(0.729, 0.333, 0.827, 1.0);"
5916 << endl << "const vec4 MediumPurple = vec4(0.576, 0.439, 0.859, 1.0);"
5917 << endl << "const vec4 BlueViolet = vec4(0.541, 0.169, 0.886, 1.0);"
5918 << endl << "const vec4 DarkViolet = vec4(0.580, 0.000, 0.827, 1.0);"
5919 << endl << "const vec4 DarkOrchid = vec4(0.600, 0.196, 0.800, 1.0);"
5920 << endl << "const vec4 DarkMagenta = vec4(0.545, 0.000, 0.545, 1.0);"
5921 << endl << "const vec4 Purple = vec4(0.502, 0.000, 0.502, 1.0);"
5922 << endl << "const vec4 Indigo = vec4(0.294, 0.000, 0.510, 1.0);"
5923 << endl << "const vec4 SlateBlue = vec4(0.416, 0.353, 0.804, 1.0);"
5924 << endl << "const vec4 DarkSlateBlue = vec4(0.282, 0.239, 0.545, 1.0);"
5925 << endl << "const vec4 GreenYellow = vec4(0.678, 1.000, 0.184, 1.0);"
5926 << endl << "const vec4 Chartreuse = vec4(0.498, 1.000, 0.000, 1.0);"
5927 << endl << "const vec4 LawnGreen = vec4(0.486, 0.988, 0.000, 1.0);"
5928 << endl << "const vec4 Lime = vec4(0.000, 1.000, 0.000, 1.0);"
5929 << endl << "const vec4 LimeGreen = vec4(0.196, 0.804, 0.196, 1.0);"
5930 << endl << "const vec4 PaleGreen = vec4(0.596, 0.984, 0.596, 1.0);"
5931 << endl << "const vec4 LightGreen = vec4(0.565, 0.933, 0.565, 1.0);"
5932 << endl << "const vec4 MediumSpringGreen = vec4(0.000, 0.980, 0.604, 1.0);"
5933 << endl << "const vec4 SpringGreen = vec4(0.000, 1.000, 0.498, 1.0);"
5934 << endl << "const vec4 MediumSeaGreen = vec4(0.235, 0.702, 0.443, 1.0);"
5935 << endl << "const vec4 SeaGreen = vec4(0.180, 0.545, 0.341, 1.0);"
5936 << endl << "const vec4 ForestGreen = vec4(0.133, 0.545, 0.133, 1.0);"
5937 << endl << "const vec4 Green = vec4(0.000, 0.502, 0.000, 1.0);"
5938 << endl << "const vec4 DarkGreen = vec4(0.000, 0.392, 0.000, 1.0);"
5939 << endl << "const vec4 YellowGreen = vec4(0.604, 0.804, 0.196, 1.0);"
5940 << endl << "const vec4 OliveDrab = vec4(0.420, 0.557, 0.137, 1.0);"
5941 << endl << "const vec4 Olive = vec4(0.502, 0.502, 0.000, 1.0);"
5942 << endl << "const vec4 DarkOliveGreen = vec4(0.333, 0.420, 0.184, 1.0);"
5943 << endl << "const vec4 MediumAquamarine = vec4(0.400, 0.804, 0.667, 1.0);"
5944 << endl << "const vec4 DarkSeaGreen = vec4(0.561, 0.737, 0.561, 1.0);"
5945 << endl << "const vec4 LightSeaGreen = vec4(0.125, 0.698, 0.667, 1.0);"
5946 << endl << "const vec4 DarkCyan = vec4(0.000, 0.545, 0.545, 1.0);"
5947 << endl << "const vec4 Teal = vec4(0.000, 0.502, 0.502, 1.0);"
5948 << endl << "const vec4 Aqua = vec4(0.000, 1.000, 1.000, 1.0);"
5949 << endl << "const vec4 Cyan = vec4(0.000, 1.000, 1.000, 1.0);"
5950 << endl << "const vec4 LightCyan = vec4(0.878, 1.000, 1.000, 1.0);"
5951 << endl << "const vec4 PaleTurquoise = vec4(0.686, 0.933, 0.933, 1.0);"
5952 << endl << "const vec4 Aquamarine = vec4(0.498, 1.000, 0.831, 1.0);"
5953 << endl << "const vec4 Turquoise = vec4(0.251, 0.878, 0.816, 1.0);"
5954 << endl << "const vec4 MediumTurquoise = vec4(0.282, 0.820, 0.800, 1.0);"
5955 << endl << "const vec4 DarkTurquoise = vec4(0.000, 0.808, 0.820, 1.0);"
5956 << endl << "const vec4 CadetBlue = vec4(0.373, 0.620, 0.627, 1.0);"
5957 << endl << "const vec4 SteelBlue = vec4(0.275, 0.510, 0.706, 1.0);"
5958 << endl << "const vec4 LightSteelBlue = vec4(0.690, 0.769, 0.871, 1.0);"
5959 << endl << "const vec4 PowderBlue = vec4(0.690, 0.878, 0.902, 1.0);"
5960 << endl << "const vec4 LightBlue = vec4(0.678, 0.847, 0.902, 1.0);"
5961 << endl << "const vec4 SkyBlue = vec4(0.529, 0.808, 0.922, 1.0);"
5962 << endl << "const vec4 LightSkyBlue = vec4(0.529, 0.808, 0.980, 1.0);"
5963 << endl << "const vec4 DeepSkyBlue = vec4(0.000, 0.749, 1.000, 1.0);"
5964 << endl << "const vec4 DodgerBlue = vec4(0.118, 0.565, 1.000, 1.0);"
5965 << endl << "const vec4 CornlowerBlue = vec4(0.392, 0.584, 0.929, 1.0);"
5966 << endl << "const vec4 MediumSlateBlue = vec4(0.482, 0.408, 0.933, 1.0);"
5967 << endl << "const vec4 RoyalBlue = vec4(0.255, 0.412, 0.882, 1.0);"
5968 << endl << "const vec4 Blue = vec4(0.000, 0.000, 1.000, 1.0);"
5969 << endl << "const vec4 MediumBlue = vec4(0.000, 0.000, 0.804, 1.0);"
5970 << endl << "const vec4 DarkBlue = vec4(0.000, 0.000, 0.545, 1.0);"
5971 << endl << "const vec4 Navy = vec4(0.000, 0.000, 0.502, 1.0);"
5972 << endl << "const vec4 MidnightBlue = vec4(0.098, 0.098, 0.439, 1.0);"
5973 << endl << "const vec4 Cornsilk = vec4(1.000, 0.973, 0.863, 1.0);"
5974 << endl << "const vec4 BlanchedAlmond = vec4(1.000, 0.922, 0.804, 1.0);"
5975 << endl << "const vec4 Bisque = vec4(1.000, 0.894, 0.769, 1.0);"
5976 << endl << "const vec4 NavajoWhite = vec4(1.000, 0.871, 0.678, 1.0);"
5977 << endl << "const vec4 Wheat = vec4(0.961, 0.871, 0.702, 1.0);"
5978 << endl << "const vec4 BurlyWood = vec4(0.871, 0.722, 0.529, 1.0);"
5979 << endl << "const vec4 Tan = vec4(0.824, 0.706, 0.549, 1.0);"
5980 << endl << "const vec4 RosyBrown = vec4(0.737, 0.561, 0.561, 1.0);"
5981 << endl << "const vec4 SandyBrown = vec4(0.957, 0.643, 0.376, 1.0);"
5982 << endl << "const vec4 Goldenrod = vec4(0.855, 0.647, 0.125, 1.0);"
5983 << endl << "const vec4 DarkGoldenrod = vec4(0.722, 0.525, 0.043, 1.0);"
5984 << endl << "const vec4 Peru = vec4(0.804, 0.522, 0.247, 1.0);"
5985 << endl << "const vec4 Chocolate = vec4(0.824, 0.412, 0.118, 1.0);"
5986 << endl << "const vec4 SaddleBrown = vec4(0.545, 0.271, 0.075, 1.0);"
5987 << endl << "const vec4 Sienna = vec4(0.627, 0.322, 0.176, 1.0);"
5988 << endl << "const vec4 Brown = vec4(0.647, 0.165, 0.165, 1.0);"
5989 << endl << "const vec4 Maroon = vec4(0.502, 0.000, 0.000, 1.0);"
5990 << endl << "const vec4 White = vec4(1.000, 1.000, 1.000, 1.0);"
5991 << endl << "const vec4 Snow = vec4(1.000, 0.980, 0.980, 1.0);"
5992 << endl << "const vec4 Honeydew = vec4(0.941, 1.000, 0.941, 1.0);"
5993 << endl << "const vec4 MintCream = vec4(0.961, 1.000, 0.980, 1.0);"
5994 << endl << "const vec4 Azure = vec4(0.941, 1.000, 1.000, 1.0);"
5995 << endl << "const vec4 AliceBlue = vec4(0.941, 0.973, 1.000, 1.0);"
5996 << endl << "const vec4 GhostWhite = vec4(0.973, 0.973, 1.000, 1.0);"
5997 << endl << "const vec4 WhiteSmoke = vec4(0.961, 0.961, 0.961, 1.0);"
5998 << endl << "const vec4 Seashell = vec4(1.000, 0.961, 0.933, 1.0);"
5999 << endl << "const vec4 Beige = vec4(0.961, 0.961, 0.863, 1.0);"
6000 << endl << "const vec4 OldLace = vec4(0.992, 0.961, 0.902, 1.0);"
6001 << endl << "const vec4 FloralWhite = vec4(1.000, 0.980, 0.941, 1.0);"
6002 << endl << "const vec4 Ivory = vec4(1.000, 1.000, 0.941, 1.0);"
6003 << endl << "const vec4 AntiqueWhite = vec4(0.980, 0.922, 0.843, 1.0);"
6004 << endl << "const vec4 Linen = vec4(0.980, 0.941, 0.902, 1.0);"
6005 << endl << "const vec4 LavenderBlush = vec4(1.000, 0.941, 0.961, 1.0);"
6006 << endl << "const vec4 MistyRose = vec4(1.000, 0.894, 0.882, 1.0);"
6007 << endl << "const vec4 Gainsboro = vec4(0.863, 0.863, 0.863, 1.0);"
6008 << endl << "const vec4 LightGrey = vec4(0.827, 0.827, 0.827, 1.0);"
6009 << endl << "const vec4 Silver = vec4(0.753, 0.753, 0.753, 1.0);"
6010 << endl << "const vec4 DarkGray = vec4(0.663, 0.663, 0.663, 1.0);"
6011 << endl << "const vec4 Gray = vec4(0.502, 0.502, 0.502, 1.0);"
6012 << endl << "const vec4 DimGray = vec4(0.412, 0.412, 0.412, 1.0);"
6013 << endl << "const vec4 LightSlateGray = vec4(0.467, 0.533, 0.600, 1.0);"
6014 << endl << "const vec4 SlateGray = vec4(0.439, 0.502, 0.565, 1.0);"
6015 << endl << "const vec4 DarkSlateGray = vec4(0.184, 0.310, 0.310, 1.0);"
6016 << endl << "const vec4 Black = vec4(0.000, 0.000, 0.000, 1.0);"
6018 << endl << "const vec4 HeatMapColor0 = Black;"
6019 << endl << "const vec4 HeatMapColor1 = DarkSlateGray;"
6020 << endl << "const vec4 HeatMapColor2 = Navy;"
6021 << endl << "const vec4 HeatMapColor3 = Blue;"
6022 << endl << "const vec4 HeatMapColor4 = RoyalBlue;"
6023 << endl << "const vec4 HeatMapColor5 = DodgerBlue;"
6024 << endl << "const vec4 HeatMapColor6 = DeepSkyBlue;"
6025 << endl << "const vec4 HeatMapColor7 = Turquoise;"
6026 << endl << "const vec4 HeatMapColor8 = Aquamarine;"
6027 << endl << "const vec4 HeatMapColor9 = Cyan;"
6028 << endl << "const vec4 HeatMapColor10 = DarkGreen;"
6029 << endl << "const vec4 HeatMapColor11 = Green;"
6030 << endl << "const vec4 HeatMapColor12 = SpringGreen;"
6031 << endl << "const vec4 HeatMapColor13 = Lime;"
6032 << endl << "const vec4 HeatMapColor14 = Chartreuse;"
6033 << endl << "const vec4 HeatMapColor15 = GreenYellow;"
6034 << endl << "const vec4 HeatMapColor16 = Yellow;"
6035 << endl << "const vec4 HeatMapColor17 = Gold;"
6036 << endl << "const vec4 HeatMapColor18 = DarkOrange;"
6037 << endl << "const vec4 HeatMapColor19 = OrangeRed;"
6038 << endl << "const vec4 HeatMapColor20 = Red;"
6039 << endl << "const vec4 HeatMapColor21 = FireBrick;"
6040 << endl << "const vec4 HeatMapColor22 = DarkRed;"
6041 << endl << "const vec4 HeatMapColor23 = BlueViolet;"
6042 << endl << "const vec4 HeatMapColor24 = Fuchsia;"
6043 << endl << "const vec4 HeatMapColor25 = DeepPink;"
6044 << endl << "const vec4 HeatMapColor26 = HotPink;"
6045 << endl << "const vec4 HeatMapColor27 = Pink;"
6046 << endl << "const vec4 HeatMapColor28 = MistyRose;"
6047 << endl << "const vec4 HeatMapColor29 = LavenderBlush;"
6048 << endl << "const vec4 HeatMapColor30 = Seashell;"
6049 << endl << "const vec4 HeatMapColor31 = White;"
6051 << endl << "const uint uiHeatMapColor0 = 0; // Black"
6052 << endl << "const uint uiHeatMapColor1 = 1; // DarkSlateGray"
6053 << endl << "const uint uiHeatMapColor2 = 2; // Navy"
6054 << endl << "const uint uiHeatMapColor3 = 3; // Blue"
6055 << endl << "const uint uiHeatMapColor4 = 4; // RoyalBlue"
6056 << endl << "const uint uiHeatMapColor5 = 5; // DodgerBlue"
6057 << endl << "const uint uiHeatMapColor6 = 6; // DeepSkyBlue"
6058 << endl << "const uint uiHeatMapColor7 = 7; // Turquoise"
6059 << endl << "const uint uiHeatMapColor8 = 8; // Aquamarine"
6060 << endl << "const uint uiHeatMapColor9 = 9; // Cyan"
6061 << endl << "const uint uiHeatMapColor10 = 10; // DarkGreen"
6062 << endl << "const uint uiHeatMapColor11 = 11; // Green"
6063 << endl << "const uint uiHeatMapColor12 = 12; // SpringGreen"
6064 << endl << "const uint uiHeatMapColor13 = 13; // Lime"
6065 << endl << "const uint uiHeatMapColor14 = 14; // Chartreuse"
6066 << endl << "const uint uiHeatMapColor15 = 15; // GreenYellow"
6067 << endl << "const uint uiHeatMapColor16 = 16; // Yellow"
6068 << endl << "const uint uiHeatMapColor17 = 17; // Gold"
6069 << endl << "const uint uiHeatMapColor18 = 18; // DarkOrange"
6070 << endl << "const uint uiHeatMapColor19 = 19; // OrangeRed"
6071 << endl << "const uint uiHeatMapColor20 = 20; // Red"
6072 << endl << "const uint uiHeatMapColor21 = 21; // FireBrick"
6073 << endl << "const uint uiHeatMapColor22 = 22; // DarkRed"
6074 << endl << "const uint uiHeatMapColor23 = 23; // BlueViolet"
6075 << endl << "const uint uiHeatMapColor24 = 24; // Fuchsia"
6076 << endl << "const uint uiHeatMapColor25 = 25; // DeepPink"
6077 << endl << "const uint uiHeatMapColor26 = 26; // HotPink"
6078 << endl << "const uint uiHeatMapColor27 = 27; // Pink"
6079 << endl << "const uint uiHeatMapColor28 = 28; // MistyRose"
6080 << endl << "const uint uiHeatMapColor29 = 29; // LavenderBlush"
6081 << endl << "const uint uiHeatMapColor30 = 30; // Seashell"
6082 << endl << "const uint uiHeatMapColor31 = 31; // White"
6084 << endl;
6086 return ost.str();
6090 // compute shader programs.
6092 std::string get_persp_frustum_cp_program()
6094 using namespace std;
6096 stringstream ost;
6098 ost << "#version 430 compatibility"
6099 << endl << ""
6100 << endl << "layout (local_size_x = " << work_group_size.x()
6101 << ", local_size_y = " << work_group_size.y()
6102 << ", local_size_z = " << work_group_size.z() << ") in;"
6103 << endl << ""
6104 << endl << "const int tile_size = " << tile_size << ";"
6105 << endl << ""
6106 << endl << "layout (std140) uniform DispatchData"
6107 << endl << "{"
6108 << endl << " mat4 matTransf; // inverse projection matrix"
6109 << endl << " uvec4 viewport;"
6110 << endl << " ivec2 numTiles;"
6111 << endl << "} dispatchData;"
6112 << endl << ""
6113 << endl << "struct Plane"
6114 << endl << "{"
6115 << endl << " vec3 N;"
6116 << endl << " float d;"
6117 << endl << "};"
6118 << endl << ""
6119 << endl << "struct Frustum"
6120 << endl << "{"
6121 << endl << " Plane planes[4];"
6122 << endl << "};"
6123 << endl << ""
6124 << endl << "layout (std430) buffer Frustums"
6125 << endl << "{"
6126 << endl << " Frustum frustum[];"
6127 << endl << "} frustums;"
6128 << endl << ""
6129 << endl << "const vec3 eyePos = vec3(0, 0, 0);"
6130 << endl << ""
6131 << endl << "Plane computePlane(in const vec3 p0, in const vec3 p1, in const vec3 p2)"
6132 << endl << "{"
6133 << endl << " Plane plane;"
6134 << endl << ""
6135 << endl << " vec3 v1 = p1 - p0;"
6136 << endl << " vec3 v2 = p2 - p0;"
6137 << endl << ""
6138 << endl << " plane.N = normalize(cross(v1, v2));"
6139 << endl << " plane.d = dot(plane.N, p0);"
6140 << endl << ""
6141 << endl << " return plane;"
6142 << endl << "}"
6143 << endl << ""
6144 << endl << "vec4 ndcFromScreen(in const vec3 p_w)"
6145 << endl << "{"
6146 << endl << " return vec4("
6147 << endl << " 2.0 * (p_w.x - dispatchData.viewport.x) / dispatchData.viewport[2] - 1.0,"
6148 << endl << " 2.0 * (p_w.y - dispatchData.viewport.y) / dispatchData.viewport[3] - 1.0,"
6149 << endl << " p_w.z, // assumed to be already in ndc-space!"
6150 << endl << " 1.0);"
6151 << endl << "}"
6152 << endl << ""
6153 << endl << "vec3 eyeFromNdc(in vec4 p_n)"
6154 << endl << "{"
6155 << endl << " vec4 p_e = dispatchData.matTransf * p_n; // inverse projection matrix"
6156 << endl << " p_e /= p_e.w;"
6157 << endl << " return p_e.xyz;"
6158 << endl << "}"
6159 << endl << ""
6160 << endl << "void main()"
6161 << endl << "{"
6162 << endl << " vec3 pnts_w[4];"
6163 << endl << " vec4 pnts_n[4];"
6164 << endl << " vec3 pnts_e[4];"
6165 << endl << ""
6167 // gl_GlobalInvocationID = gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID
6169 // gl_WorkGroupID - contains the index of the workgroup currently being operated on by a compute shader
6170 // values range across the parameters passed into glDispatchCompute, i.e. from (0,0,0)
6171 // to (gl_NumWorkGroups.x-1, gl_NumWorkGroups.y-1, gl_NumWorkGroups.z-1)
6173 // gl_WorkGroupSize - match those specified in the required local_size_x, local_size_y, and local_size_z
6174 // layout qualifiers for the current shader
6176 // gl_LocalInvocationID - values for this variable range across the local work group size, i.e., (0,0,0)
6177 // to (gl_WorkGroupSize.x-1, gl_WorkGroupSize.y-1, gl_WorkGroupSize.z-1)
6179 << endl << " float x_v = dispatchData.viewport.x;"
6180 << endl << " float y_v = dispatchData.viewport.y;"
6181 << endl << " float w_v = dispatchData.viewport.z;"
6182 << endl << " float h_v = dispatchData.viewport.w;"
6183 << endl << ""
6184 << endl << " float x0 = x_v + gl_GlobalInvocationID.x * tile_size;"
6185 << endl << " float x1 = min(x_v + (gl_GlobalInvocationID.x+1) * tile_size, x_v + w_v);"
6186 << endl << " float y0 = y_v + gl_GlobalInvocationID.y * tile_size;"
6187 << endl << " float y1 = min(y_v + (gl_GlobalInvocationID.y+1) * tile_size, y_v + h_v);"
6188 << endl << ""
6189 << endl << " pnts_w[0] = vec3(x0, y0, -1.0);"
6190 << endl << " pnts_w[1] = vec3(x1, y0, -1.0);"
6191 << endl << " pnts_w[2] = vec3(x0, y1, -1.0);"
6192 << endl << " pnts_w[3] = vec3(x1, y1, -1.0);"
6193 << endl << ""
6194 << endl << " for (int i = 0; i < 4; ++i)"
6195 << endl << " {"
6196 << endl << " pnts_n[i] = ndcFromScreen(pnts_w[i]);"
6197 << endl << " pnts_e[i] = eyeFromNdc (pnts_n[i]);"
6198 << endl << " }"
6199 << endl << ""
6200 << endl << " Frustum frustum;"
6201 << endl << ""
6202 << endl << " frustum.planes[0] = computePlane(eyePos, pnts_e[0], pnts_e[2]);"
6203 << endl << " frustum.planes[1] = computePlane(eyePos, pnts_e[3], pnts_e[1]);"
6204 << endl << " frustum.planes[2] = computePlane(eyePos, pnts_e[2], pnts_e[3]);"
6205 << endl << " frustum.planes[3] = computePlane(eyePos, pnts_e[1], pnts_e[0]);"
6206 << endl << ""
6207 << endl << " if (gl_GlobalInvocationID.x < dispatchData.numTiles.x && gl_GlobalInvocationID.y < dispatchData.numTiles.y)"
6208 << endl << " {"
6209 << endl << " uint idx = gl_GlobalInvocationID.y * dispatchData.numTiles.x + gl_GlobalInvocationID.x;"
6210 << endl << " frustums.frustum[idx] = frustum;"
6211 << endl << " }"
6212 << endl << "}"
6213 << endl << ""
6214 << endl;
6216 return ost.str();
6219 std::string get_ortho_frustum_cp_program()
6221 using namespace std;
6223 stringstream ost;
6225 ost << "#version 430 compatibility"
6226 << endl << ""
6227 << endl << "layout (local_size_x = " << work_group_size.x()
6228 << ", local_size_y = " << work_group_size.y()
6229 << ", local_size_z = " << work_group_size.z() << ") in;"
6230 << endl << ""
6231 << endl << "const int tile_size = " << tile_size << ";"
6232 << endl << ""
6233 << endl << "layout (std140) uniform DispatchData"
6234 << endl << "{"
6235 << endl << " mat4 matTransf; // inverse projection matrix"
6236 << endl << " uvec4 viewport;"
6237 << endl << " ivec2 numTiles;"
6238 << endl << "} dispatchData;"
6239 << endl << ""
6240 << endl << "struct Plane"
6241 << endl << "{"
6242 << endl << " vec3 N;"
6243 << endl << " float d;"
6244 << endl << "};"
6245 << endl << ""
6246 << endl << "struct Frustum"
6247 << endl << "{"
6248 << endl << " Plane planes[4];"
6249 << endl << "};"
6250 << endl << ""
6251 << endl << "layout (std430) buffer Frustums"
6252 << endl << "{"
6253 << endl << " Frustum frustum[];"
6254 << endl << "} frustums;"
6255 << endl << ""
6256 << endl << "Plane computePlane(in const vec3 p0, in const vec3 p1, in const vec3 p2)"
6257 << endl << "{"
6258 << endl << " Plane plane;"
6259 << endl << ""
6260 << endl << " vec3 v1 = p1 - p0;"
6261 << endl << " vec3 v2 = p2 - p0;"
6262 << endl << ""
6263 << endl << " plane.N = normalize(cross(v1, v2));"
6264 << endl << " plane.d = dot(plane.N, p0);"
6265 << endl << ""
6266 << endl << " return plane;"
6267 << endl << "}"
6268 << endl << ""
6269 << endl << "vec4 ndcFromScreen(in const vec3 p_w)"
6270 << endl << "{"
6271 << endl << " return vec4("
6272 << endl << " 2.0 * (p_w.x - dispatchData.viewport.x) / dispatchData.viewport[2] - 1.0,"
6273 << endl << " 2.0 * (p_w.y - dispatchData.viewport.y) / dispatchData.viewport[3] - 1.0,"
6274 << endl << " p_w.z, // assumed to be already in ndc-space!"
6275 << endl << " 1.0);"
6276 << endl << "}"
6277 << endl << ""
6278 << endl << "vec3 eyeFromNdc(in vec4 p_n)"
6279 << endl << "{"
6280 << endl << " vec4 p_e = dispatchData.matTransf * p_n; // inverse projection matrix"
6281 << endl << " p_e /= p_e.w;"
6282 << endl << " return p_e.xyz;"
6283 << endl << "}"
6284 << endl << ""
6285 << endl << "void main()"
6286 << endl << "{"
6287 << endl << " vec3 pnts_w[8];"
6288 << endl << " vec4 pnts_n[8];"
6289 << endl << " vec3 pnts_e[8];"
6290 << endl << ""
6292 // gl_GlobalInvocationID = gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID
6294 // gl_WorkGroupID - contains the index of the workgroup currently being operated on by a compute shader
6295 // values range across the parameters passed into glDispatchCompute, i.e. from (0,0,0)
6296 // to (gl_NumWorkGroups.x-1, gl_NumWorkGroups.y-1, gl_NumWorkGroups.z-1)
6298 // gl_WorkGroupSize - match those specified in the required local_size_x, local_size_y, and local_size_z
6299 // layout qualifiers for the current shader
6301 // gl_LocalInvocationID - values for this variable range across the local work group size, i.e., (0,0,0)
6302 // to (gl_WorkGroupSize.x-1, gl_WorkGroupSize.y-1, gl_WorkGroupSize.z-1)
6304 << endl << " float x_v = dispatchData.viewport.x;"
6305 << endl << " float y_v = dispatchData.viewport.y;"
6306 << endl << " float w_v = dispatchData.viewport.z;"
6307 << endl << " float h_v = dispatchData.viewport.w;"
6308 << endl << ""
6309 << endl << " float x0 = x_v + gl_GlobalInvocationID.x * tile_size;"
6310 << endl << " float x1 = min(x_v + (gl_GlobalInvocationID.x+1) * tile_size, x_v + w_v);"
6311 << endl << " float y0 = y_v + gl_GlobalInvocationID.y * tile_size;"
6312 << endl << " float y1 = min(y_v + (gl_GlobalInvocationID.y+1) * tile_size, y_v + h_v);"
6313 << endl << ""
6314 << endl << " pnts_w[0] = vec3(x0, y0, 1.0);"
6315 << endl << " pnts_w[1] = vec3(x1, y0, 1.0);"
6316 << endl << " pnts_w[2] = vec3(x0, y1, 1.0);"
6317 << endl << " pnts_w[3] = vec3(x1, y1, 1.0);"
6318 << endl << ""
6319 << endl << " pnts_w[4] = vec3(x0, y0,-1.0);"
6320 << endl << " pnts_w[5] = vec3(x1, y0,-1.0);"
6321 << endl << " pnts_w[6] = vec3(x0, y1,-1.0);"
6322 << endl << " pnts_w[7] = vec3(x1, y1,-1.0);"
6323 << endl << ""
6324 << endl << " for (int i = 0; i < 8; ++i)"
6325 << endl << " {"
6326 << endl << " pnts_n[i] = ndcFromScreen(pnts_w[i]);"
6327 << endl << " pnts_e[i] = eyeFromNdc (pnts_n[i]);"
6328 << endl << " }"
6329 << endl << ""
6330 << endl << " Frustum frustum;"
6331 << endl << ""
6332 << endl << " frustum.planes[0] = computePlane(pnts_e[6], pnts_e[0], pnts_e[2]);"
6333 << endl << " frustum.planes[1] = computePlane(pnts_e[7], pnts_e[3], pnts_e[1]);"
6334 << endl << " frustum.planes[2] = computePlane(pnts_e[6], pnts_e[2], pnts_e[3]);"
6335 << endl << " frustum.planes[3] = computePlane(pnts_e[4], pnts_e[1], pnts_e[0]);"
6336 << endl << ""
6337 << endl << " if (gl_GlobalInvocationID.x < dispatchData.numTiles.x && gl_GlobalInvocationID.y < dispatchData.numTiles.y)"
6338 << endl << " {"
6339 << endl << " uint idx = gl_GlobalInvocationID.y * dispatchData.numTiles.x + gl_GlobalInvocationID.x;"
6340 << endl << " frustums.frustum[idx] = frustum;"
6341 << endl << " }"
6342 << endl << "}"
6343 << endl << ""
6344 << endl;
6346 return ost.str();
6349 std::string get_light_culling_cp_program()
6351 using namespace std;
6353 stringstream ost;
6355 ost << "#version 430 compatibility"
6356 << endl << ""
6357 << endl << "#extension GL_ARB_shader_image_load_store: enable"
6358 << endl << ""
6359 << endl << "layout (local_size_x = " << work_group_size.x()
6360 << ", local_size_y = " << work_group_size.y()
6361 << ", local_size_z = " << work_group_size.z() << ") in;"
6362 << endl << ""
6363 << add_test_colors()
6364 << endl << ""
6365 << endl << "const int tile_size = " << tile_size << ";"
6366 << endl << ""
6367 << endl << "const int POINT_LIGHT = 1; // defined in OSGMultiLightChunk.h"
6368 << endl << "const int DIRECTIONAL_LIGHT = 2;"
6369 << endl << "const int SPOT_LIGHT = 3;"
6370 << endl << "const int CINEMA_LIGHT = 4;"
6371 << endl << ""
6372 << endl << "//"
6373 << endl << "// We write our results into the global light grid with:"
6374 << endl << "// imageStore(light_grid, ivec3(i,j,k), uvec4(o,c,0,0))"
6375 << endl << "// were:"
6376 << endl << "// i,j,k define the cluster index"
6377 << endl << "// o is the offset from the beginning of the global light index list for the cluster"
6378 << endl << "// c is the number if lights that are to be used for the cluster"
6379 << endl << "//"
6380 << endl << "layout(binding = 0, rg32ui) uniform uimage2DArray light_grid;"
6381 << endl << ""
6382 << endl << "//"
6383 << endl << "// We need access to the lights shape and position data"
6384 << endl << "//"
6385 << endl << "struct Light"
6386 << endl << "{"
6387 << endl << " mat4 eyeToLightSpaceMatrix;"
6388 << endl << " vec3 position; // in world space"
6389 << endl << " vec3 direction; // in world space"
6390 << endl << " vec3 color;"
6391 << endl << " float intensity;"
6392 << endl << " float range;"
6393 << endl << " float cosSpotlightAngle;"
6394 << endl << " float spotlightAngle;"
6395 << endl << " float innerSuperEllipsesWidth; // a"
6396 << endl << " float innerSuperEllipsesHeight; // b"
6397 << endl << " float outerSuperEllipsesWidth; // A"
6398 << endl << " float outerSuperEllipsesHeight; // B"
6399 << endl << " float superEllipsesRoundness; // r"
6400 << endl << " float superEllipsesTwist; // theta"
6401 << endl << " int type; // specific type of light: POINT_LIGHT, DIRECTIONAL_LIGHT, SPOT_LIGHT or CINEMA_LIGHT"
6402 << endl << " bool enabled; // on/off state of light"
6403 << endl << "};"
6404 << endl << ""
6405 << endl << "layout (std430) buffer Lights"
6406 << endl << "{"
6407 << endl << " Light light[];"
6408 << endl << "} lights;"
6409 << endl << ""
6410 << endl << "//"
6411 << endl << "// Miscellaneous data that are needed for the task at hand"
6412 << endl << "//"
6413 << endl << "layout (std140) uniform DispatchData"
6414 << endl << "{"
6415 << endl << " mat4 matTransf; // world to view matrix"
6416 << endl << " uvec4 viewport;"
6417 << endl << " ivec2 numTiles;"
6418 << endl << "} dispatchData;"
6419 << endl << ""
6420 << endl << "//"
6421 << endl << "// The data we need to calc the cluster depth values from the cluster key k"
6422 << endl << "//"
6423 << endl << "layout (std140) uniform ClusteringData"
6424 << endl << "{"
6425 << endl << " float zNear; // positive near plane distance from eye zNear > 0"
6426 << endl << " float zFar; // positive far plane distance from eye zFar > zNear > 0"
6427 //<< endl << " float D; // positive near plane offset D >= 0 // for testing"
6428 << endl << " float nD; // zNear + D : shader optimization"
6429 << endl << " float lg_nD; // log2(nD) : shader optimization"
6430 << endl << " float a; // precalculated factor (c-1)/log2(f/(n+D))"
6431 << endl << " float b; // precalculated factor log2(f/(n+D))/(c-1)"
6432 //<< endl << " int c; // number of cluster planes // for testing"
6433 << endl << " int c_1; // number of cluster planes minus one : shader optimization"
6434 << endl << " ivec2 p_v; // viewport corner points"
6435 //<< endl << " ivec3 n_c; // number of clusters // for testing"
6436 << endl << " int t_v; // test dependent content // for testing"
6437 << endl << "} clusteringData;"
6438 << endl << ""
6439 // Debug Test Begin
6440 //<< endl << "//"
6441 //<< endl << "// Pure testing data"
6442 //<< endl << "//"
6443 //<< endl << "layout (std430) buffer TestData"
6444 //<< endl << "{"
6445 //<< endl << " float value01;"
6446 //<< endl << " float value02;"
6447 //<< endl << " float value03;"
6448 //<< endl << " float value04;"
6449 //<< endl << " vec3 value05;"
6450 //<< endl << " vec3 value06;"
6451 //<< endl << " int value07;"
6452 //<< endl << " int value08;"
6453 //<< endl << " uint value09;"
6454 //<< endl << " uint value10;"
6455 //<< endl << " ivec3 value11;"
6456 //<< endl << " uvec3 value12;"
6457 //<< endl << " float value13[" << TestData::num_array_elements << "];"
6458 //<< endl << " float value14[" << TestData::num_array_elements << "];"
6459 //<< endl << " uint value15[" << TestData::num_array_elements << "];"
6460 //<< endl << " vec3 value16[" << TestData::num_array_elements << "];"
6461 //<< endl << " vec3 value17[" << TestData::num_array_elements << "];"
6462 //<< endl << "} testData;"
6463 //<< endl << ""
6464 // Debug Test End
6465 << endl << "//"
6466 << endl << "// A simple Plane abstraction"
6467 << endl << "//"
6468 << endl << "struct Plane"
6469 << endl << "{"
6470 << endl << " vec3 N;"
6471 << endl << " float d;"
6472 << endl << "};"
6473 << endl << ""
6474 << endl << "//"
6475 << endl << "// The 4 planes of the tile frustum"
6476 << endl << "//"
6477 << endl << "struct Frustum"
6478 << endl << "{"
6479 << endl << " Plane planes[4];"
6480 << endl << "};"
6481 << endl << ""
6482 << endl << "//"
6483 << endl << "// A simple Sphere abstraction"
6484 << endl << "//"
6485 << endl << "struct Sphere"
6486 << endl << "{"
6487 << endl << " vec3 c; // Center point."
6488 << endl << " float r; // Radius."
6489 << endl << "};"
6490 << endl << ""
6491 << endl << "//"
6492 << endl << "// A simple Cone abstraction"
6493 << endl << "//"
6494 << endl << "struct Cone"
6495 << endl << "{"
6496 << endl << " vec3 T; // Cone tip."
6497 << endl << " float h; // Height of the cone."
6498 << endl << " vec3 d; // Direction of the cone."
6499 << endl << " float r; // bottom radius of the cone."
6500 << endl << "};"
6501 << endl << ""
6502 << endl << "//"
6503 << endl << "// We get the pre calculated list of frustums for each tile."
6504 << endl << "// The cluster frustum is accessed with the help of the"
6505 << endl << "// gl_WorkGroupID variable:"
6506 << endl << "//"
6507 << endl << "// idx = j * numHorizontalTiles + i"
6508 << endl << "// idx = gl_WorkGroupID.y * dispatchData.numTiles.x + gl_WorkGroupID.x"
6509 << endl << "//"
6510 << endl << "layout (std430) buffer Frustums"
6511 << endl << "{"
6512 << endl << " Frustum frustum[];"
6513 << endl << "} frustums;"
6514 << endl << ""
6515 // Debug Test Begin
6516 //<< endl << "layout (std430) buffer CPUFrustums"
6517 //<< endl << "{"
6518 //<< endl << " Frustum frustum[];"
6519 //<< endl << "} cpuFrustums;"
6520 //<< endl << ""
6521 // Debug Test End
6522 << endl << "//"
6523 << endl << "// The affected light index list that is iterated to get the light"
6524 << endl << "//"
6525 << endl << "layout (std430) buffer AffectedLightIndexList"
6526 << endl << "{"
6527 << endl << " uint idx[];"
6528 << endl << "} affectedLightIndexList;"
6529 << endl << ""
6530 << endl << "//"
6531 << endl << "// The global light index list that is to be written by this shader"
6532 << endl << "//"
6533 << endl << "layout (std430) buffer LightIndexList"
6534 << endl << "{"
6535 << endl << " uint idx[];"
6536 << endl << "} lightIndexList;"
6537 << endl << ""
6538 << endl << "//"
6539 << endl << "// The global light index list that is to be written by this shader"
6540 << endl << "//"
6541 << endl << "layout (std430) buffer LightIndexCounter"
6542 << endl << "{"
6543 << endl << " uint lightIndexCounter;"
6544 << endl << "};"
6545 << endl << ""
6546 << endl << "//"
6547 << endl << "// Per work group shared state"
6548 << endl << "//"
6549 << endl << "shared Frustum sharedFrustum;"
6550 << endl << "shared vec2 sharedFrustumZ;"
6551 << endl << "shared uint sharedLightCount;"
6552 << endl << "shared uint sharedLightStartOffset;"
6553 << endl << "shared uint sharedLightIndexList[1024];"
6554 // Debug Test Begin
6555 //<< endl << "shared uint sharedTestValue;"
6556 //<< endl << ""
6557 //<< endl << "const float eps = 1.0E-4;"
6558 //<< endl << ""
6559 //<< endl << "bool isEqual(in const vec3 v1, in const vec3 v2)"
6560 //<< endl << "{"
6561 //<< endl << " if (all(lessThan(abs(v1-v2), vec3(eps,eps,eps))))"
6562 //<< endl << " return true;"
6563 //<< endl << " else"
6564 //<< endl << " return false;"
6565 //<< endl << "}"
6566 //<< endl << ""
6567 //<< endl << "bool isEqual(in const float v1, in const float v2)"
6568 //<< endl << "{"
6569 //<< endl << " if (abs(v1-v2) < eps)"
6570 //<< endl << " return true;"
6571 //<< endl << " else"
6572 //<< endl << " return false;"
6573 //<< endl << "}"
6574 // Debug Test End
6575 << endl << ""
6576 << endl << "//"
6577 << endl << "// cluster_z and cluster_z_verbose calculates the cluster eye space z from the cluster key k value"
6578 << endl << "// z_e = cluster_z(k, ...) with z_e in [-n, -f]"
6579 << endl << "//"
6580 << endl << "// Formular:"
6581 << endl << "// z_e = -n if k == 0"
6582 << endl << "// z_e = -(n+D) * exp2( (k-1)*(log2(f/(n+D))/(c-1)) ) else"
6583 << endl << "// z_e = -f if k > c-1"
6584 << endl << "//"
6585 // Debug Test Begin
6586 //<< endl << "float cluster_z_verbose("
6587 //<< endl << " in const uint k, // cluster coordinate, 0 <= k <= c"
6588 //<< endl << " in const float n, // near plane distance from viewer n > 0"
6589 //<< endl << " in const float f, // far plane distance from viewer f > n > 0"
6590 //<< endl << " in const float D, // near plane offset"
6591 //<< endl << " in const int c) // number of cluster planes"
6592 //<< endl << "{"
6593 //<< endl << " if (k == 0) return -n;"
6594 //<< endl << " if (k > c-1) return -f;"
6595 //<< endl << ""
6596 //<< endl << " float z_e = -(n+D) * exp2(float(k-1) * (log2(f/(n+D))/float(c-1)));"
6597 //<< endl << " return z_e;"
6598 //<< endl << "}"
6599 //<< endl << ""
6600 // Debug Test End
6601 << endl << "float cluster_z("
6602 << endl << " in const uint k, // cluster coordinate, 0 <= k <= c"
6603 << endl << " in const float n, // near plane distance from viewer n > 0"
6604 << endl << " in const float f, // far plane distance from viewer f > n > 0"
6605 << endl << " in const float nD, // near plane distance from viewer plus offset, nD = n+D with n > 0, D > 0"
6606 << endl << " in const float b, // factor log2(f/(n+D))/(c-1)"
6607 << endl << " in const int c_1) // number of cluster planes"
6608 << endl << "{"
6609 << endl << " if (k == 0) return -n;"
6610 << endl << " if (k > c_1) return -f;"
6611 << endl << ""
6612 << endl << " float z_e = -nD * exp2(float(k-1) * b);"
6613 << endl << " return z_e;"
6614 << endl << "}"
6615 << endl << ""
6616 << endl << "//"
6617 << endl << "// Check to see if a sphere is fully behind (inside the negative halfspace of) a plane."
6618 << endl << "//"
6619 << endl << "bool sphereInsidePlane("
6620 << endl << " in const Sphere sphere,"
6621 << endl << " in const Plane plane)"
6622 << endl << "{"
6623 << endl << " float val = dot(plane.N, sphere.c) - plane.d;"
6624 << endl << " return val < -sphere.r;"
6625 << endl << "}"
6626 << endl << ""
6627 << endl << "//"
6628 << endl << "// Check to see of a light is partially contained within the frustum."
6629 << endl << "//"
6630 << endl << "bool sphereInsideFrustum("
6631 << endl << " in const Sphere sphere,"
6632 << endl << " in const Frustum frustum,"
6633 << endl << " in const float zNear,"
6634 << endl << " in const float zFar)"
6635 << endl << "{"
6636 << endl << " bool result = true;"
6637 << endl << ""
6638 << endl << " if (sphere.c.z - sphere.r > zNear || zFar > sphere.c.z + sphere.r)"
6639 << endl << " {"
6640 << endl << " result = false;"
6641 << endl << " }"
6642 << endl << ""
6643 << endl << " for (int i = 0; i < 4 && result; i++)"
6644 << endl << " {"
6645 << endl << " if (sphereInsidePlane(sphere, frustum.planes[i]))"
6646 << endl << " {"
6647 << endl << " result = false;"
6648 << endl << " }"
6649 << endl << " }"
6650 << endl << ""
6651 << endl << " return result;"
6652 << endl << "}"
6653 << endl << ""
6654 << endl << "//"
6655 << endl << "// Check to see if a point is fully behind (inside the negative halfspace of) a plane."
6656 << endl << "//"
6657 << endl << "bool pointInsidePlane("
6658 << endl << " in const vec3 p,"
6659 << endl << " in const Plane plane)"
6660 << endl << "{"
6661 << endl << " float val = dot(plane.N, p) - plane.d;"
6662 << endl << " return val < 0;"
6663 << endl << "}"
6664 << endl << ""
6665 << endl << "//"
6666 << endl << "// Check to see if a cone if fully behind (inside the negative halfspace of) a plane."
6667 << endl << "//"
6668 << endl << "bool coneInsidePlane("
6669 << endl << " in const Cone cone,"
6670 << endl << " in const Plane plane)"
6671 << endl << "{"
6672 << endl << " // Compute the farthest point on the end of the cone to the positive space of the plane."
6673 << endl << " vec3 m = cross(cross(plane.N, cone.d), cone.d);"
6674 << endl << " vec3 Q = cone.T + cone.d * cone.h - m * cone.r;"
6675 << endl << ""
6676 << endl << " // The cone is in the negative halfspace of the plane if both"
6677 << endl << " // the tip of the cone and the farthest point on the end of the cone to the "
6678 << endl << " // positive halfspace of the plane are both inside the negative halfspace "
6679 << endl << " // of the plane."
6680 << endl << " return pointInsidePlane(cone.T, plane) && pointInsidePlane(Q, plane);"
6681 << endl << "}"
6682 << endl << ""
6683 << endl << "bool coneInsideFrustum("
6684 << endl << " in const Cone cone,"
6685 << endl << " in const Frustum frustum,"
6686 << endl << " in const float zNear,"
6687 << endl << " in const float zFar)"
6688 << endl << "{"
6689 << endl << " bool result = true;"
6690 << endl << ""
6691 << endl << " Plane nearPlane; nearPlane.N = vec3(0, 0,-1); nearPlane.d = -zNear;"
6692 << endl << " Plane farPlane; farPlane.N = vec3(0, 0, 1); farPlane.d = zFar;"
6693 << endl << ""
6694 << endl << " if (coneInsidePlane(cone, nearPlane) || coneInsidePlane(cone, farPlane))"
6695 << endl << " {"
6696 << endl << " result = false;"
6697 << endl << " }"
6698 << endl << ""
6699 << endl << " for (int i = 0; i < 4 && result; i++)"
6700 << endl << " {"
6701 << endl << " if (coneInsidePlane(cone, frustum.planes[i]))"
6702 << endl << " {"
6703 << endl << " result = false;"
6704 << endl << " }"
6705 << endl << " }"
6706 << endl << ""
6707 << endl << " return result;"
6708 << endl << "}"
6709 << endl << ""
6710 << endl << "//"
6711 << endl << "// Helper function that provides the cluster index (ivec3) of the current work group invocation"
6712 << endl << "//"
6713 << endl << "ivec3 clusterAccessor()"
6714 << endl << "{"
6715 // gl_WorkGroupID - contains the index of the workgroup currently being operated on by a compute shader
6716 // values range across the parameters passed into glDispatchCompute, i.e. from (0,0,0)
6717 // to (gl_NumWorkGroups.x-1, gl_NumWorkGroups.y-1, gl_NumWorkGroups.z-1)
6718 // in uvec3 gl_WorkGroupID
6719 << endl << " return ivec3(gl_WorkGroupID);"
6720 << endl << "}"
6721 << endl << ""
6722 << endl << "//"
6723 << endl << "// Helper function that provides the tile frustum index of the current cluster"
6724 << endl << "//"
6725 << endl << "int frustumAccessor()"
6726 << endl << "{"
6727 // gl_WorkGroupID - contains the index of the workgroup currently being operated on by a compute shader
6728 // values range across the parameters passed into glDispatchCompute, i.e. from (0,0,0)
6729 // to (gl_NumWorkGroups.x-1, gl_NumWorkGroups.y-1, gl_NumWorkGroups.z-1)
6730 // in uvec3 gl_WorkGroupID
6731 << endl << " return int(gl_WorkGroupID.y) * dispatchData.numTiles.x + int(gl_WorkGroupID.x);"
6732 << endl << "}"
6733 << endl << ""
6734 << endl << "//"
6735 << endl << "// Helper function that provides the tile frustum index of the current cluster"
6736 << endl << "//"
6737 << endl << "vec2 getClusterDepth()"
6738 << endl << "{"
6739 << endl << " return vec2(cluster_z(gl_WorkGroupID.z, clusteringData.zNear, clusteringData.zFar, clusteringData.nD, clusteringData.b, clusteringData.c_1),"
6740 << endl << " cluster_z(gl_WorkGroupID.z+1, clusteringData.zNear, clusteringData.zFar, clusteringData.nD, clusteringData.b, clusteringData.c_1));"
6741 // Debug Test Begin
6742 //<< endl << " return vec2(cluster_z_verbose(gl_WorkGroupID.z, clusteringData.zNear, clusteringData.zFar, clusteringData.D, clusteringData.c),"
6743 //<< endl << " cluster_z_verbose(gl_WorkGroupID.z+1, clusteringData.zNear, clusteringData.zFar, clusteringData.D, clusteringData.c));"
6744 // Debug Test End
6745 << endl << "}"
6746 << endl << ""
6747 << endl << "//"
6748 << endl << "// Append the light light_idx to the list of lights to be rendered for "
6749 << endl << "// this cluster. That is we have to increment the sharedLightCount and"
6750 << endl << "// to append the light_idx to the sharedLightIndexList."
6751 << endl << "// "
6752 << endl << "void appendLight(in const uint light_idx)"
6753 << endl << "{"
6754 << endl << " uint idx = atomicAdd(sharedLightCount, 1);"
6755 << endl << " if (idx < 1024)"
6756 << endl << " {"
6757 << endl << " sharedLightIndexList[idx] = light_idx;"
6758 << endl << " }"
6759 << endl << "}"
6760 << endl << ""
6761 << endl << "void main()"
6762 << endl << "{"
6763 << endl << " //"
6764 << endl << " // Initialize the work group shared state: Only the first thread is needed for that"
6765 << endl << " //"
6766 // gl_LocalInvocationIndex - contains the local linear index of work item currently being operated on by a compute shader
6767 // - in uint gl_LocalInvocationIndex
6768 // - is a derived input variable containing the 1-dimensional linearized index of the work invocation
6769 // within the work group that the current shader is executing on. The value of gl_LocalInvocationIndex
6770 // is equal to
6771 // gl_LocalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y
6772 // + gl_LocalInvocationID.y * gl_WorkGroupSize.x
6773 // + gl_LocalInvocationID.x.
6775 << endl << " if (gl_LocalInvocationIndex == 0)"
6776 << endl << " {"
6777 << endl << " sharedFrustum = frustums.frustum[frustumAccessor()];"
6778 << endl << " sharedFrustumZ = getClusterDepth();"
6779 << endl << " sharedLightCount = 0;"
6780 // Debug Test Begin
6781 // << endl << " sharedTestValue = 0;"
6782 // Debug Test End
6783 << endl << " }"
6784 << endl << ""
6785 // memoryBarrierShared - controls the ordering of operations on shared variables issued by a single shader invocation
6786 // - waits on the completion of all memory accesses resulting from the use of shared variables and
6787 // then returns with no other effect. When this function returns, the results of any modifications
6788 // to the content of shared variables will be visible to any access to the same buffer from other
6789 // shader invocations. In particular, any modifications made in one shader stage are guaranteed to
6790 // be visible to accesses performed by shader invocations in subsequent stages when those invocations
6791 // were triggered by the execution of the original shader invocation (e.g., fragment shader invocations
6792 // for a primitive resulting from a particular geometry shader invocation).
6794 // barrier - synchronize execution of multiple shader invocations
6795 // - provides a partially defined order of execution between shader invocations.
6796 // - for any given static instance of barrier in a compute shader, all invocations within a single work group
6797 // must enter it before any are allowed to continue beyond it. This ensures that values written by one
6798 // invocation prior to a given static instance of barrier can be safely read by other invocations after their
6799 // call to the same static instance of barrier.
6800 // - may be placed anywhere in a compute shader. Calls to barrier may not be placed within any control flow.
6802 << endl << " memoryBarrierShared(); // Ensure change to sharedXXX is visible in other invocations"
6803 << endl << " barrier(); // Stall until every thread reaches this point"
6804 << endl << ""
6806 // gl_WorkGroupSize - contains the size of the workgroup operated on by a compute shader
6807 // - const uvec3 gl_WorkGroupSize
6808 // - contains the size of a workgroup declared by a compute shader. The size of the work group in the X, Y, and Z dimensions
6809 // is stored in the x, y, and z components of gl_WorkGroupSize.
6810 // - match those specified in the required local_size_x, local_size_y, and local_size_z layout qualifiers for the current shader.
6811 // - is constant so that it can be used to size arrays of memory that can be shared within the local work group.
6813 << endl << " //"
6814 << endl << " // We iterate over all affected lights whereby splitting the lights into subsets for each thread."
6815 << endl << " // For each light we test it against the current frustum and if it is inside of the frustum, we add"
6816 << endl << " // the light to the group shared list of lights contributing to the current cluster corresponding to"
6817 << endl << " // the work group."
6818 << endl << " //"
6819 << endl << " for (uint i = gl_LocalInvocationIndex; i < affectedLightIndexList.idx.length(); i += gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z)"
6820 << endl << " {"
6821 << endl << " uint light_index = affectedLightIndexList.idx[i];"
6822 << endl << ""
6823 // Debug Test Begin
6824 //<< endl << " if (!isEqual(sharedFrustumZ.x, testData.value13[gl_WorkGroupID.z]))"
6825 //<< endl << " atomicAdd(sharedTestValue, 1);"
6826 //<< endl << " if (!isEqual(sharedFrustumZ.y, testData.value14[gl_WorkGroupID.z]))"
6827 //<< endl << " atomicAdd(sharedTestValue, 1);"
6828 // Debug Test End
6829 << endl << " if (lights.light[light_index].enabled)"
6830 << endl << " {"
6831 << endl << " Light light = lights.light[light_index];"
6832 // Debug Test Begin
6833 //<< endl << " uint test_idx = light_index * dispatchData.numTiles.x * dispatchData.numTiles.y * clusteringData.c"
6834 //<< endl << " + gl_WorkGroupID.z * dispatchData.numTiles.x * dispatchData.numTiles.y"
6835 //<< endl << " + gl_WorkGroupID.y * dispatchData.numTiles.x"
6836 //<< endl << " + gl_WorkGroupID.x;"
6837 // Debug Test End
6838 << endl << ""
6839 << endl << " switch (light.type)"
6840 << endl << " {"
6841 << endl << " case DIRECTIONAL_LIGHT:"
6842 << endl << " {"
6843 << endl << " appendLight(light_index);"
6844 // Debug Test Begin
6845 //<< endl << " if (test_idx != testData.value15[test_idx])"
6846 //<< endl << " atomicAdd(sharedTestValue, 1);"
6847 // Debug Test End
6848 << endl << " }"
6849 << endl << " break;"
6850 << endl << ""
6851 << endl << " case POINT_LIGHT:"
6852 << endl << " case CINEMA_LIGHT:"
6853 << endl << " {"
6854 << endl << " vec4 position = dispatchData.matTransf * vec4(light.position, 1.0);"
6855 // Debug Test Begin
6856 //<< endl << " if (!isEqual(position.xyz, testData.value16[light_index]))"
6857 //<< endl << " atomicAdd(sharedTestValue, 1);"
6858 // Debug Test End
6859 << endl << ""
6860 << endl << " Sphere sphere = { position.xyz, light.range };"
6861 << endl << ""
6862 << endl << " if (sphereInsideFrustum(sphere, sharedFrustum, sharedFrustumZ.x, sharedFrustumZ.y))"
6863 << endl << " {"
6864 << endl << " appendLight(light_index);"
6865 // Debug Test Begin
6866 //<< endl << " if (test_idx != testData.value15[test_idx])"
6867 //<< endl << " atomicAdd(sharedTestValue, 1);"
6868 // Debug Test End
6869 << endl << " }"
6870 << endl << " }"
6871 << endl << " break;"
6872 << endl << ""
6873 << endl << " case SPOT_LIGHT:"
6874 << endl << " {"
6875 << endl << " vec4 position = dispatchData.matTransf * vec4(light.position, 1.0);"
6876 << endl << " vec4 direction = dispatchData.matTransf * vec4(light.direction, 0.0);"
6877 << endl << ""
6878 // Debug Test Begin
6879 //<< endl << " if (!isEqual(position.xyz, testData.value16[light_index]))"
6880 //<< endl << " atomicAdd(sharedTestValue, 1);"
6881 //<< endl << " if (!isEqual(direction.xyz, testData.value17[light_index]))"
6882 //<< endl << " atomicAdd(sharedTestValue, 1);"
6883 // Debug Test End
6884 << endl << " float radius = tan(light.spotlightAngle) * light.range;"
6885 << endl << " Cone cone = { position.xyz, light.range, direction.xyz, radius };"
6886 << endl << ""
6887 << endl << " if (coneInsideFrustum(cone, sharedFrustum, sharedFrustumZ.x, sharedFrustumZ.y))"
6888 << endl << " {"
6889 << endl << " appendLight(light_index);"
6890 // Debug Test Begin
6891 //<< endl << " if (test_idx != testData.value15[test_idx])"
6892 //<< endl << " atomicAdd(sharedTestValue, 1);"
6893 // Debug Test End
6894 << endl << " }"
6895 << endl << " }"
6896 << endl << " break;"
6897 << endl << " }"
6898 << endl << " }"
6899 << endl << " }"
6900 << endl << ""
6901 << endl << " //"
6902 << endl << " // Wait till all threads in group have caught up."
6903 << endl << " //"
6904 << endl << " memoryBarrierShared(); // Ensure change to sharedXXX is visible in other invocations"
6905 << endl << " barrier(); // Stall until every thread reaches this point"
6906 << endl << ""
6907 << endl << " //"
6908 << endl << " // Now we have the sharedLightIndexList filled and know by sharedLightCount the number"
6909 << endl << " // of lights that are contributing for the current cluster. What we have to do now is"
6910 << endl << " // to get space in the global light index list (lightIndexList). For that, we use the"
6911 << endl << " // global light index counter (lightIndexCounter) by atomically incrementing it"
6912 << endl << " // with the number of lights contributing to the current cluster and getting back the"
6913 << endl << " // offset from the start of the global light index list (sharedLightStartOffset)."
6914 << endl << " // So now we have requested space on the global light index list and we have the data"
6915 << endl << " // that need to be written to the global light grid data image, i.e. the offset from"
6916 << endl << " // the beginning of the global light index list and the number of lights to use for"
6917 << endl << " // shading the fragments falling into the current cluster."
6918 << endl << " //"
6919 << endl << " // Only thread 0 is needed for:"
6920 << endl << " // - atomically increment lightIndexCounter by sharedLightCount to get"
6921 << endl << " // sharedLightStartOffset"
6922 << endl << " // - write (sharedLightStartOffset, sharedLightCount) to light grid"
6923 << endl << " //"
6924 << endl << " if (gl_LocalInvocationIndex == 0)"
6925 << endl << " {"
6926 << endl << " sharedLightStartOffset = atomicAdd(lightIndexCounter, sharedLightCount);"
6927 << endl << ""
6928 << endl << " uvec4 data = uvec4(sharedLightStartOffset, sharedLightCount, 0, 0);"
6929 << endl << ""
6930 << endl << " //"
6931 << endl << " // We must protect from overflow"
6932 << endl << " //"
6933 << endl << " uint num_indices = lightIndexList.idx.length();"
6934 << endl << " if (sharedLightStartOffset + sharedLightCount >= num_indices)"
6935 << endl << " data = uvec4(0,0,0,0);"
6936 << endl << ""
6937 << endl << " imageStore(light_grid, clusterAccessor(), data);"
6938 // Debug Test Begin
6940 // Test value evaluation
6942 //<< endl << " if (cpuFrustums.frustum.length() == 0) sharedTestValue += 1;"
6943 //<< endl << " else if ( frustums.frustum.length() == 0) sharedTestValue += 1;"
6944 //<< endl << " else if ( frustums.frustum.length() != cpuFrustums.frustum.length()) sharedTestValue += 1;"
6945 //<< endl << ""
6947 //<< endl << " for (int j = 0; j < cpuFrustums.frustum.length(); ++j)"
6948 //<< endl << " {"
6949 //<< endl << " for (int i = 0; i < 4; ++i)"
6950 //<< endl << " {"
6951 //<< endl << " if (cpuFrustums.frustum[j].planes[i].d != frustums.frustum[j].planes[i].d) sharedTestValue += 1;"
6952 //<< endl << " else if (!isEqual(cpuFrustums.frustum[j].planes[i].N, frustums.frustum[j].planes[i].N)) sharedTestValue += 1;"
6953 //<< endl << " }"
6954 //<< endl << " }"
6956 //<< endl << " if (sharedTestValue > 0)"
6957 //<< endl << " sharedTestValue = uiHeatMapColor20;"
6958 //<< endl << " else"
6959 //<< endl << " sharedTestValue= 1000;"
6961 //<< endl << " uvec4 data = uvec4(0, sharedTestValue, 0, 0);"
6962 //<< endl << " imageStore(light_grid, clusterAccessor(), data);"
6965 // Test grid storage
6967 //<< endl << " uint light_start_offset = 0;"
6968 //<< endl << " uint light_count = 0;"
6969 //<< endl << " if (gl_WorkGroupID.x == 0 && gl_WorkGroupID.y == 0)"
6970 //<< endl << " {"
6971 //<< endl << " light_start_offset = 7345698 + uiHeatMapColor13;"
6972 //<< endl << " light_count = 563472981 + gl_WorkGroupID.z;"
6973 //<< endl << " }"
6974 //<< endl << " else if (gl_WorkGroupID.x == gl_NumWorkGroups.x-1 && gl_WorkGroupID.y == gl_NumWorkGroups.y-1)"
6975 //<< endl << " {"
6976 //<< endl << " light_start_offset = 7345698 + uiHeatMapColor13;"
6977 //<< endl << " light_count = 563472981 + uiHeatMapColor8;"
6978 //<< endl << " }"
6979 //<< endl << " else"
6980 //<< endl << " {"
6981 //<< endl << " light_start_offset = 7345698 + uiHeatMapColor13;"
6982 //<< endl << " light_count = 563472981 + gl_WorkGroupID.z;"
6983 //<< endl << " }"
6984 //<< endl << " uvec4 data = uvec4(light_start_offset, light_count, 0, 0);"
6985 //<< endl << " imageStore(light_grid, clusterAccessor(), data);"
6986 // Debug Test End
6987 << endl << " }"
6988 << endl << ""
6989 << endl << " memoryBarrierShared(); // Ensure change to sharedXXX is visible in other invocations"
6990 << endl << " barrier(); // Stall until every thread reaches this point"
6991 << endl << ""
6992 << endl << " //"
6993 << endl << " // The last task is to write the actual lights affecting the current cluster into the"
6994 << endl << " // the global light index list. We have already requestet the appropriate space on the"
6995 << endl << " // this list so we can just iterate over the local light list (sharedLightIndexList) and"
6996 << endl << " // write the carry the content to the global list. That can also be done in parrallel, so"
6997 << endl << " // we use all the thread we have at hand."
6998 << endl << " //"
6999 << endl << ""
7000 << endl << " uint num_indices = lightIndexList.idx.length();"
7001 << endl << ""
7002 << endl << " for (uint i = gl_LocalInvocationIndex; i < sharedLightCount; i += gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z)"
7003 << endl << " {"
7004 << endl << " if (sharedLightStartOffset + i < num_indices)"
7005 << endl << " lightIndexList.idx[sharedLightStartOffset + i] = sharedLightIndexList[i];"
7006 << endl << " }"
7007 << endl << "}"
7008 << endl << ""
7009 << endl;
7011 return ost.str();
7015 // vertex shader program.
7017 std::string get_vp_program()
7019 using namespace std;
7021 stringstream ost;
7023 ost << "#version 440 compatibility"
7024 << endl << ""
7025 << endl << "#extension GL_ARB_separate_shader_objects: enable"
7026 << endl << "#extension GL_ARB_shader_storage_buffer_object: enable"
7027 << endl << ""
7028 << endl << "smooth out vec3 vNormalES; // eye space normal"
7029 << endl << "smooth out vec3 vPositionES; // eye space position"
7030 << endl << ""
7031 << endl << "void main()"
7032 << endl << "{"
7033 << endl << " //"
7034 << endl << " // multiply the object space vertex position with the modelview matrix "
7035 << endl << " // to get the eye space vertex position"
7036 << endl << " //"
7037 << endl << " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;"
7038 << endl << ""
7039 << endl << " //"
7040 << endl << " // multiply the object space normal with the normal matrix (transpose of the inverse "
7041 << endl << " // model view matrix) to get the eye space normal"
7042 << endl << " //"
7043 << endl << " vNormalES = gl_NormalMatrix * gl_Normal;"
7044 << endl << ""
7045 << endl << " //"
7046 << endl << " // multiply the combiend modelview projection matrix with the object space vertex"
7047 << endl << " // position to get the clip space position"
7048 << endl << " //"
7049 << endl << " gl_Position = ftransform();"
7050 << endl << "}"
7051 << endl << ""
7052 << endl;
7054 return ost.str();
7058 // fragment shader program for bump mapping in surface local coordinates
7060 std::string get_fp_program()
7062 using namespace std;
7064 stringstream ost;
7067 << "#version 440 compatibility"
7068 << endl << ""
7069 << endl << "#extension GL_ARB_shader_storage_buffer_object: enable"
7070 << endl << "#extension GL_ARB_shader_image_load_store: enable"
7071 << endl << ""
7072 << endl << "smooth in vec3 vNormalES; // eye space normal"
7073 << endl << "smooth in vec3 vPositionES; // eye space position"
7074 << endl << ""
7075 << add_test_colors()
7076 << endl << ""
7077 << endl << "const int num_materials = " << num_materials << ";"
7078 << endl << ""
7079 << endl << "const int POINT_LIGHT = 1; // defined in OSGMultiLightChunk.h"
7080 << endl << "const int DIRECTIONAL_LIGHT = 2;"
7081 << endl << "const int SPOT_LIGHT = 3;"
7082 << endl << "const int CINEMA_LIGHT = 4;"
7083 << endl << ""
7084 << endl << "const int tile_size = " << tile_size << ";"
7085 << endl << ""
7086 << endl << "uniform mat4 OSGViewMatrix; // from world space to view space transformation"
7087 << endl << ""
7088 << endl << "layout(binding = 0, rg32ui) uniform uimage2DArray light_grid;"
7089 // Debug Test Begin
7090 //<< endl << "layout(binding = 1, rg32ui) uniform uimage2DArray light_grid_cpu;"
7091 // Debug Test End
7092 << endl << ""
7093 << endl << "struct Light"
7094 << endl << "{"
7095 << endl << " mat4 eyeToLightSpaceMatrix;"
7096 << endl << " vec3 position; // in world space"
7097 << endl << " vec3 direction; // in world space"
7098 << endl << " vec3 color;"
7099 << endl << " float intensity;"
7100 << endl << " float range;"
7101 << endl << " float cosSpotlightAngle;"
7102 << endl << " float spotlightAngle;"
7103 << endl << " float innerSuperEllipsesWidth; // a"
7104 << endl << " float innerSuperEllipsesHeight; // b"
7105 << endl << " float outerSuperEllipsesWidth; // A"
7106 << endl << " float outerSuperEllipsesHeight; // B"
7107 << endl << " float superEllipsesRoundness; // r"
7108 << endl << " float superEllipsesTwist; // theta"
7109 << endl << " int type; // specific type of light: POINT_LIGHT, DIRECTIONAL_LIGHT, SPOT_LIGHT or CINEMA_LIGHT"
7110 << endl << " bool enabled; // on/off state of light"
7111 << endl << "};"
7112 << endl << ""
7113 << endl << "layout (std430) buffer Lights"
7114 << endl << "{"
7115 << endl << " Light light[];"
7116 << endl << "} lights;"
7117 << endl << ""
7118 << endl << "//"
7119 << endl << "// The affected light index list that is iterated to get the light"
7120 << endl << "//"
7121 << endl << "layout (std430) buffer AffectedLightIndexList"
7122 << endl << "{"
7123 << endl << " uint idx[];"
7124 << endl << "} affectedLightIndexList;"
7125 << endl << ""
7126 << endl << "layout (std430) buffer LightIndexList"
7127 << endl << "{"
7128 << endl << " uint idx[];"
7129 << endl << "} lightIndexList;"
7130 << endl << ""
7131 << endl << "struct Material"
7132 << endl << "{"
7133 << endl << " vec3 ambient;"
7134 << endl << " vec3 diffuse;"
7135 << endl << " vec3 specular;"
7136 << endl << " vec3 emissive;"
7137 << endl << ""
7138 << endl << " float opacity;"
7139 << endl << " float shininess;"
7140 << endl << "};"
7141 << endl << ""
7142 << endl << "layout (std430) buffer Materials"
7143 << endl << "{"
7144 << endl << " Material material[num_materials];"
7145 << endl << "} materials;"
7146 << endl << ""
7147 << endl << ""
7148 << endl << "layout (std140) uniform GeomState"
7149 << endl << "{"
7150 << endl << " uint material_index;"
7151 << endl << "} geom_state;"
7152 << endl << ""
7153 << endl << "struct Plane"
7154 << endl << "{"
7155 << endl << " vec3 N;"
7156 << endl << " float d;"
7157 << endl << "};"
7158 << endl << ""
7159 << endl << "struct Frustum"
7160 << endl << "{"
7161 << endl << " Plane planes[4];"
7162 << endl << "};"
7163 << endl << ""
7164 << endl << "layout (std430) buffer Frustums"
7165 << endl << "{"
7166 << endl << " Frustum frustum[];"
7167 << endl << "} frustums;"
7168 << endl << ""
7169 // Debug Test Begin
7170 //<< endl << "layout (std430) buffer CPUFrustums"
7171 //<< endl << "{"
7172 //<< endl << " Frustum frustum[];"
7173 //<< endl << "} cpuFrustums;"
7174 //<< endl << ""
7175 // Debug Test End
7176 << endl << "layout (std140) uniform ClusteringData"
7177 << endl << "{"
7178 << endl << " float zNear; // positive near plane distance from eye zNear > 0"
7179 << endl << " float zFar; // positive far plane distance from eye zFar > zNear > 0"
7180 //<< endl << " float D; // positive near plane offset D >= 0 // for testing"
7181 << endl << " float nD; // zNear + D : shader optimization"
7182 << endl << " float lg_nD; // log2(nD) : shader optimization"
7183 << endl << " float a; // precalculated factor (c-1)/log2(f/(n+D))"
7184 << endl << " float b; // precalculated factor log2(f/(n+D))/(c-1)"
7185 //<< endl << " int c; // number of cluster planes // for testing"
7186 << endl << " int c_1; // number of cluster planes minus one : shader optimization"
7187 << endl << " ivec2 p_v; // viewport corner points"
7188 //<< endl << " ivec3 n_c; // number of clusters // for testing"
7189 << endl << " int t_v; // test dependent content // for testing"
7190 << endl << "} clusteringData;"
7191 << endl << ""
7192 // Debug Test Begin
7193 //<< endl << "//"
7194 //<< endl << "// Pure testing data"
7195 //<< endl << "//"
7196 //<< endl << "layout (std430) buffer TestData"
7197 //<< endl << "{"
7198 //<< endl << " float value01;"
7199 //<< endl << " float value02;"
7200 //<< endl << " float value03;"
7201 //<< endl << " float value04;"
7202 //<< endl << " vec3 value05;"
7203 //<< endl << " vec3 value06;"
7204 //<< endl << " int value07;"
7205 //<< endl << " int value08;"
7206 //<< endl << " uint value09;"
7207 //<< endl << " uint value10;"
7208 //<< endl << " ivec3 value11;"
7209 //<< endl << " uvec3 value12;"
7210 //<< endl << " float value13[" << TestData::num_array_elements << "];"
7211 //<< endl << " float value14[" << TestData::num_array_elements << "];"
7212 //<< endl << " uint value15[" << TestData::num_array_elements << "];"
7213 //<< endl << " vec3 value16[" << TestData::num_array_elements << "];"
7214 //<< endl << " vec3 value17[" << TestData::num_array_elements << "];"
7215 //<< endl << "} testData;"
7216 //<< endl << ""
7217 // Debug Test End
7218 << endl << "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!"
7219 << endl << ""
7220 << endl << "layout(location = 0) out vec4 vFragColor;"
7221 << endl << ""
7222 // Debug Test Begin
7223 //<< endl << "//"
7224 //<< endl << "// Test equality of two vectors with respect to local eps value"
7225 //<< endl << "//"
7226 //<< endl << "bool isEqual(in const vec3 v1, in const vec3 v2)"
7227 //<< endl << "{"
7228 //<< endl << " const float eps = 1.0E-4;"
7229 //<< endl << " if (all(lessThan(abs(v1 -v2), vec3(eps,eps,eps))))"
7230 //<< endl << " return true;"
7231 //<< endl << " else"
7232 //<< endl << " return false;"
7233 //<< endl << "}"
7234 //<< endl << ""
7235 // Debug Test End
7236 << endl << "//"
7237 << endl << "// cluster_k and cluster_k_verbose calculates the cluster key from the eye space z value"
7238 << endl << "// k = cluster_k(z_e, ...) with k in [0, c["
7239 << endl << "//"
7240 << endl << "// Formular:"
7241 << endl << "// k = 0 if z_e >= -(n+D)"
7242 << endl << "// k = 1 + (c-1) * log2(z_e/-(n+D)) / log2(f/(n+D)) else"
7243 << endl << "// k = c-1 if z_e <= -f"
7244 << endl << "//"
7245 // Debug Test Begin
7246 //<< endl << "int cluster_k_verbose("
7247 //<< endl << " in const float z_e, // eye space z-position, z_e < 0"
7248 //<< endl << " in const float n, // near plane distance from viewer n > 0"
7249 //<< endl << " in const float f, // far plane distance from viewer f > n > 0"
7250 //<< endl << " in const float D, // near plane offset"
7251 //<< endl << " in const int c) // number of cluster planes"
7252 //<< endl << "{"
7253 //<< endl << " if (z_e >= -(n+D)) return 0;"
7254 //<< endl << " if (z_e <= -f) return c-1;"
7255 //<< endl << ""
7256 //<< endl << " float s = 1.0+(float(c-1)/log2(f/(n+D)))*log2(z_e/-(n+D));"
7257 //<< endl << " return clamp(int(s), 0, c-1);"
7258 //<< endl << "}"
7259 //<< endl << ""
7260 // Debug Test Begin
7261 << endl << "int cluster_k("
7262 << endl << " in const float z_e, // eye space z-position, z_e < 0"
7263 << endl << " in const float nD, // near plane distance plus the offset D from viewer n > 0, D > 0"
7264 << endl << " in const float lg_nD,// log2(nD)"
7265 << endl << " in const float f, // far plane distance from viewer f > n > 0"
7266 << endl << " in const float a, // (c-1)/log2(f/(n+D))"
7267 << endl << " in const int c_1) // number of cluster planes minus 1"
7268 << endl << "{"
7269 << endl << " if (z_e >= -nD) return 0;"
7270 << endl << " if (z_e <= -f) return c_1;"
7271 << endl << ""
7272 << endl << " float s = 1.0 + a * (log2(-z_e) - lg_nD);"
7273 << endl << " return clamp(int(s), 0, c_1);"
7274 << endl << "}"
7275 << endl << ""
7276 << endl << "//"
7277 << endl << "// OpenGL window space is defined such that pixel centers are on half-integer boundaries."
7278 << endl << "// So the center of the lower-left pixel is (0.5,0.5). Using pixel_center_integer? adjust"
7279 << endl << "// gl_FragCoord such that whole integer values represent pixel centers."
7280 << endl << "// This feature exist to be compatible with D3D's window space. Unless you need your shaders"
7281 << endl << "// to have this compatibility, you are advised not to use these features."
7282 << endl << "// => We do not use it!"
7283 << endl << "//"
7284 << endl << "// Provide a accessor key to probe the light grid."
7285 << endl << "// in p_w : xy-screen position provided by gl_FragCoord.xy: lower-left is (0.5, 0.5)"
7286 << endl << "// in z_e : fragment eye space z from vPositionES"
7287 << endl << "// out : 3D image coordinate"
7288 << endl << "//"
7289 << endl << "ivec3 gridAccessor("
7290 << endl << " in const vec2 p_w, // xy-screen position provided by gl_FragCoord.xy: lower-left is (0.5, 0.5)"
7291 << endl << " in const float z_e) // fragment eye space z from vPositionES"
7292 << endl << "{"
7293 << endl << " ivec2 q_w = ivec2(p_w - vec2(0.5, 0.5));"
7294 << endl << " int k = cluster_k(z_e, clusteringData.nD, clusteringData.lg_nD, clusteringData.zFar, clusteringData.a, clusteringData.c_1);"
7295 << endl << " ivec2 p = (q_w - clusteringData.p_v) / tile_size;"
7296 << endl << " return ivec3(p.xy, k);"
7297 << endl << "}"
7298 << endl << ""
7299 << endl << "//"
7300 << endl << "// Retrieve the cluster light grid data."
7301 << endl << "// in p_w : xy-screen position provided by gl_FragCoord.xy: lower-left is (0.5, 0.5)"
7302 << endl << "// in z_e : fragment eye space z from vPositionES"
7303 << endl << "// out : (light index list start position, number of lights)"
7304 << endl << "//"
7305 << endl << "uvec2 getGridData("
7306 << endl << " in const vec2 p_w,"
7307 << endl << " in const float z_e)"
7308 << endl << "{"
7309 << endl << " ivec3 accessor = gridAccessor(p_w, z_e);"
7310 << endl << " return imageLoad(light_grid, accessor).xy;"
7311 << endl << "}"
7312 << endl << ""
7313 << endl << "//"
7314 << endl << "// Calculate the attenuation of the light based on the light "
7315 << endl << "// range r and the distance d of the light to the current point."
7316 << endl << "//"
7317 << endl << "float calcAttenuation("
7318 << endl << " in const float r,"
7319 << endl << " in const float d)"
7320 << endl << "{"
7321 << endl << " //"
7322 << endl << " // Perform smooth Hermite interpolation between 0 and 1, when e0<x<e1"
7323 << endl << " // float t = clamp((x-e0)/(e1-e0),0.0,1.0);"
7324 << endl << " // smoothstep(e0,e1,x) = t*t*(3-2*t);"
7325 << endl << " //"
7326 << endl << " return 1.0 - smoothstep(0.75 * r, r, d);"
7327 << endl << "}"
7328 << endl << ""
7329 << endl << "//"
7330 << endl << "// Calculate the attenuation with respect to the spot light cone."
7331 << endl << "// Parameters:"
7332 << endl << "// minCosSpotAngle: the cosine of the spot light angle"
7333 << endl << "// l : normalized direction between fragment and light position"
7334 << endl << "// s : normalized light direction"
7335 << endl << "//"
7336 << endl << "float spotAttenuation("
7337 << endl << " in const float minCosSpotAngle,"
7338 << endl << " in const vec3 l,"
7339 << endl << " in const vec3 s)"
7340 << endl << "{"
7341 << endl << " //"
7342 << endl << " // Linear interpolate between x and y using weight a"
7343 << endl << " // mix(x,y,a) = x*(1-a)+y*a"
7344 << endl << " //"
7345 << endl << " float maxCosSpotAngle = mix(minCosSpotAngle, 1.0, 0.5);"
7346 << endl << " float l_dot_s = dot(-l, s);"
7347 << endl << " //"
7348 << endl << " // Perform smooth Hermite interpolation between 0 and 1, when e0<x<e1"
7349 << endl << " // float t = clamp((x-e0)/(e1-e0),0.0,1.0);"
7350 << endl << " // smoothstep(e0,e1,x) = t*t*(3-2*t);"
7351 << endl << " //"
7352 << endl << " return smoothstep(minCosSpotAngle, maxCosSpotAngle, l_dot_s);"
7353 << endl << "}"
7354 << endl << ""
7355 << endl << "//"
7356 << endl << "// cinema (uber) light super ellipses clipping"
7357 << endl << "// Parameters:"
7358 << endl << "// a : inner super ellipses width"
7359 << endl << "// b : inner super ellipses height"
7360 << endl << "// A : outer super ellipses width"
7361 << endl << "// B : outer super ellipses height"
7362 << endl << "// r : roundness parameter"
7363 << endl << "// theta : twist parameter"
7364 << endl << "// pos : fragment position in light space"
7365 << endl << "//"
7366 << endl << "// |x/a|^r + |y/b|^r = 1 <=> a*b*(|b*x|^r + |a*y|^r)^(-1/r) = 1"
7367 << endl << "//"
7368 << endl << "// smoothstep(e0,e1,x)"
7369 << endl << "// Perform smooth Hermite interpolation between 0 and 1, when e0<x<e1"
7370 << endl << "// float t = clamp((x-e0)/(e1-e0),0.0,1.0);"
7371 << endl << "// smoothstep(e0,e1,x) = t*t*(3-2*t);"
7372 << endl << "//"
7373 << endl << "float clipSuperEllipses("
7374 << endl << " in float a,"
7375 << endl << " in float b,"
7376 << endl << " in float A,"
7377 << endl << " in float B,"
7378 << endl << " in float r,"
7379 << endl << " in float theta,"
7380 << endl << " in vec3 pos)"
7381 << endl << "{"
7382 << endl << " float result = 1.0;"
7383 << endl << ""
7384 << endl << " vec2 P = pos.xy / pos.z;"
7385 << endl << " if (all(equal(P, vec2(0.0, 0.0))))"
7386 << endl << " return 1.0;"
7387 << endl << ""
7388 << endl << " float cos_theta = cos(-theta);"
7389 << endl << " float sin_theta = sin(-theta);"
7390 << endl << ""
7391 << endl << " float x = abs(cos_theta * P.x - sin_theta * P.y);"
7392 << endl << " float y = abs(sin_theta * P.x + cos_theta * P.y);"
7393 << endl << ""
7394 << endl << " if (r > 50) // basically a square"
7395 << endl << " {"
7396 << endl << " // Simpler case of a square"
7397 << endl << " result = (1.0 - smoothstep(a, A, x)) * (1.0 - smoothstep(b, B, y));"
7398 << endl << " }"
7399 << endl << " else"
7400 << endl << " {"
7401 << endl << " float q = pow(x/a, r) + pow(y/b, r);"
7402 << endl << " float Q = pow(x/A, r) + pow(y/B, r);"
7403 << endl << ""
7404 << endl << " if (q < 1) return 1.0;"
7405 << endl << " if (Q >= 1) return 0.0;"
7406 << endl << ""
7407 << endl << " result = 1.0 - smoothstep(q, Q, 1.0);"
7408 << endl << " }"
7409 << endl << ""
7410 << endl << " return result;"
7411 << endl << "}"
7412 << endl << ""
7413 << endl << "//"
7414 << endl << "// directional light contribution"
7415 << endl << "//"
7416 << endl << "vec3 directionalLight("
7417 << endl << " in const uint i, // light identifier, i.e. current light"
7418 << endl << " in const uint j, // material identifier"
7419 << endl << " in const vec3 n, // vertex normal in eye space"
7420 << endl << " in const vec3 v) // view direction in eye space"
7421 << endl << "{"
7422 << endl << " if (!lights.light[i].enabled)"
7423 << endl << " return vec3(0.0, 0.0, 0.0);"
7424 << endl << ""
7425 << endl << " //"
7426 << endl << " // Transform the light direction from world space into eye space for further considerations"
7427 << endl << " //"
7428 << endl << " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
7429 << endl << ""
7430 << endl << " vec3 l = -direction.xyz;"
7431 << endl << ""
7432 << endl << " //"
7433 << endl << " // the half vector"
7434 << endl << " //"
7435 << endl << " vec3 h = normalize(l+v);"
7436 << endl << ""
7437 << endl << " float n_dot_l = max(0.0, dot(n, l));"
7438 << endl << " float n_dot_h = max(0.0, dot(n, h));"
7439 << endl << ""
7440 << endl << " float m = materials.material[j].shininess;"
7441 << endl << ""
7442 << endl << " float pf; // power factor"
7443 << endl << ""
7444 << endl << " if (n_dot_l == 0.0)"
7445 << endl << " pf = 0.0;"
7446 << endl << " else"
7447 << endl << " pf = pow(n_dot_h, m);"
7448 << endl << ""
7449 << endl << " vec3 light_intensity = lights.light[i].intensity * lights.light[i].color;"
7450 << endl << ""
7451 << endl << " return materials.material[j].emissive"
7452 << endl << " + light_intensity * materials.material[j].ambient"
7453 << endl << " + light_intensity * materials.material[j].diffuse * n_dot_l"
7454 << endl << " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
7455 << endl << "}"
7456 << endl << ""
7457 << endl << "//"
7458 << endl << "// point light contribution"
7459 << endl << "//"
7460 << endl << "vec3 pointLight("
7461 << endl << " in const uint i, // light identifier, i.e. current light"
7462 << endl << " in const uint j, // material identifier"
7463 << endl << " in const vec3 n, // vertex normal in eye space"
7464 << endl << " in const vec3 v, // view direction in eye space"
7465 << endl << " in const vec3 p) // vertex position in eye space"
7466 << endl << "{"
7467 << endl << " if (!lights.light[i].enabled)"
7468 << endl << " return vec3(0.0, 0.0, 0.0);"
7469 << endl << ""
7470 << endl << " //"
7471 << endl << " // Transform the light position from world space into eye space for further considerations"
7472 << endl << " //"
7473 << endl << " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
7474 << endl << ""
7475 << endl << " vec3 l = position.xyz - p; // dir from surface to light position"
7476 << endl << " float d = length(l); // dist from surface to light source"
7477 << endl << ""
7478 << endl << " if (lights.light[i].range < d)"
7479 << endl << " return vec3(0.0, 0.0, 0.0);"
7480 << endl << ""
7481 << endl << " l = normalize(l); // norm direction from surf to light"
7482 << endl << ""
7483 << endl << " //"
7484 << endl << " // the half vector"
7485 << endl << " //"
7486 << endl << " vec3 h = normalize(l+v);"
7487 << endl << ""
7488 << endl << " float n_dot_l = max(0.0, dot(n, l));"
7489 << endl << " float n_dot_h = max(0.0, dot(n, h));"
7490 << endl << ""
7491 << endl << " float m = materials.material[j].shininess;"
7492 << endl << ""
7493 << endl << " float pf; // power factor"
7494 << endl << ""
7495 << endl << " if (n_dot_l == 0.0)"
7496 << endl << " pf = 0.0;"
7497 << endl << " else"
7498 << endl << " pf = pow(n_dot_h, m);"
7499 << endl << ""
7500 << endl << " float attenuation = calcAttenuation(lights.light[i].range, d);"
7501 << endl << ""
7502 << endl << " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
7503 << endl << ""
7504 << endl << " return materials.material[j].emissive"
7505 << endl << " + light_intensity * materials.material[j].ambient"
7506 << endl << " + light_intensity * materials.material[j].diffuse * n_dot_l"
7507 << endl << " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
7508 << endl << "}"
7509 << endl << ""
7510 << endl << "//"
7511 << endl << "// spot light contribution"
7512 << endl << "//"
7513 << endl << "vec3 spotLight("
7514 << endl << " in const uint i, // light identifier, i.e. current light"
7515 << endl << " in const uint j, // material identifier"
7516 << endl << " in const vec3 n, // vertex normal in eye space"
7517 << endl << " in const vec3 v, // view direction in eye space"
7518 << endl << " in const vec3 p) // vertex position in eye space"
7519 << endl << "{"
7520 << endl << " if (!lights.light[i].enabled)"
7521 << endl << " return vec3(0.0, 0.0, 0.0);"
7522 << endl << ""
7523 << endl << " //"
7524 << endl << " // Transform the light position from world space into eye space for further considerations"
7525 << endl << " //"
7526 << endl << " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
7527 << endl << ""
7528 << endl << " vec3 l = position.xyz - p; // dir from surface to light position"
7529 << endl << " float d = length(l); // dist from surface to light source"
7530 << endl << ""
7531 << endl << " if (lights.light[i].range < d)"
7532 << endl << " return vec3(0.0, 0.0, 0.0);"
7533 << endl << ""
7534 << endl << " l = normalize(l); // norm dir from surface to light"
7535 << endl << ""
7536 << endl << " //"
7537 << endl << " // Transform the light direction from world space into eye space for further considerations"
7538 << endl << " //"
7539 << endl << " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
7540 << endl << ""
7541 << endl << " vec3 s = direction.xyz;"
7542 << endl << " s = normalize(s);"
7543 << endl << ""
7544 << endl << " //"
7545 << endl << " // the half vector"
7546 << endl << " //"
7547 << endl << " vec3 h = normalize(l+v);"
7548 << endl << ""
7549 << endl << " float n_dot_l = max(0.0, dot(n, l));"
7550 << endl << " float n_dot_h = max(0.0, dot(n, h));"
7551 << endl << ""
7552 << endl << " float m = materials.material[j].shininess;"
7553 << endl << ""
7554 << endl << " float pf; // power factor"
7555 << endl << ""
7556 << endl << " if (n_dot_l == 0.0)"
7557 << endl << " pf = 0.0;"
7558 << endl << " else"
7559 << endl << " pf = pow(n_dot_h, m);"
7560 << endl << ""
7561 << endl << " float attenuation = calcAttenuation(lights.light[i].range, d);"
7562 << endl << ""
7563 << endl << " attenuation *= spotAttenuation(lights.light[i].cosSpotlightAngle, l, s);"
7564 << endl << ""
7565 << endl << " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
7566 << endl << ""
7567 << endl << " return materials.material[j].emissive"
7568 << endl << " + light_intensity * materials.material[j].ambient"
7569 << endl << " + light_intensity * materials.material[j].diffuse * n_dot_l"
7570 << endl << " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
7571 << endl << "}"
7572 << endl << ""
7573 << endl << "//"
7574 << endl << "// cinema light contribution"
7575 << endl << "//"
7576 << endl << "vec3 cinemaLight("
7577 << endl << " in const uint i, // light identifier, i.e. current light"
7578 << endl << " in const uint j, // material identifier"
7579 << endl << " in const vec3 n, // vertex normal in eye space"
7580 << endl << " in const vec3 v, // view direction in eye space"
7581 << endl << " in const vec3 p) // vertex position in eye space"
7582 << endl << "{"
7583 << endl << " if (!lights.light[i].enabled)"
7584 << endl << " return vec3(0.0, 0.0, 0.0);"
7585 << endl << ""
7586 << endl << " //"
7587 << endl << " // Transform the light position from world space into eye space for further considerations"
7588 << endl << " //"
7589 << endl << " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
7590 << endl << ""
7591 << endl << " vec3 l = position.xyz - p; // dir from surface to light position"
7592 << endl << " float d = length(l); // dist from surface to light source"
7593 << endl << ""
7594 << endl << " if (lights.light[i].range < d)"
7595 << endl << " return vec3(0.0, 0.0, 0.0);"
7596 << endl << ""
7597 << endl << " l = normalize(l); // norm dir from surface to light"
7598 << endl << ""
7599 << endl << " //"
7600 << endl << " // Transform the light direction from world space into eye space for further considerations"
7601 << endl << " //"
7602 << endl << " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
7603 << endl << ""
7604 << endl << " vec3 s = direction.xyz;"
7605 << endl << " s = normalize(s);"
7606 << endl << ""
7607 << endl << " //"
7608 << endl << " // the half vector"
7609 << endl << " //"
7610 << endl << " vec3 h = normalize(l+v);"
7611 << endl << ""
7612 << endl << " float n_dot_l = max(0.0, dot(n, l));"
7613 << endl << " float n_dot_h = max(0.0, dot(n, h));"
7614 << endl << ""
7615 << endl << " float m = materials.material[j].shininess;"
7616 << endl << ""
7617 << endl << " float pf; // power factor"
7618 << endl << ""
7619 << endl << " if (n_dot_l == 0.0)"
7620 << endl << " pf = 0.0;"
7621 << endl << " else"
7622 << endl << " pf = pow(n_dot_h, m);"
7623 << endl << ""
7624 << endl << " float attenuation = calcAttenuation(lights.light[i].range, d);"
7625 << endl << ""
7626 << endl << " vec3 p_LS = (lights.light[i].eyeToLightSpaceMatrix * vec4(p, 1.0)).xyz;"
7627 << endl << ""
7628 << endl << " attenuation *= clipSuperEllipses("
7629 << endl << " lights.light[i].innerSuperEllipsesWidth,"
7630 << endl << " lights.light[i].innerSuperEllipsesHeight,"
7631 << endl << " lights.light[i].outerSuperEllipsesWidth,"
7632 << endl << " lights.light[i].outerSuperEllipsesHeight,"
7633 << endl << " lights.light[i].superEllipsesRoundness,"
7634 << endl << " lights.light[i].superEllipsesTwist,"
7635 << endl << " p_LS);"
7636 << endl << ""
7637 << endl << " if (p_LS.z > 0.0) attenuation = 0.0;"
7638 << endl << ""
7639 << endl << " attenuation = clamp(attenuation, 0.0, 1.0);"
7640 << endl << ""
7641 << endl << " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
7642 << endl << ""
7643 << endl << " return materials.material[j].emissive"
7644 << endl << " + light_intensity * materials.material[j].ambient"
7645 << endl << " + light_intensity * materials.material[j].diffuse * n_dot_l"
7646 << endl << " + light_intensity * materials.material[j].specular * (m+8)*0.0125 * pf;"
7647 << endl << "}"
7648 << endl << ""
7649 << endl << "void main()"
7650 << endl << "{"
7651 << endl << " //"
7652 << endl << " // normalize the eye space normal"
7653 << endl << " //"
7654 << endl << " int frontCond = -(1 - int(gl_FrontFacing)*2);"
7655 << endl << " vec3 N = frontCond * normalize(vNormalES);"
7656 << endl << ""
7657 << endl << " //"
7658 << endl << " // get the view vector and normalize it"
7659 << endl << " //"
7660 << endl << " vec3 V = normalize(cCameraPositionES - vPositionES);"
7661 << endl << ""
7662 << endl << " //"
7663 << endl << " // Integrate over all lights: Any unused light does not contribute and each light"
7664 << endl << " // contribute either from the directional light, the point light or the spot light."
7665 << endl << " //"
7666 << endl << " vec3 color = vec3(0.0, 0.0, 0.0);"
7667 << endl << ""
7668 //<< endl << " uvec2 grid_data = getGridData(gl_FragCoord.xy, vPositionES.z);"
7669 //<< endl << ""
7670 //<< endl << " uint list_idx = grid_data.x;"
7671 //<< endl << " uint light_count = grid_data.y;"
7672 //<< endl << ""
7673 //<< endl << " if (clusteringData.t_v == 1)"
7674 //<< endl << " light_count = num_lights;"
7675 //<< endl << ""
7677 << endl << " uint list_idx = 0;"
7678 << endl << " uint light_count = 0;"
7679 << endl << ""
7680 << endl << " if (clusteringData.t_v == 0)"
7681 << endl << " {"
7682 << endl << " uvec2 grid_data = getGridData(gl_FragCoord.xy, vPositionES.z);"
7683 << endl << " "
7684 << endl << " list_idx = grid_data.x;"
7685 << endl << " light_count = grid_data.y;"
7686 << endl << " }"
7687 << endl << " else"
7688 << endl << " {"
7689 << endl << " light_count = affectedLightIndexList.idx.length();"
7690 << endl << " }"
7691 << endl << ""
7693 // Debug Test Begin
7695 // Consitency check
7697 //<< endl << " uint num_indices = lightIndexList.idx.length();"
7698 //<< endl << " uint num_lights = lights.light.length();"
7699 //<< endl << ""
7700 //<< endl << " if (num_indices != " << light_index_list_size << ")"
7701 //<< endl << " color = Cyan.xyz;"
7702 //<< endl << ""
7703 //<< endl << " if (list_idx+light_count >= num_indices)" // do not blow up the lightIndexList.idx array
7704 //<< endl << " color = Red.xyz;"
7705 //<< endl << ""
7706 //<< endl << " if (light_count > num_lights)" // do not blow up the lights.light array
7707 //<< endl << " color = Yellow.xyz;"
7708 // Debug Test End
7710 << endl << ""
7711 << endl << " for (uint i = 0; i < light_count; ++i)"
7712 << endl << " {"
7713 << endl << " uint light_idx = (clusteringData.t_v == 0) ? lightIndexList.idx[list_idx+i] : affectedLightIndexList.idx[i];"
7714 << endl << ""
7715 << endl << " switch (lights.light[light_idx].type)"
7716 << endl << " {"
7717 << endl << " case POINT_LIGHT: color += pointLight(light_idx, geom_state.material_index, N, V, vPositionES); break;"
7718 << endl << " case DIRECTIONAL_LIGHT: color += directionalLight(light_idx, geom_state.material_index, N, V); break;"
7719 << endl << " case SPOT_LIGHT: color += spotLight(light_idx, geom_state.material_index, N, V, vPositionES); break;"
7720 << endl << " case CINEMA_LIGHT: color += cinemaLight(light_idx, geom_state.material_index, N, V, vPositionES); break;"
7721 << endl << " }"
7722 << endl << " }"
7723 << endl << ""
7724 << endl << " vFragColor = vec4(color, materials.material[geom_state.material_index].opacity);"
7725 << endl << ""
7726 // Debug Test Begin
7728 // The following test checks if the layout of the cpu and gpu calculated frustums are identical
7730 //<< endl << ""
7731 //<< endl << " if (cpuFrustums.frustum.length() == 0) vFragColor = Red;"
7732 //<< endl << " else if (gpuFrustums.frustum.length() == 0) vFragColor = Green;"
7733 //<< endl << " else if (gpuFrustums.frustum.length() != cpuFrustums.frustum.length()) vFragColor = Blue;"
7734 //<< endl << ""
7737 // The following test is really, really computational intensive. Therefore it is commented and to be used
7738 // only deliberately.
7740 //<< endl << " for (int j = 0; j < cpuFrustums.frustum.length(); ++j)"
7741 //<< endl << " {"
7742 //<< endl << " for (int i = 0; i < 4; ++i)"
7743 //<< endl << " {"
7744 //<< endl << " if (cpuFrustums.frustum[j].planes[i].d != gpuFrustums.frustum[j].planes[i].d) vFragColor = Yellow;"
7745 //<< endl << " else if (!isEqual(cpuFrustums.frustum[j].planes[i].N, gpuFrustums.frustum[j].planes[i].N)) vFragColor = Cyan;"
7746 //<< endl << " }"
7747 //<< endl << " }"
7750 // Test with artificially filled CPU/GPU grid data
7752 //<< endl << " ivec3 accessor = gridAccessor(gl_FragCoord.xy, vPositionES.z);"
7753 //<< endl << ""
7754 //<< endl << " uvec2 data_cpu = imageLoad(light_grid_cpu, accessor).xy;"
7755 //<< endl << " uvec2 data_gpu = imageLoad(light_grid, accessor).xy;"
7756 //<< endl << ""
7757 //<< endl << " uint test_value_x = data_gpu.x - 7345698;"
7758 //<< endl << " uint test_value_y = data_gpu.y - 563472981;"
7759 //<< endl << ""
7760 //<< endl << " uint test_value = test_value_y;"
7761 //<< endl << ""
7762 //<< endl << " if (test_value == 0) vFragColor = HeatMapColor0; // Black"
7763 //<< endl << " if (test_value == 1) vFragColor = HeatMapColor1; // DarkSlateGray"
7764 //<< endl << " if (test_value == 2) vFragColor = HeatMapColor2; // Navy"
7765 //<< endl << " if (test_value == 3) vFragColor = HeatMapColor3; // Blue"
7766 //<< endl << " if (test_value == 4) vFragColor = HeatMapColor4; // RoyalBlue"
7767 //<< endl << " if (test_value == 5) vFragColor = HeatMapColor5; // DodgerBlue"
7768 //<< endl << " if (test_value == 6) vFragColor = HeatMapColor6; // DeepSkyBlue"
7769 //<< endl << " if (test_value == 7) vFragColor = HeatMapColor7; // Turquoise"
7770 //<< endl << " if (test_value == 8) vFragColor = HeatMapColor8; // Aquamarine"
7771 //<< endl << " if (test_value == 9) vFragColor = HeatMapColor9; // Cyan"
7772 //<< endl << " if (test_value == 10) vFragColor = HeatMapColor10; // DarkGreen"
7773 //<< endl << " if (test_value == 11) vFragColor = HeatMapColor11; // Green"
7774 //<< endl << " if (test_value == 12) vFragColor = HeatMapColor12; // SpringGreen"
7775 //<< endl << " if (test_value == 13) vFragColor = HeatMapColor13; // Lime"
7776 //<< endl << " if (test_value == 14) vFragColor = HeatMapColor14; // Chartreuse"
7777 //<< endl << " if (test_value == 15) vFragColor = HeatMapColor15; // GreenYellow"
7778 //<< endl << " if (test_value == 16) vFragColor = HeatMapColor16; // Yellow"
7779 //<< endl << " if (test_value == 17) vFragColor = HeatMapColor17; // Gold"
7780 //<< endl << " if (test_value == 18) vFragColor = HeatMapColor18; // DarkOrange"
7781 //<< endl << " if (test_value == 19) vFragColor = HeatMapColor19; // OrangeRed"
7782 //<< endl << " if (test_value == 20) vFragColor = HeatMapColor20; // Red"
7783 //<< endl << " if (test_value == 21) vFragColor = HeatMapColor21; // FireBrick"
7784 //<< endl << " if (test_value == 22) vFragColor = HeatMapColor22; // DarkRed"
7785 //<< endl << " if (test_value == 23) vFragColor = HeatMapColor23; // BlueViolet"
7786 //<< endl << " if (test_value == 24) vFragColor = HeatMapColor24; // Fuchsia"
7787 //<< endl << " if (test_value == 25) vFragColor = HeatMapColor25; // DeepPink"
7788 //<< endl << " if (test_value == 26) vFragColor = HeatMapColor26; // HotPink"
7789 //<< endl << " if (test_value == 27) vFragColor = HeatMapColor27; // Pink"
7790 //<< endl << " if (test_value == 28) vFragColor = HeatMapColor28; // MistyRose"
7791 //<< endl << " if (test_value == 29) vFragColor = HeatMapColor29; // LavenderBlush"
7792 //<< endl << " if (test_value == 30) vFragColor = HeatMapColor30; // Seashell"
7793 //<< endl << " if (test_value == 31) vFragColor = HeatMapColor31; // White"
7796 // Test LC 4: Check if the CPU light grid is identical to the GPU light grid
7798 //<< endl << " ivec3 accessor = gridAccessor(gl_FragCoord.xy, vPositionES.z);"
7799 //<< endl << ""
7800 //<< endl << " uvec2 data_cpu = imageLoad(light_grid_cpu, accessor).xy;"
7801 //<< endl << " uvec2 data_gpu = imageLoad(light_grid, accessor).xy;"
7802 //<< endl << ""
7803 //<< endl << " if (data_cpu.y != data_gpu.y) vFragColor = SteelBlue;"
7804 //<< endl << ""
7806 //<< endl << " ivec3 accessor = gridAccessor(gl_FragCoord.xy, vPositionES.z);"
7807 //<< endl << ""
7808 //<< endl << " uvec2 data_gpu = imageLoad(light_grid, accessor).xy;"
7809 //<< endl << ""
7810 //<< endl << " uint test_value = data_gpu.y;"
7811 //<< endl << ""
7812 //<< endl << " if (test_value == 0) vFragColor = HeatMapColor0; // Black"
7813 //<< endl << " if (test_value == 1) vFragColor = HeatMapColor1; // DarkSlateGray"
7814 //<< endl << " if (test_value == 2) vFragColor = HeatMapColor2; // Navy"
7815 //<< endl << " if (test_value == 3) vFragColor = HeatMapColor3; // Blue"
7816 //<< endl << " if (test_value == 4) vFragColor = HeatMapColor4; // RoyalBlue"
7817 //<< endl << " if (test_value == 5) vFragColor = HeatMapColor5; // DodgerBlue"
7818 //<< endl << " if (test_value == 6) vFragColor = HeatMapColor6; // DeepSkyBlue"
7819 //<< endl << " if (test_value == 7) vFragColor = HeatMapColor7; // Turquoise"
7820 //<< endl << " if (test_value == 8) vFragColor = HeatMapColor8; // Aquamarine"
7821 //<< endl << " if (test_value == 9) vFragColor = HeatMapColor9; // Cyan"
7822 //<< endl << " if (test_value == 10) vFragColor = HeatMapColor10; // DarkGreen"
7823 //<< endl << " if (test_value == 11) vFragColor = HeatMapColor11; // Green"
7824 //<< endl << " if (test_value == 12) vFragColor = HeatMapColor12; // SpringGreen"
7825 //<< endl << " if (test_value == 13) vFragColor = HeatMapColor13; // Lime"
7826 //<< endl << " if (test_value == 14) vFragColor = HeatMapColor14; // Chartreuse"
7827 //<< endl << " if (test_value == 15) vFragColor = HeatMapColor15; // GreenYellow"
7828 //<< endl << " if (test_value == 16) vFragColor = HeatMapColor16; // Yellow"
7829 //<< endl << " if (test_value == 17) vFragColor = HeatMapColor17; // Gold"
7830 //<< endl << " if (test_value == 18) vFragColor = HeatMapColor18; // DarkOrange"
7831 //<< endl << " if (test_value == 19) vFragColor = HeatMapColor19; // OrangeRed"
7832 //<< endl << " if (test_value == 20) vFragColor = HeatMapColor20; // Red"
7833 //<< endl << " if (test_value == 21) vFragColor = HeatMapColor21; // FireBrick"
7834 //<< endl << " if (test_value == 22) vFragColor = HeatMapColor22; // DarkRed"
7835 //<< endl << " if (test_value == 23) vFragColor = HeatMapColor23; // BlueViolet"
7836 //<< endl << " if (test_value == 24) vFragColor = HeatMapColor24; // Fuchsia"
7837 //<< endl << " if (test_value == 25) vFragColor = HeatMapColor25; // DeepPink"
7838 //<< endl << " if (test_value == 26) vFragColor = HeatMapColor26; // HotPink"
7839 //<< endl << " if (test_value == 27) vFragColor = HeatMapColor27; // Pink"
7840 //<< endl << " if (test_value == 28) vFragColor = HeatMapColor28; // MistyRose"
7841 //<< endl << " if (test_value == 29) vFragColor = HeatMapColor29; // LavenderBlush"
7842 //<< endl << " if (test_value == 30) vFragColor = HeatMapColor30; // Seashell"
7843 //<< endl << " if (test_value == 31) vFragColor = HeatMapColor31; // White"
7844 // Debug Test End
7845 << endl << ""
7846 << endl << "}"
7847 << endl << ""
7848 << endl;
7850 return ost.str();