1 // OpenSG Example: MultiRangeLightClusterShading
3 // This example implements a forward cluster shading algorithm according to
4 // Ola Olsson et.al and Emil Persson
5 // https://newq.net/publications/more/s2015-many-lights-course
7 // It uses the MultiLightChunk for the light representation and 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.
25 // - only tested on decsent NVidia GPUs
26 // - this example is a proof of concept
27 // - this example is not performance optimized
31 // Space : toogle geometry simulation on/off
33 // 2 : half number of lights
34 // 3 : double number of lights
35 // 4 : half number of geometry objects
36 // 5 : double number of geometry objects
37 // a : add directional test lights useful only if the view
38 // frustum is visualized
39 // b : show correct light geometry frustum
40 // c : cull lights on cpu. Only useful for testing
41 // e/E : speed up/down simulation
42 // h : toogle HDR stage usage on/off
43 // i/I : increase/decrease light intensity
44 // l : toogle light simulation on/off
45 // m : assign new color to geometry
46 // o/O : double/half simulation time interval
47 // p/P : increase/decrease light range
48 // r : reset the example
49 // s : toogle statistics on/off
50 // t : toogle usage of cluster shading on/off
51 // u : toggle spot direction line on/off
52 // U : toggle special spot direction cases
53 // v : toogle frustum visualization on/off
54 // x : recreate the lights with current spot dir case
57 #include <boost/functional/hash.hpp>
58 #include <boost/unordered_set.hpp>
59 #include <boost/foreach.hpp>
60 #include <boost/random.hpp>
61 #include <boost/tuple/tuple.hpp>
62 #include "boost/tuple/tuple_comparison.hpp"
63 #include <boost/multi_array.hpp>
65 #ifdef OSG_BUILD_ACTIVE
68 #include <OSGConfig.h>
69 #include <OSGSimpleGeometry.h>
70 #include <OSGGLUTWindow.h>
71 #include <OSGSimpleSceneManager.h>
72 #include <OSGBaseFunctions.h>
73 #include <OSGTransform.h>
80 #include <OSGMatrixCamera.h>
81 #include <OSGPerspectiveCamera.h>
82 #include <OSGOrthographicCamera.h>
83 #include <OSGHDR2Stage.h>
84 #include <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>
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>
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>
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()
283 while (v
.length() < OSG::Eps
)
285 -1.f
+ 2.f
* unit_die(),
286 -1.f
+ 2.f
* unit_die(),
287 -1.f
+ 2.f
* unit_die());
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
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;
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;
322 class SmoothCubicBezierSpline
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;
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;
345 std::vector
<OSG::Pnt3f
> knots
;
346 std::vector
<OSG::Real32
> intervals
;
347 std::vector
<CubicBezierCurve
> curves
;
350 // ============================================================================
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
,
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
384 OSG::Matrix
rotate_a_into_direction_b(OSG::Vec3f a
, OSG::Vec3f b
)
391 OSG::Real32 c
= a
.dot(b
);
392 if (OSG::osgAbs(1.f
- c
) < OSG::Eps
)
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
,
405 OSG::Matrix
T(skew
); T
.mult(skew
); T
.scale(1.f
/ (1.f
+ c
));
407 R
.add(skew
); R
.add(T
);
413 OSG::Matrix rotate_a_into_direction_b(OSG::Vec3f a, OSG::Vec3f b)
420 OSG::Real32 c = a.dot(b);
421 if (OSG::osgAbs(1.f - c) < OSG::Eps)
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,
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);
447 // ============================================================================
449 // Part: Extensions for simple geometry generation
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 )
476 if ( (sides
& 1) == 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
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
)
522 (*pvecCurr
)[i
] = pR
+ r_cone
* OSG::Vec3f(OSG::osgSin(phi
), 0, -OSG::osgCos(phi
));
525 (*pvecCurr
)[sides
-1] = (*pvecCurr
)[0];
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
]);
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
)
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
)
580 (*pvecCurr
)[i
] = pj
+ r_cone
* OSG::Vec3f(OSG::osgSin(phi
), 0, -OSG::osgCos(phi
));
582 OSG::Vec3f n
= (*pvecCurr
)[i
] - pT
;
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
]);
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());
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 )
654 if ( (sides
& 1) == 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
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();
710 OSG::Vec3f v
= p
.subZero();
721 (*pvecCurr
)[sides
-1] = (*pvecCurr
)[0];
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
]);
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
);
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
]);
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
);
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();
828 OSG::Vec3f v
= p
.subZero();
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
]);
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
);
881 t
->push_back(GL_TRIANGLE_FAN
);
882 l
->push_back(1 + sides
);
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
]);
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
);
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());
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();
975 OSG::GeoVec3fPropertyRefPtr normals
= OSG::GeoVec3fProperty::create();
976 OSG::Vec3f v1
, v2
, n
;
979 v1
= nrb
- nlb
; v2
= nlt
- nlb
; n
= v1
.cross(v2
); n
.normalize(); for (int i
= 0; i
< 4; ++i
) normals
->addValue(n
);
982 v1
= flb
- frb
; v2
= frt
- frb
; n
= v1
.cross(v2
); n
.normalize(); for (int i
= 0; i
< 4; ++i
) normals
->addValue(n
);
985 v1
= nlb
- flb
; v2
= flt
- flb
; n
= v1
.cross(v2
); n
.normalize(); for (int i
= 0; i
< 4; ++i
) normals
->addValue(n
);
988 v1
= frb
- nrb
; v2
= nrt
- nrb
; n
= v1
.cross(v2
); n
.normalize(); for (int i
= 0; i
< 4; ++i
) normals
->addValue(n
);
991 v1
= frt
- nrt
; v2
= nlt
- nrt
; n
= v1
.cross(v2
); n
.normalize(); for (int i
= 0; i
< 4; ++i
) normals
->addValue(n
);
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());
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
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
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
)
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
1100 struct ClusteringData
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
)
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
1216 static const OSG::UInt32 num_array_elements
= num_test_val_entries
;
1222 , value05(0.f
,0.f
,0.f
)
1223 , value06(0.f
,0.f
,0.f
)
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
))
1243 value05
= OSG::Vec3f(0.f
,0.f
,0.f
);
1244 value06
= OSG::Vec3f(0.f
,0.f
,0.f
);
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
)
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
;
1270 OSG::UInt32 value09
;
1271 OSG::UInt32 value10
;
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
;
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
;
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
)
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
,
1471 bool allocate_memory
)
1473 OSG::ImageRefPtr image
= OSG::Image::create();
1475 GL_RG
, // pixel format
1476 width
, // width in pixel
1477 height
, // height in pixel
1478 depth
, // depth in pixel
1483 OSG::Image::OSG_UINT32_IMAGEDATA
, // type
1484 allocate_memory
, // allocate memory
1487 return OSG::ImageTransitPtr(image
);
1495 bool allocate_memory
)
1498 GL_RG
, // pixel format
1499 width
, // width in pixel
1500 height
, // height in pixel
1501 depth
, // depth in pixel
1506 OSG::Image::OSG_UINT32_IMAGEDATA
, // type
1507 allocate_memory
, // allocate memory
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(
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
,
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
,
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
;
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.
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
,
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]);
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
),
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]);
1728 2.f
* (p_w
.x() - x_v
) / w
- 1.f
,
1729 2.f
* (p_w
.y() - y_v
) / h
- 1.f
,
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
;
1780 OSG::Pnt3f
EyeFromClip(const OSG::Pnt4f
& p_c
, const OSG::Matrix
& matInvProjection
)
1783 matInvProjection
.mult(p_c
, p_e
);
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
)
1791 matInvProjection
.mult(p_n
, p_e
);
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
);
1802 OSG::MatrixCamera
* matrixCam
= dynamic_cast<OSG::MatrixCamera
*>(cam
);
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
)
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
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
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
)
1988 std::vector
<OSG::UInt8
> buffer
= create_frustum_buffer(vFrustums
);
1989 ssbo
->editMFBuffer()->setValues(buffer
);
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
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
)
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
)
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
)
2084 // The counter compromises exactly one UInt32 element
2086 std::vector
<OSG::UInt8
> buffer(sizeof(OSG::UInt32
) * 1, 0);
2088 ssbo
->editMFBuffer()->setValues(buffer
);
2094 OSG::Pnt3f c
; // Center point.
2095 OSG::Real32 r
; // Radius.
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
)
2122 if (sphere
.c
.z() - sphere
.r
> zNear
|| zFar
> sphere
.c
.z() + sphere
.r
)
2127 for (int i
= 0; i
< 4 && result
; i
++)
2129 if (SphereInsidePlane(sphere
, frustum
.planes
[i
]))
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();
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
2160 return PointInsidePlane(cone
.T
, plane
) && PointInsidePlane(Q
, plane
);
2163 bool ConeInsideFrustum(const Cone
& cone
, const Frustum
& frustum
, OSG::Real32 zNear
, OSG::Real32 zFar
)
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
))
2175 for (int i
= 0; i
< 4 && result
; i
++)
2177 if (ConeInsidePlane(cone
, frustum
.planes
[i
]))
2187 // simple light data structure
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
);
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
)
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
)
2276 , curve(dice_knots(true))
2285 void transformToEyeSpace(
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)
2295 OSG::Matrix matWsFromBS
;
2299 beacon
->getToWorld(matWsFromBS
);
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
)
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
)
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));
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));
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)));
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
);
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
;
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
);
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
);
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
];
2741 case Light::directional_light
:
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
))
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
))
2771 vecAffectedLights
.push_back(OSG::UInt32(i
));
2775 std::size_t frustumAccessor(
2778 const OSG::Vec3u
& dimensions
)
2780 return j
* dimensions
.x() + i
;
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
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
);
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()
2849 //globalTestData.value15[test_idx] = 0;
2851 const Light
& light
= lights
[light_index
];
2857 case Light::directional_light
:
2860 lightIndexList
.push_back(OSG::UInt32(light_index
));
2862 //globalTestData.value15[test_idx] = test_idx;
2865 case Light::point_light
:
2866 case Light::cinema_light
:
2868 if (PointLightInsideFrustum(light
, frustum
, n
, f
))
2871 lightIndexList
.push_back(OSG::UInt32(light_index
));
2873 //globalTestData.value15[test_idx] = test_idx;
2877 case Light::spot_light
:
2879 if (SpotLightInsideFrustum(light
, frustum
, n
, f
))
2882 lightIndexList
.push_back(OSG::UInt32(light_index
));
2884 //globalTestData.value15[test_idx] = test_idx;
2892 write_image_data(i
, j
, k
, dimensions
, std::make_pair(light_start_offset
, light_count
), gridData
);
2900 // Simple material data structure
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
)
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();
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
;
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
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
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
)
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
);
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
)
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
);
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
)
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
);
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;
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
;
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
;
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
;
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();
3403 void setup_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
);
3471 void createHDRStage()
3475 hdr_stage
= OSG::HDR2Stage::create();
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
);
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
);
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
);
3629 void deinitialize_lights()
3631 BOOST_FOREACH(const Light
& light
, lights
)
3633 scene_node
->subChild(light
.beacon
);
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();
3653 type
= Light::point_light
;
3657 type
= Light::spot_light
;
3661 type
= Light::cinema_light
;
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;
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;
3709 Light::dir_test_case_6
+= OSG::Vec3f(0.1f
, 0.f
, 0.f
);
3711 Light::dir_test_case_6
-= OSG::Vec3f(0.1f
, 0.f
, 0.f
);
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;
3730 Light::dir_test_case_7
+= OSG::Vec3f(0.1f
, -0.1f
, 0.f
);
3732 Light::dir_test_case_7
-= OSG::Vec3f(0.1f
, -0.1f
, 0.f
);
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;
3752 Light::dir_test_case_8
+= OSG::Vec3f(0.f
, -0.1f
, 0.1f
);
3754 Light::dir_test_case_8
-= OSG::Vec3f(0.f
, -0.1f
, 0.1f
);
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
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;
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();
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);
3824 l
.spotlightAngle
= spot_die();
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();
3843 l
.superEllipsesRoundness
= light_ellipsis_roundness_die1();
3847 l
.superEllipsesRoundness
= light_ellipsis_roundness_die2();
3851 l
.superEllipsesRoundness
= light_ellipsis_roundness_die3();
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;
3874 void Light::create_light_geometry(OSG::UInt32 material_idx
)
3876 if (!beacon
) return;
3878 beacon
->clearChildren();
3881 mat
.emissive
= color
;
3884 materials
[material_idx
] = mat
;
3886 OSG::ChunkMaterialRefPtr geomState
= OSG::ChunkMaterial::create();
3888 OSG::Real32 R
= range
;
3890 if (!correct_light_geometry
)
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);
3928 case directional_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
3942 OSG::GeometryRefPtr geometry
= makeSpotGeo(h
, spotlightAngle
, 24, 24);
3943 geometry
->setMaterial(geomState
);
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);
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);
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);
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);
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);
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);
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);
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);
3984 //t = rotate_a_into_direction_b(a, b);
3985 //a = OSG::Vec3f(4.f, -2.f, 0.6f); a.normalize();
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
);
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
4037 OSG::GeometryRefPtr geometry
= makeCinemaGeo(
4038 outerSuperEllipsesWidth
,
4039 outerSuperEllipsesHeight
,
4040 superEllipsesRoundness
,
4041 OSG::osgDegree2Rad(superEllipsesTwist
),
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
);
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
);
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
);
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
;
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
);
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
,
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();
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
));
4344 OSG::NodeTransitPtr
createGeometry()
4346 int idx
= geom_idx_die();
4348 OSG::GeometryRefPtr geometry
;
4353 geometry
= OSG::makeConeGeo(3.f
* small_die(), 1.f
* small_die(), 24, true, true);
4356 geometry
= OSG::makeBoxGeo(3.f
* small_die(), 3.f
* small_die(), 3.f
* small_die(), 1, 1, 1);
4359 geometry
= OSG::makeCylinderGeo(3.f
* small_die(), .3f
, 24, true, true, true );
4362 geometry
= OSG::makeSphereGeo(6, 3.f
* small_die());
4365 geometry
= OSG::makeTorusGeo(0.6f
* small_die(), 2.f
* small_die(), 24, 36);
4367 case 5: // ellipsoide
4368 geometry
= OSG::makeLatLongEllipsoidGeo(24, 36, 2.f
* small_die(), 1.f
* small_die());
4371 geometry
= OSG::makeConicalFrustumGeo(2.f
* small_die(), 2.f
* small_die(), 2.f
* small_die(), 6, true, true, true);
4374 geometry
= OSG::makeTeapotGeo(24, 1.f
* small_die());
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
;
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
);
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
[]);
4438 // Initialize GLUT & OpenSG and set up the scene
4440 int main(int argc
, char **argv
)
4443 OSG::osgInit(argc
,argv
);
4446 int winid
= setupGLUT(&argc
, argv
);
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
);
4459 // create the SimpleSceneManager helper
4460 mgr
= OSG::SimpleSceneManager::create();
4461 mgr
->setWindow(gwin
);
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
);
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
);
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();
4611 // show the whole scene
4622 // GLUT callback functions
4626 // redraw the window
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
;
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
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
);
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
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();
4788 // react to size changes
4790 void reshape(int w
, int h
)
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
);
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
)
4907 mgr
->mouseButtonRelease(button
, x
, y
);
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();
4926 void keyboard(unsigned char k
, int x
, int y
)
4932 // clean up global variables
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
;
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
;
4978 geom_trafos
.clear();
4979 geom_curves
.clear();
4981 ubo_geom_states
.clear();
4995 simulate_geometry
= !simulate_geometry
;
4996 std::cout
<< "simulate_geometry = " << simulate_geometry
<< std::endl
;
5002 initialize_lights(1);
5003 update_light_state(multi_light_chunk
, lights
);
5004 update_material_database_state(ssbo_material_database
, materials
);
5005 glutPostRedisplay();
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();
5024 std::cout
<< "minimal number if lights reached!" << std::endl
;
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();
5044 std::cout
<< "maximal number if lights reached!" << std::endl
;
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
);
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();
5073 std::cout
<< "minimal number if geometries reached!" << std::endl
;
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
);
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();
5101 std::cout
<< "maximal number if geometries reached!" << std::endl
;
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();
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();
5135 Light::cpu_cull_lights
= !Light::cpu_cull_lights
;
5136 std::cout
<< "Light::cpu_cull_lights = " << Light::cpu_cull_lights
<< std::endl
;
5142 simulation_delta
*= 2.f
;
5148 simulation_delta
/= 2.f
;
5154 OSG::HDR2Stage
* core
= dynamic_cast<OSG::HDR2Stage
*>(hdr_node
->getCore());
5159 std::cout
<< "HDR is off" << std::endl
;
5165 std::cout
<< "HDR is on" << std::endl
;
5168 glutPostRedisplay();
5174 BOOST_FOREACH(Light
& light
, lights
)
5175 light
.intensity
*= 1.2f
;
5177 update_light_state(multi_light_chunk
, lights
);
5178 glutPostRedisplay();
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();
5195 simulate_lights
= !simulate_lights
;
5196 std::cout
<< "simulate_lights = " << simulate_lights
<< std::endl
;
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();
5214 elapse_time_limit
*= 2.f
;
5220 elapse_time_limit
/= 2.f
;
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();
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();
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();
5277 mgr
->setStatistics(!mgr
->getStatistics());
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
;
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();
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
;
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
);
5346 change_spot_dir_lights();
5347 update_light_state(multi_light_chunk
, lights
);
5348 update_material_database_state(ssbo_material_database
, materials
);
5349 glutPostRedisplay();
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
);
5381 glutReshapeFunc(NULL
);
5382 glutMouseFunc(NULL
);
5383 glutMotionFunc(NULL
);
5384 glutKeyboardFunc(NULL
);
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
;
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
)
5455 p
[0] = rhs
.p
[0]; p
[1] = rhs
.p
[1]; p
[2] = rhs
.p
[2]; p
[3] = rhs
.p
[3];
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();
5482 OSG::Vec3f
CubicBezierCurve::normal(OSG::Real32 t
) const
5484 OSG::Vec3f normal
= binormal(t
);
5485 normal
.crossThis(tangent(t
));
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
)
5501 else if (t
- OSG::Eps
>= 0.f
)
5506 binormal
= fst_derivative(t
);
5507 binormal
.crossThis(sec_derivative(t
));
5508 binormal
.normalize();
5514 OSG::Matrix
CubicBezierCurve::frame(OSG::Real32 t
, bool position_only
) const
5519 OSG::Vec3f P
= (*this)(t
).subZero();
5523 mat
.setTranslate(P
);
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
);
5550 OSG::Real32
CubicBezierCurve::length(OSG::UInt32 numSeg
) const
5552 OSG_ASSERT(numSeg
>= 2);
5554 OSG::Real32 d
= 1.f
/ numSeg
;
5556 OSG::Real32 l
= 0.f
;
5558 OSG::Pnt3f p0
= operator()(0.f
);
5562 OSG::Pnt3f p1
= operator()(t
);
5564 l
+= (p1
- p0
).length();
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
)
5606 OSG_ASSERT(knots
.size() > 3);
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();
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
)
5643 , intervals(rhs
.intervals
)
5644 , curves(rhs
.curves
)
5648 SmoothCubicBezierSpline
& SmoothCubicBezierSpline::operator=(const SmoothCubicBezierSpline
& rhs
)
5653 intervals
= rhs
.intervals
;
5654 curves
= rhs
.curves
;
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
);
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;
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>());
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
)
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
)
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());
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();
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
);
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>());
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
)
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
;
5859 knots
.push_back(knots
.front());
5864 // ============================================================================
5866 // Part: The shader programs
5868 // ============================================================================
5870 std::string
add_test_colors()
5872 using namespace std
;
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"
6090 // compute shader programs.
6092 std::string
get_persp_frustum_cp_program()
6094 using namespace std
;
6098 ost
<< "#version 430 compatibility"
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;"
6104 << endl
<< "const int tile_size = " << tile_size
<< ";"
6106 << endl
<< "layout (std140) uniform DispatchData"
6108 << endl
<< " mat4 matTransf; // inverse projection matrix"
6109 << endl
<< " uvec4 viewport;"
6110 << endl
<< " ivec2 numTiles;"
6111 << endl
<< "} dispatchData;"
6113 << endl
<< "struct Plane"
6115 << endl
<< " vec3 N;"
6116 << endl
<< " float d;"
6119 << endl
<< "struct Frustum"
6121 << endl
<< " Plane planes[4];"
6124 << endl
<< "layout (std430) buffer Frustums"
6126 << endl
<< " Frustum frustum[];"
6127 << endl
<< "} frustums;"
6129 << endl
<< "const vec3 eyePos = vec3(0, 0, 0);"
6131 << endl
<< "Plane computePlane(in const vec3 p0, in const vec3 p1, in const vec3 p2)"
6133 << endl
<< " Plane plane;"
6135 << endl
<< " vec3 v1 = p1 - p0;"
6136 << endl
<< " vec3 v2 = p2 - p0;"
6138 << endl
<< " plane.N = normalize(cross(v1, v2));"
6139 << endl
<< " plane.d = dot(plane.N, p0);"
6141 << endl
<< " return plane;"
6144 << endl
<< "vec4 ndcFromScreen(in const vec3 p_w)"
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!"
6153 << endl
<< "vec3 eyeFromNdc(in vec4 p_n)"
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;"
6160 << endl
<< "void main()"
6162 << endl
<< " vec3 pnts_w[4];"
6163 << endl
<< " vec4 pnts_n[4];"
6164 << endl
<< " vec3 pnts_e[4];"
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;"
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);"
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);"
6194 << endl
<< " for (int i = 0; i < 4; ++i)"
6196 << endl
<< " pnts_n[i] = ndcFromScreen(pnts_w[i]);"
6197 << endl
<< " pnts_e[i] = eyeFromNdc (pnts_n[i]);"
6200 << endl
<< " Frustum frustum;"
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]);"
6207 << endl
<< " if (gl_GlobalInvocationID.x < dispatchData.numTiles.x && gl_GlobalInvocationID.y < dispatchData.numTiles.y)"
6209 << endl
<< " uint idx = gl_GlobalInvocationID.y * dispatchData.numTiles.x + gl_GlobalInvocationID.x;"
6210 << endl
<< " frustums.frustum[idx] = frustum;"
6219 std::string
get_ortho_frustum_cp_program()
6221 using namespace std
;
6225 ost
<< "#version 430 compatibility"
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;"
6231 << endl
<< "const int tile_size = " << tile_size
<< ";"
6233 << endl
<< "layout (std140) uniform DispatchData"
6235 << endl
<< " mat4 matTransf; // inverse projection matrix"
6236 << endl
<< " uvec4 viewport;"
6237 << endl
<< " ivec2 numTiles;"
6238 << endl
<< "} dispatchData;"
6240 << endl
<< "struct Plane"
6242 << endl
<< " vec3 N;"
6243 << endl
<< " float d;"
6246 << endl
<< "struct Frustum"
6248 << endl
<< " Plane planes[4];"
6251 << endl
<< "layout (std430) buffer Frustums"
6253 << endl
<< " Frustum frustum[];"
6254 << endl
<< "} frustums;"
6256 << endl
<< "Plane computePlane(in const vec3 p0, in const vec3 p1, in const vec3 p2)"
6258 << endl
<< " Plane plane;"
6260 << endl
<< " vec3 v1 = p1 - p0;"
6261 << endl
<< " vec3 v2 = p2 - p0;"
6263 << endl
<< " plane.N = normalize(cross(v1, v2));"
6264 << endl
<< " plane.d = dot(plane.N, p0);"
6266 << endl
<< " return plane;"
6269 << endl
<< "vec4 ndcFromScreen(in const vec3 p_w)"
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!"
6278 << endl
<< "vec3 eyeFromNdc(in vec4 p_n)"
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;"
6285 << endl
<< "void main()"
6287 << endl
<< " vec3 pnts_w[8];"
6288 << endl
<< " vec4 pnts_n[8];"
6289 << endl
<< " vec3 pnts_e[8];"
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;"
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);"
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);"
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);"
6324 << endl
<< " for (int i = 0; i < 8; ++i)"
6326 << endl
<< " pnts_n[i] = ndcFromScreen(pnts_w[i]);"
6327 << endl
<< " pnts_e[i] = eyeFromNdc (pnts_n[i]);"
6330 << endl
<< " Frustum frustum;"
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]);"
6337 << endl
<< " if (gl_GlobalInvocationID.x < dispatchData.numTiles.x && gl_GlobalInvocationID.y < dispatchData.numTiles.y)"
6339 << endl
<< " uint idx = gl_GlobalInvocationID.y * dispatchData.numTiles.x + gl_GlobalInvocationID.x;"
6340 << endl
<< " frustums.frustum[idx] = frustum;"
6349 std::string
get_light_culling_cp_program()
6351 using namespace std
;
6355 ost
<< "#version 430 compatibility"
6357 << endl
<< "#extension GL_ARB_shader_image_load_store: enable"
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;"
6363 << add_test_colors()
6365 << endl
<< "const int tile_size = " << tile_size
<< ";"
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;"
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"
6380 << endl
<< "layout(binding = 0, rg32ui) uniform uimage2DArray light_grid;"
6383 << endl
<< "// We need access to the lights shape and position data"
6385 << endl
<< "struct Light"
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"
6405 << endl
<< "layout (std430) buffer Lights"
6407 << endl
<< " Light light[];"
6408 << endl
<< "} lights;"
6411 << endl
<< "// Miscellaneous data that are needed for the task at hand"
6413 << endl
<< "layout (std140) uniform DispatchData"
6415 << endl
<< " mat4 matTransf; // world to view matrix"
6416 << endl
<< " uvec4 viewport;"
6417 << endl
<< " ivec2 numTiles;"
6418 << endl
<< "} dispatchData;"
6421 << endl
<< "// The data we need to calc the cluster depth values from the cluster key k"
6423 << endl
<< "layout (std140) uniform ClusteringData"
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;"
6441 //<< endl << "// Pure testing data"
6443 //<< endl << "layout (std430) buffer TestData"
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;"
6466 << endl
<< "// A simple Plane abstraction"
6468 << endl
<< "struct Plane"
6470 << endl
<< " vec3 N;"
6471 << endl
<< " float d;"
6475 << endl
<< "// The 4 planes of the tile frustum"
6477 << endl
<< "struct Frustum"
6479 << endl
<< " Plane planes[4];"
6483 << endl
<< "// A simple Sphere abstraction"
6485 << endl
<< "struct Sphere"
6487 << endl
<< " vec3 c; // Center point."
6488 << endl
<< " float r; // Radius."
6492 << endl
<< "// A simple Cone abstraction"
6494 << endl
<< "struct Cone"
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."
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:"
6507 << endl
<< "// idx = j * numHorizontalTiles + i"
6508 << endl
<< "// idx = gl_WorkGroupID.y * dispatchData.numTiles.x + gl_WorkGroupID.x"
6510 << endl
<< "layout (std430) buffer Frustums"
6512 << endl
<< " Frustum frustum[];"
6513 << endl
<< "} frustums;"
6516 //<< endl << "layout (std430) buffer CPUFrustums"
6518 //<< endl << " Frustum frustum[];"
6519 //<< endl << "} cpuFrustums;"
6523 << endl
<< "// The affected light index list that is iterated to get the light"
6525 << endl
<< "layout (std430) buffer AffectedLightIndexList"
6527 << endl
<< " uint idx[];"
6528 << endl
<< "} affectedLightIndexList;"
6531 << endl
<< "// The global light index list that is to be written by this shader"
6533 << endl
<< "layout (std430) buffer LightIndexList"
6535 << endl
<< " uint idx[];"
6536 << endl
<< "} lightIndexList;"
6539 << endl
<< "// The global light index list that is to be written by this shader"
6541 << endl
<< "layout (std430) buffer LightIndexCounter"
6543 << endl
<< " uint lightIndexCounter;"
6547 << endl
<< "// Per work group shared state"
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];"
6555 //<< endl << "shared uint sharedTestValue;"
6557 //<< endl << "const float eps = 1.0E-4;"
6559 //<< endl << "bool isEqual(in const vec3 v1, in const vec3 v2)"
6561 //<< endl << " if (all(lessThan(abs(v1-v2), vec3(eps,eps,eps))))"
6562 //<< endl << " return true;"
6563 //<< endl << " else"
6564 //<< endl << " return false;"
6567 //<< endl << "bool isEqual(in const float v1, in const float v2)"
6569 //<< endl << " if (abs(v1-v2) < eps)"
6570 //<< endl << " return true;"
6571 //<< endl << " else"
6572 //<< endl << " return false;"
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]"
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"
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"
6593 //<< endl << " if (k == 0) return -n;"
6594 //<< endl << " if (k > c-1) return -f;"
6596 //<< endl << " float z_e = -(n+D) * exp2(float(k-1) * (log2(f/(n+D))/float(c-1)));"
6597 //<< endl << " return z_e;"
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"
6609 << endl
<< " if (k == 0) return -n;"
6610 << endl
<< " if (k > c_1) return -f;"
6612 << endl
<< " float z_e = -nD * exp2(float(k-1) * b);"
6613 << endl
<< " return z_e;"
6617 << endl
<< "// Check to see if a sphere is fully behind (inside the negative halfspace of) a plane."
6619 << endl
<< "bool sphereInsidePlane("
6620 << endl
<< " in const Sphere sphere,"
6621 << endl
<< " in const Plane plane)"
6623 << endl
<< " float val = dot(plane.N, sphere.c) - plane.d;"
6624 << endl
<< " return val < -sphere.r;"
6628 << endl
<< "// Check to see of a light is partially contained within the frustum."
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)"
6636 << endl
<< " bool result = true;"
6638 << endl
<< " if (sphere.c.z - sphere.r > zNear || zFar > sphere.c.z + sphere.r)"
6640 << endl
<< " result = false;"
6643 << endl
<< " for (int i = 0; i < 4 && result; i++)"
6645 << endl
<< " if (sphereInsidePlane(sphere, frustum.planes[i]))"
6647 << endl
<< " result = false;"
6651 << endl
<< " return result;"
6655 << endl
<< "// Check to see if a point is fully behind (inside the negative halfspace of) a plane."
6657 << endl
<< "bool pointInsidePlane("
6658 << endl
<< " in const vec3 p,"
6659 << endl
<< " in const Plane plane)"
6661 << endl
<< " float val = dot(plane.N, p) - plane.d;"
6662 << endl
<< " return val < 0;"
6666 << endl
<< "// Check to see if a cone if fully behind (inside the negative halfspace of) a plane."
6668 << endl
<< "bool coneInsidePlane("
6669 << endl
<< " in const Cone cone,"
6670 << endl
<< " in const Plane plane)"
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;"
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);"
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)"
6689 << endl
<< " bool result = true;"
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;"
6694 << endl
<< " if (coneInsidePlane(cone, nearPlane) || coneInsidePlane(cone, farPlane))"
6696 << endl
<< " result = false;"
6699 << endl
<< " for (int i = 0; i < 4 && result; i++)"
6701 << endl
<< " if (coneInsidePlane(cone, frustum.planes[i]))"
6703 << endl
<< " result = false;"
6707 << endl
<< " return result;"
6711 << endl
<< "// Helper function that provides the cluster index (ivec3) of the current work group invocation"
6713 << endl
<< "ivec3 clusterAccessor()"
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);"
6723 << endl
<< "// Helper function that provides the tile frustum index of the current cluster"
6725 << endl
<< "int frustumAccessor()"
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);"
6735 << endl
<< "// Helper function that provides the tile frustum index of the current cluster"
6737 << endl
<< "vec2 getClusterDepth()"
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));"
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));"
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."
6752 << endl
<< "void appendLight(in const uint light_idx)"
6754 << endl
<< " uint idx = atomicAdd(sharedLightCount, 1);"
6755 << endl
<< " if (idx < 1024)"
6757 << endl
<< " sharedLightIndexList[idx] = light_idx;"
6761 << endl
<< "void main()"
6764 << endl
<< " // Initialize the work group shared state: Only the first thread is needed for that"
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
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)"
6777 << endl
<< " sharedFrustum = frustums.frustum[frustumAccessor()];"
6778 << endl
<< " sharedFrustumZ = getClusterDepth();"
6779 << endl
<< " sharedLightCount = 0;"
6781 // << endl << " sharedTestValue = 0;"
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"
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.
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."
6819 << endl
<< " for (uint i = gl_LocalInvocationIndex; i < affectedLightIndexList.idx.length(); i += gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z)"
6821 << endl
<< " uint light_index = affectedLightIndexList.idx[i];"
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);"
6829 << endl
<< " if (lights.light[light_index].enabled)"
6831 << endl
<< " Light light = lights.light[light_index];"
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;"
6839 << endl
<< " switch (light.type)"
6841 << endl
<< " case DIRECTIONAL_LIGHT:"
6843 << endl
<< " appendLight(light_index);"
6845 //<< endl << " if (test_idx != testData.value15[test_idx])"
6846 //<< endl << " atomicAdd(sharedTestValue, 1);"
6849 << endl
<< " break;"
6851 << endl
<< " case POINT_LIGHT:"
6852 << endl
<< " case CINEMA_LIGHT:"
6854 << endl
<< " vec4 position = dispatchData.matTransf * vec4(light.position, 1.0);"
6856 //<< endl << " if (!isEqual(position.xyz, testData.value16[light_index]))"
6857 //<< endl << " atomicAdd(sharedTestValue, 1);"
6860 << endl
<< " Sphere sphere = { position.xyz, light.range };"
6862 << endl
<< " if (sphereInsideFrustum(sphere, sharedFrustum, sharedFrustumZ.x, sharedFrustumZ.y))"
6864 << endl
<< " appendLight(light_index);"
6866 //<< endl << " if (test_idx != testData.value15[test_idx])"
6867 //<< endl << " atomicAdd(sharedTestValue, 1);"
6871 << endl
<< " break;"
6873 << endl
<< " case SPOT_LIGHT:"
6875 << endl
<< " vec4 position = dispatchData.matTransf * vec4(light.position, 1.0);"
6876 << endl
<< " vec4 direction = dispatchData.matTransf * vec4(light.direction, 0.0);"
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);"
6884 << endl
<< " float radius = tan(light.spotlightAngle) * light.range;"
6885 << endl
<< " Cone cone = { position.xyz, light.range, direction.xyz, radius };"
6887 << endl
<< " if (coneInsideFrustum(cone, sharedFrustum, sharedFrustumZ.x, sharedFrustumZ.y))"
6889 << endl
<< " appendLight(light_index);"
6891 //<< endl << " if (test_idx != testData.value15[test_idx])"
6892 //<< endl << " atomicAdd(sharedTestValue, 1);"
6896 << endl
<< " break;"
6902 << endl
<< " // Wait till all threads in group have caught up."
6904 << endl
<< " memoryBarrierShared(); // Ensure change to sharedXXX is visible in other invocations"
6905 << endl
<< " barrier(); // Stall until every thread reaches this point"
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."
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"
6924 << endl
<< " if (gl_LocalInvocationIndex == 0)"
6926 << endl
<< " sharedLightStartOffset = atomicAdd(lightIndexCounter, sharedLightCount);"
6928 << endl
<< " uvec4 data = uvec4(sharedLightStartOffset, sharedLightCount, 0, 0);"
6931 << endl
<< " // We must protect from overflow"
6933 << endl
<< " uint num_indices = lightIndexList.idx.length();"
6934 << endl
<< " if (sharedLightStartOffset + sharedLightCount >= num_indices)"
6935 << endl
<< " data = uvec4(0,0,0,0);"
6937 << endl
<< " imageStore(light_grid, clusterAccessor(), data);"
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;"
6947 //<< endl << " for (int j = 0; j < cpuFrustums.frustum.length(); ++j)"
6949 //<< endl << " for (int i = 0; i < 4; ++i)"
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;"
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)"
6971 //<< endl << " light_start_offset = 7345698 + uiHeatMapColor13;"
6972 //<< endl << " light_count = 563472981 + gl_WorkGroupID.z;"
6974 //<< endl << " else if (gl_WorkGroupID.x == gl_NumWorkGroups.x-1 && gl_WorkGroupID.y == gl_NumWorkGroups.y-1)"
6976 //<< endl << " light_start_offset = 7345698 + uiHeatMapColor13;"
6977 //<< endl << " light_count = 563472981 + uiHeatMapColor8;"
6979 //<< endl << " else"
6981 //<< endl << " light_start_offset = 7345698 + uiHeatMapColor13;"
6982 //<< endl << " light_count = 563472981 + gl_WorkGroupID.z;"
6984 //<< endl << " uvec4 data = uvec4(light_start_offset, light_count, 0, 0);"
6985 //<< endl << " imageStore(light_grid, clusterAccessor(), data);"
6989 << endl
<< " memoryBarrierShared(); // Ensure change to sharedXXX is visible in other invocations"
6990 << endl
<< " barrier(); // Stall until every thread reaches this point"
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."
7000 << endl
<< " uint num_indices = lightIndexList.idx.length();"
7002 << endl
<< " for (uint i = gl_LocalInvocationIndex; i < sharedLightCount; i += gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z)"
7004 << endl
<< " if (sharedLightStartOffset + i < num_indices)"
7005 << endl
<< " lightIndexList.idx[sharedLightStartOffset + i] = sharedLightIndexList[i];"
7015 // vertex shader program.
7017 std::string
get_vp_program()
7019 using namespace std
;
7023 ost
<< "#version 440 compatibility"
7025 << endl
<< "#extension GL_ARB_separate_shader_objects: enable"
7026 << endl
<< "#extension GL_ARB_shader_storage_buffer_object: enable"
7028 << endl
<< "smooth out vec3 vNormalES; // eye space normal"
7029 << endl
<< "smooth out vec3 vPositionES; // eye space position"
7031 << endl
<< "void main()"
7034 << endl
<< " // multiply the object space vertex position with the modelview matrix "
7035 << endl
<< " // to get the eye space vertex position"
7037 << endl
<< " vPositionES = (gl_ModelViewMatrix * gl_Vertex).xyz;"
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"
7043 << endl
<< " vNormalES = gl_NormalMatrix * gl_Normal;"
7046 << endl
<< " // multiply the combiend modelview projection matrix with the object space vertex"
7047 << endl
<< " // position to get the clip space position"
7049 << endl
<< " gl_Position = ftransform();"
7058 // fragment shader program for bump mapping in surface local coordinates
7060 std::string
get_fp_program()
7062 using namespace std
;
7067 << "#version 440 compatibility"
7069 << endl
<< "#extension GL_ARB_shader_storage_buffer_object: enable"
7070 << endl
<< "#extension GL_ARB_shader_image_load_store: enable"
7072 << endl
<< "smooth in vec3 vNormalES; // eye space normal"
7073 << endl
<< "smooth in vec3 vPositionES; // eye space position"
7075 << add_test_colors()
7077 << endl
<< "const int num_materials = " << num_materials
<< ";"
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;"
7084 << endl
<< "const int tile_size = " << tile_size
<< ";"
7086 << endl
<< "uniform mat4 OSGViewMatrix; // from world space to view space transformation"
7088 << endl
<< "layout(binding = 0, rg32ui) uniform uimage2DArray light_grid;"
7090 //<< endl << "layout(binding = 1, rg32ui) uniform uimage2DArray light_grid_cpu;"
7093 << endl
<< "struct Light"
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"
7113 << endl
<< "layout (std430) buffer Lights"
7115 << endl
<< " Light light[];"
7116 << endl
<< "} lights;"
7119 << endl
<< "// The affected light index list that is iterated to get the light"
7121 << endl
<< "layout (std430) buffer AffectedLightIndexList"
7123 << endl
<< " uint idx[];"
7124 << endl
<< "} affectedLightIndexList;"
7126 << endl
<< "layout (std430) buffer LightIndexList"
7128 << endl
<< " uint idx[];"
7129 << endl
<< "} lightIndexList;"
7131 << endl
<< "struct Material"
7133 << endl
<< " vec3 ambient;"
7134 << endl
<< " vec3 diffuse;"
7135 << endl
<< " vec3 specular;"
7136 << endl
<< " vec3 emissive;"
7138 << endl
<< " float opacity;"
7139 << endl
<< " float shininess;"
7142 << endl
<< "layout (std430) buffer Materials"
7144 << endl
<< " Material material[num_materials];"
7145 << endl
<< "} materials;"
7148 << endl
<< "layout (std140) uniform GeomState"
7150 << endl
<< " uint material_index;"
7151 << endl
<< "} geom_state;"
7153 << endl
<< "struct Plane"
7155 << endl
<< " vec3 N;"
7156 << endl
<< " float d;"
7159 << endl
<< "struct Frustum"
7161 << endl
<< " Plane planes[4];"
7164 << endl
<< "layout (std430) buffer Frustums"
7166 << endl
<< " Frustum frustum[];"
7167 << endl
<< "} frustums;"
7170 //<< endl << "layout (std430) buffer CPUFrustums"
7172 //<< endl << " Frustum frustum[];"
7173 //<< endl << "} cpuFrustums;"
7176 << endl
<< "layout (std140) uniform ClusteringData"
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;"
7194 //<< endl << "// Pure testing data"
7196 //<< endl << "layout (std430) buffer TestData"
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;"
7218 << endl
<< "const vec3 cCameraPositionES = vec3(0,0,0); // eye is at vec3(0,0,0) in eye space!"
7220 << endl
<< "layout(location = 0) out vec4 vFragColor;"
7224 //<< endl << "// Test equality of two vectors with respect to local eps value"
7226 //<< endl << "bool isEqual(in const vec3 v1, in const vec3 v2)"
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;"
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["
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"
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"
7253 //<< endl << " if (z_e >= -(n+D)) return 0;"
7254 //<< endl << " if (z_e <= -f) return c-1;"
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);"
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"
7269 << endl
<< " if (z_e >= -nD) return 0;"
7270 << endl
<< " if (z_e <= -f) return c_1;"
7272 << endl
<< " float s = 1.0 + a * (log2(-z_e) - lg_nD);"
7273 << endl
<< " return clamp(int(s), 0, c_1);"
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!"
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"
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"
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);"
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)"
7305 << endl
<< "uvec2 getGridData("
7306 << endl
<< " in const vec2 p_w,"
7307 << endl
<< " in const float z_e)"
7309 << endl
<< " ivec3 accessor = gridAccessor(p_w, z_e);"
7310 << endl
<< " return imageLoad(light_grid, accessor).xy;"
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."
7317 << endl
<< "float calcAttenuation("
7318 << endl
<< " in const float r,"
7319 << endl
<< " in const float d)"
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);"
7326 << endl
<< " return 1.0 - smoothstep(0.75 * r, r, d);"
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"
7336 << endl
<< "float spotAttenuation("
7337 << endl
<< " in const float minCosSpotAngle,"
7338 << endl
<< " in const vec3 l,"
7339 << endl
<< " in const vec3 s)"
7342 << endl
<< " // Linear interpolate between x and y using weight a"
7343 << endl
<< " // mix(x,y,a) = x*(1-a)+y*a"
7345 << endl
<< " float maxCosSpotAngle = mix(minCosSpotAngle, 1.0, 0.5);"
7346 << endl
<< " float l_dot_s = dot(-l, s);"
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);"
7352 << endl
<< " return smoothstep(minCosSpotAngle, maxCosSpotAngle, l_dot_s);"
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"
7366 << endl
<< "// |x/a|^r + |y/b|^r = 1 <=> a*b*(|b*x|^r + |a*y|^r)^(-1/r) = 1"
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);"
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)"
7382 << endl
<< " float result = 1.0;"
7384 << endl
<< " vec2 P = pos.xy / pos.z;"
7385 << endl
<< " if (all(equal(P, vec2(0.0, 0.0))))"
7386 << endl
<< " return 1.0;"
7388 << endl
<< " float cos_theta = cos(-theta);"
7389 << endl
<< " float sin_theta = sin(-theta);"
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);"
7394 << endl
<< " if (r > 50) // basically a square"
7396 << endl
<< " // Simpler case of a square"
7397 << endl
<< " result = (1.0 - smoothstep(a, A, x)) * (1.0 - smoothstep(b, B, y));"
7401 << endl
<< " float q = pow(x/a, r) + pow(y/b, r);"
7402 << endl
<< " float Q = pow(x/A, r) + pow(y/B, r);"
7404 << endl
<< " if (q < 1) return 1.0;"
7405 << endl
<< " if (Q >= 1) return 0.0;"
7407 << endl
<< " result = 1.0 - smoothstep(q, Q, 1.0);"
7410 << endl
<< " return result;"
7414 << endl
<< "// directional light contribution"
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"
7422 << endl
<< " if (!lights.light[i].enabled)"
7423 << endl
<< " return vec3(0.0, 0.0, 0.0);"
7426 << endl
<< " // Transform the light direction from world space into eye space for further considerations"
7428 << endl
<< " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
7430 << endl
<< " vec3 l = -direction.xyz;"
7433 << endl
<< " // the half vector"
7435 << endl
<< " vec3 h = normalize(l+v);"
7437 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
7438 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
7440 << endl
<< " float m = materials.material[j].shininess;"
7442 << endl
<< " float pf; // power factor"
7444 << endl
<< " if (n_dot_l == 0.0)"
7445 << endl
<< " pf = 0.0;"
7447 << endl
<< " pf = pow(n_dot_h, m);"
7449 << endl
<< " vec3 light_intensity = lights.light[i].intensity * lights.light[i].color;"
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;"
7458 << endl
<< "// point light contribution"
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"
7467 << endl
<< " if (!lights.light[i].enabled)"
7468 << endl
<< " return vec3(0.0, 0.0, 0.0);"
7471 << endl
<< " // Transform the light position from world space into eye space for further considerations"
7473 << endl
<< " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
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"
7478 << endl
<< " if (lights.light[i].range < d)"
7479 << endl
<< " return vec3(0.0, 0.0, 0.0);"
7481 << endl
<< " l = normalize(l); // norm direction from surf to light"
7484 << endl
<< " // the half vector"
7486 << endl
<< " vec3 h = normalize(l+v);"
7488 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
7489 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
7491 << endl
<< " float m = materials.material[j].shininess;"
7493 << endl
<< " float pf; // power factor"
7495 << endl
<< " if (n_dot_l == 0.0)"
7496 << endl
<< " pf = 0.0;"
7498 << endl
<< " pf = pow(n_dot_h, m);"
7500 << endl
<< " float attenuation = calcAttenuation(lights.light[i].range, d);"
7502 << endl
<< " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
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;"
7511 << endl
<< "// spot light contribution"
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"
7520 << endl
<< " if (!lights.light[i].enabled)"
7521 << endl
<< " return vec3(0.0, 0.0, 0.0);"
7524 << endl
<< " // Transform the light position from world space into eye space for further considerations"
7526 << endl
<< " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
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"
7531 << endl
<< " if (lights.light[i].range < d)"
7532 << endl
<< " return vec3(0.0, 0.0, 0.0);"
7534 << endl
<< " l = normalize(l); // norm dir from surface to light"
7537 << endl
<< " // Transform the light direction from world space into eye space for further considerations"
7539 << endl
<< " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
7541 << endl
<< " vec3 s = direction.xyz;"
7542 << endl
<< " s = normalize(s);"
7545 << endl
<< " // the half vector"
7547 << endl
<< " vec3 h = normalize(l+v);"
7549 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
7550 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
7552 << endl
<< " float m = materials.material[j].shininess;"
7554 << endl
<< " float pf; // power factor"
7556 << endl
<< " if (n_dot_l == 0.0)"
7557 << endl
<< " pf = 0.0;"
7559 << endl
<< " pf = pow(n_dot_h, m);"
7561 << endl
<< " float attenuation = calcAttenuation(lights.light[i].range, d);"
7563 << endl
<< " attenuation *= spotAttenuation(lights.light[i].cosSpotlightAngle, l, s);"
7565 << endl
<< " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
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;"
7574 << endl
<< "// cinema light contribution"
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"
7583 << endl
<< " if (!lights.light[i].enabled)"
7584 << endl
<< " return vec3(0.0, 0.0, 0.0);"
7587 << endl
<< " // Transform the light position from world space into eye space for further considerations"
7589 << endl
<< " vec4 position = OSGViewMatrix * vec4(lights.light[i].position, 1.0);"
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"
7594 << endl
<< " if (lights.light[i].range < d)"
7595 << endl
<< " return vec3(0.0, 0.0, 0.0);"
7597 << endl
<< " l = normalize(l); // norm dir from surface to light"
7600 << endl
<< " // Transform the light direction from world space into eye space for further considerations"
7602 << endl
<< " vec4 direction = OSGViewMatrix * vec4(lights.light[i].direction, 0.0);"
7604 << endl
<< " vec3 s = direction.xyz;"
7605 << endl
<< " s = normalize(s);"
7608 << endl
<< " // the half vector"
7610 << endl
<< " vec3 h = normalize(l+v);"
7612 << endl
<< " float n_dot_l = max(0.0, dot(n, l));"
7613 << endl
<< " float n_dot_h = max(0.0, dot(n, h));"
7615 << endl
<< " float m = materials.material[j].shininess;"
7617 << endl
<< " float pf; // power factor"
7619 << endl
<< " if (n_dot_l == 0.0)"
7620 << endl
<< " pf = 0.0;"
7622 << endl
<< " pf = pow(n_dot_h, m);"
7624 << endl
<< " float attenuation = calcAttenuation(lights.light[i].range, d);"
7626 << endl
<< " vec3 p_LS = (lights.light[i].eyeToLightSpaceMatrix * vec4(p, 1.0)).xyz;"
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);"
7637 << endl
<< " if (p_LS.z > 0.0) attenuation = 0.0;"
7639 << endl
<< " attenuation = clamp(attenuation, 0.0, 1.0);"
7641 << endl
<< " vec3 light_intensity = attenuation * lights.light[i].intensity * lights.light[i].color;"
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;"
7649 << endl
<< "void main()"
7652 << endl
<< " // normalize the eye space normal"
7654 << endl
<< " int frontCond = -(1 - int(gl_FrontFacing)*2);"
7655 << endl
<< " vec3 N = frontCond * normalize(vNormalES);"
7658 << endl
<< " // get the view vector and normalize it"
7660 << endl
<< " vec3 V = normalize(cCameraPositionES - vPositionES);"
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."
7666 << endl
<< " vec3 color = vec3(0.0, 0.0, 0.0);"
7668 //<< endl << " uvec2 grid_data = getGridData(gl_FragCoord.xy, vPositionES.z);"
7670 //<< endl << " uint list_idx = grid_data.x;"
7671 //<< endl << " uint light_count = grid_data.y;"
7673 //<< endl << " if (clusteringData.t_v == 1)"
7674 //<< endl << " light_count = num_lights;"
7677 << endl
<< " uint list_idx = 0;"
7678 << endl
<< " uint light_count = 0;"
7680 << endl
<< " if (clusteringData.t_v == 0)"
7682 << endl
<< " uvec2 grid_data = getGridData(gl_FragCoord.xy, vPositionES.z);"
7684 << endl
<< " list_idx = grid_data.x;"
7685 << endl
<< " light_count = grid_data.y;"
7689 << endl
<< " light_count = affectedLightIndexList.idx.length();"
7697 //<< endl << " uint num_indices = lightIndexList.idx.length();"
7698 //<< endl << " uint num_lights = lights.light.length();"
7700 //<< endl << " if (num_indices != " << light_index_list_size << ")"
7701 //<< endl << " color = Cyan.xyz;"
7703 //<< endl << " if (list_idx+light_count >= num_indices)" // do not blow up the lightIndexList.idx array
7704 //<< endl << " color = Red.xyz;"
7706 //<< endl << " if (light_count > num_lights)" // do not blow up the lights.light array
7707 //<< endl << " color = Yellow.xyz;"
7711 << endl
<< " for (uint i = 0; i < light_count; ++i)"
7713 << endl
<< " uint light_idx = (clusteringData.t_v == 0) ? lightIndexList.idx[list_idx+i] : affectedLightIndexList.idx[i];"
7715 << endl
<< " switch (lights.light[light_idx].type)"
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;"
7724 << endl
<< " vFragColor = vec4(color, materials.material[geom_state.material_index].opacity);"
7728 // The following test checks if the layout of the cpu and gpu calculated frustums are identical
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;"
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)"
7742 //<< endl << " for (int i = 0; i < 4; ++i)"
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;"
7750 // Test with artificially filled CPU/GPU grid data
7752 //<< endl << " ivec3 accessor = gridAccessor(gl_FragCoord.xy, vPositionES.z);"
7754 //<< endl << " uvec2 data_cpu = imageLoad(light_grid_cpu, accessor).xy;"
7755 //<< endl << " uvec2 data_gpu = imageLoad(light_grid, accessor).xy;"
7757 //<< endl << " uint test_value_x = data_gpu.x - 7345698;"
7758 //<< endl << " uint test_value_y = data_gpu.y - 563472981;"
7760 //<< endl << " uint test_value = test_value_y;"
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);"
7800 //<< endl << " uvec2 data_cpu = imageLoad(light_grid_cpu, accessor).xy;"
7801 //<< endl << " uvec2 data_gpu = imageLoad(light_grid, accessor).xy;"
7803 //<< endl << " if (data_cpu.y != data_gpu.y) vFragColor = SteelBlue;"
7806 //<< endl << " ivec3 accessor = gridAccessor(gl_FragCoord.xy, vPositionES.z);"
7808 //<< endl << " uvec2 data_gpu = imageLoad(light_grid, accessor).xy;"
7810 //<< endl << " uint test_value = data_gpu.y;"
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"