e7a3e3df4fbada884984b0088d4c9bd4232d5342
[occt.git] / src / Shaders / RaytraceBase.fs
1 #ifdef USE_TEXTURES
2   #extension GL_ARB_bindless_texture : require
3 #endif
4
5 //! Normalized pixel coordinates.
6 in vec2 vPixel;
7
8 //! Sub-pixel offset in X direction for FSAA.
9 uniform float uOffsetX = 0.f;
10 //! Sub-pixel offset in Y direction for FSAA.
11 uniform float uOffsetY = 0.f;
12
13 //! Origin of viewing ray in left-top corner.
14 uniform vec3 uOriginLT;
15 //! Origin of viewing ray in left-bottom corner.
16 uniform vec3 uOriginLB;
17 //! Origin of viewing ray in right-top corner.
18 uniform vec3 uOriginRT;
19 //! Origin of viewing ray in right-bottom corner.
20 uniform vec3 uOriginRB;
21
22 //! Width of the rendering window.
23 uniform int uWinSizeX;
24 //! Height of the rendering window.
25 uniform int uWinSizeY;
26
27 //! Direction of viewing ray in left-top corner.
28 uniform vec3 uDirectLT;
29 //! Direction of viewing ray in left-bottom corner.
30 uniform vec3 uDirectLB;
31 //! Direction of viewing ray in right-top corner.
32 uniform vec3 uDirectRT;
33 //! Direction of viewing ray in right-bottom corner.
34 uniform vec3 uDirectRB;
35
36 //! Inverse model-view-projection matrix.
37 uniform mat4 uUnviewMat;
38
39 //! Model-view-projection matrix.
40 uniform mat4 uViewMat;
41
42 //! Texture buffer of data records of bottom-level BVH nodes.
43 uniform isamplerBuffer uSceneNodeInfoTexture;
44 //! Texture buffer of minimum points of bottom-level BVH nodes.
45 uniform samplerBuffer uSceneMinPointTexture;
46 //! Texture buffer of maximum points of bottom-level BVH nodes.
47 uniform samplerBuffer uSceneMaxPointTexture;
48 //! Texture buffer of transformations of high-level BVH nodes.
49 uniform samplerBuffer uSceneTransformTexture;
50
51 //! Texture buffer of vertex coords.
52 uniform samplerBuffer uGeometryVertexTexture;
53 //! Texture buffer of vertex normals.
54 uniform samplerBuffer uGeometryNormalTexture;
55 #ifdef USE_TEXTURES
56   //! Texture buffer of per-vertex UV-coordinates.
57   uniform samplerBuffer uGeometryTexCrdTexture;
58 #endif
59 //! Texture buffer of triangle indices.
60 uniform isamplerBuffer uGeometryTriangTexture;
61
62 //! Texture buffer of material properties.
63 uniform samplerBuffer uRaytraceMaterialTexture;
64 //! Texture buffer of light source properties.
65 uniform samplerBuffer uRaytraceLightSrcTexture;
66 //! Environment map texture.
67 uniform sampler2D uEnvironmentMapTexture;
68
69 //! Input pre-raytracing image rendered by OpenGL.
70 uniform sampler2D uOpenGlColorTexture;
71 //! Input pre-raytracing depth image rendered by OpenGL.
72 uniform sampler2D uOpenGlDepthTexture;
73
74 //! Total number of light sources.
75 uniform int uLightCount;
76 //! Intensity of global ambient light.
77 uniform vec4 uGlobalAmbient;
78
79 //! Enables/disables hard shadows.
80 uniform int uShadowsEnabled;
81 //! Enables/disables specular reflections.
82 uniform int uReflectEnabled;
83 //! Enables/disables spherical environment map.
84 uniform int uSphereMapEnabled;
85 //! Enables/disables environment map background.
86 uniform int uSphereMapForBack;
87
88 //! Radius of bounding sphere of the scene.
89 uniform float uSceneRadius;
90 //! Scene epsilon to prevent self-intersections.
91 uniform float uSceneEpsilon;
92
93 #ifdef USE_TEXTURES
94   //! Unique 64-bit handles of OpenGL textures.
95   uniform uvec2 uTextureSamplers[MAX_TEX_NUMBER];
96 #endif
97
98 //! Top color of gradient background.
99 uniform vec4 uBackColorTop = vec4 (0.0);
100 //! Bottom color of gradient background.
101 uniform vec4 uBackColorBot = vec4 (0.0);
102
103 /////////////////////////////////////////////////////////////////////////////////////////
104 // Specific data types
105
106 //! Stores ray parameters.
107 struct SRay
108 {
109   vec3 Origin;
110
111   vec3 Direct;
112 };
113
114 //! Stores intersection parameters.
115 struct SIntersect
116 {
117   float Time;
118
119   vec2 UV;
120
121   vec3 Normal;
122 };
123
124 /////////////////////////////////////////////////////////////////////////////////////////
125 // Some useful constants
126
127 #define MAXFLOAT 1e15f
128
129 #define SMALL vec3 (exp2 (-80.0f))
130
131 #define ZERO vec3 (0.0f, 0.0f, 0.0f)
132 #define UNIT vec3 (1.0f, 1.0f, 1.0f)
133
134 #define AXIS_X vec3 (1.0f, 0.0f, 0.0f)
135 #define AXIS_Y vec3 (0.0f, 1.0f, 0.0f)
136 #define AXIS_Z vec3 (0.0f, 0.0f, 1.0f)
137
138 #define M_PI 3.14159265f
139
140 #define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)
141
142 // =======================================================================
143 // function : MatrixRowMultiplyDir
144 // purpose  : Multiplies a vector by matrix
145 // =======================================================================
146 vec3 MatrixRowMultiplyDir (in vec3 v,
147                            in vec4 m0,
148                            in vec4 m1,
149                            in vec4 m2)
150 {
151   return vec3 (dot (m0.xyz, v),
152                dot (m1.xyz, v),
153                dot (m2.xyz, v));
154 }
155
156 //! 32-bit state of random number generator.
157 uint RandState;
158
159 // =======================================================================
160 // function : SeedRand
161 // purpose  : Applies hash function by Thomas Wang to randomize seeds
162 //            (see http://www.burtleburtle.net/bob/hash/integer.html)
163 // =======================================================================
164 void SeedRand (in int theSeed, in int theSizeX, in int theRadius)
165 {
166   RandState = uint (int (gl_FragCoord.y) / theRadius * theSizeX + int (gl_FragCoord.x) / theRadius + theSeed);
167
168   RandState = (RandState + 0x479ab41du) + (RandState <<  8);
169   RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >>  5);
170   RandState = (RandState + 0x9942f0a6u) - (RandState << 14);
171   RandState = (RandState ^ 0x5aedd67du) ^ (RandState >>  3);
172   RandState = (RandState + 0x17bea992u) + (RandState <<  7);
173 }
174
175 // =======================================================================
176 // function : RandInt
177 // purpose  : Generates integer using Xorshift algorithm by G. Marsaglia
178 // =======================================================================
179 uint RandInt()
180 {
181   RandState ^= (RandState << 13);
182   RandState ^= (RandState >> 17);
183   RandState ^= (RandState <<  5);
184
185   return RandState;
186 }
187
188 // =======================================================================
189 // function : RandFloat
190 // purpose  : Generates a random float in [0, 1) range
191 // =======================================================================
192 float RandFloat()
193 {
194   return float (RandInt()) * (1.f / 4294967296.f);
195 }
196
197 // =======================================================================
198 // function : MatrixColMultiplyPnt
199 // purpose  : Multiplies a vector by matrix
200 // =======================================================================
201 vec3 MatrixColMultiplyPnt (in vec3 v,
202                            in vec4 m0,
203                            in vec4 m1,
204                            in vec4 m2,
205                            in vec4 m3)
206 {
207   return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z + m3.x,
208                m0.y * v.x + m1.y * v.y + m2.y * v.z + m3.y,
209                m0.z * v.x + m1.z * v.y + m2.z * v.z + m3.z);
210 }
211
212 // =======================================================================
213 // function : MatrixColMultiplyDir
214 // purpose  : Multiplies a vector by matrix
215 // =======================================================================
216 vec3 MatrixColMultiplyDir (in vec3 v,
217                            in vec4 m0,
218                            in vec4 m1,
219                            in vec4 m2)
220 {
221   return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z,
222                m0.y * v.x + m1.y * v.y + m2.y * v.z,
223                m0.z * v.x + m1.z * v.y + m2.z * v.z);
224 }
225
226 //=======================================================================
227 // function : InverseDirection
228 // purpose  : Returns safely inverted direction of the given one
229 //=======================================================================
230 vec3 InverseDirection (in vec3 theInput)
231 {
232   vec3 anInverse = 1.f / max (abs (theInput), SMALL);
233
234   return mix (-anInverse, anInverse, step (ZERO, theInput));
235 }
236
237 //=======================================================================
238 // function : BackgroundColor
239 // purpose  : Returns color of gradient background
240 //=======================================================================
241 vec4 BackgroundColor()
242 {
243   return mix (uBackColorBot, uBackColorTop, vPixel.y);
244 }
245
246 /////////////////////////////////////////////////////////////////////////////////////////
247 // Functions for compute ray-object intersection
248
249 // =======================================================================
250 // function : GenerateRay
251 // purpose  :
252 // =======================================================================
253 SRay GenerateRay (in vec2 thePixel)
254 {
255   vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
256   vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
257
258   vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x);
259   vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x);
260
261   vec3 aDirection = normalize (mix (aD0, aD1, thePixel.y));
262
263   return SRay (mix (aP0, aP1, thePixel.y), aDirection);
264 }
265
266 // =======================================================================
267 // function : ComputeOpenGlDepth
268 // purpose  :
269 // =======================================================================
270 float ComputeOpenGlDepth (in SRay theRay)
271 {
272   // a depth in range [0,1]
273   float anOpenGlDepth = texelFetch (uOpenGlDepthTexture, ivec2 (gl_FragCoord.xy), 0).r;
274   // pixel point in NDC-space [-1,1]
275   vec4 aPoint = vec4 (2.0f * vPixel.x - 1.0f,
276                       2.0f * vPixel.y - 1.0f,
277                       2.0f * anOpenGlDepth - 1.0f,
278                       1.0f);
279   vec4 aFinal = uUnviewMat * aPoint;
280   aFinal.xyz *= 1.f / aFinal.w;
281
282   return (anOpenGlDepth < 1.f) ? length (aFinal.xyz - theRay.Origin) : MAXFLOAT;
283 }
284
285 // =======================================================================
286 // function : ComputeOpenGlColor
287 // purpose  :
288 // =======================================================================
289 vec4 ComputeOpenGlColor()
290 {
291   vec4 anOpenGlColor = texelFetch (uOpenGlColorTexture, ivec2 (gl_FragCoord.xy), 0);
292   // During blending with factors GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA (for text and markers)
293   // the alpha channel (written in the color buffer) was squared.
294   anOpenGlColor.a = 1.f - sqrt (anOpenGlColor.a);
295
296   return anOpenGlColor;
297 }
298
299 // =======================================================================
300 // function : IntersectSphere
301 // purpose  : Computes ray-sphere intersection
302 // =======================================================================
303 float IntersectSphere (in SRay theRay, in float theRadius)
304 {
305   float aDdotD = dot (theRay.Direct, theRay.Direct);
306   float aDdotO = dot (theRay.Direct, theRay.Origin);
307   float aOdotO = dot (theRay.Origin, theRay.Origin);
308
309   float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);
310
311   if (aD > 0.0f)
312   {
313     float aTime = (sqrt (aD) - aDdotO) * (1.0f / aDdotD);
314     
315     return aTime > 0.0f ? aTime : MAXFLOAT;
316   }
317
318   return MAXFLOAT;
319 }
320
321 // =======================================================================
322 // function : IntersectTriangle
323 // purpose  : Computes ray-triangle intersection (branchless version)
324 // =======================================================================
325 void IntersectTriangle (in SRay theRay,
326                         in vec3 thePnt0,
327                         in vec3 thePnt1,
328                         in vec3 thePnt2,
329                         out vec3 theUVT,
330                         out vec3 theNorm)
331 {
332   vec3 aToTrg = thePnt0 - theRay.Origin;
333
334   vec3 aEdge0 = thePnt1 - thePnt0;
335   vec3 aEdge1 = thePnt0 - thePnt2;
336
337   theNorm = cross (aEdge1, aEdge0);
338
339   vec3 theVect = cross (theRay.Direct, aToTrg);
340
341   theUVT = vec3 (dot (theNorm, aToTrg),
342                  dot (theVect, aEdge1),
343                  dot (theVect, aEdge0)) * (1.f / dot (theNorm, theRay.Direct));
344
345   theUVT.x = any (lessThan (theUVT, ZERO)) || (theUVT.y + theUVT.z) > 1.f ? MAXFLOAT : theUVT.x;
346 }
347
348 #define EMPTY_ROOT ivec4(0)
349
350 //! Utility structure containing information about
351 //! currently traversing sub-tree of scene's BVH.
352 struct SSubTree
353 {
354   //! Transformed ray.
355   SRay  TrsfRay;
356
357   //! Inversed ray direction.
358   vec3  Inverse;
359
360   //! Parameters of sub-root node.
361   ivec4 SubData;
362 };
363
364 #define MATERIAL_AMBN(index) (18 * index + 0)
365 #define MATERIAL_DIFF(index) (18 * index + 1)
366 #define MATERIAL_SPEC(index) (18 * index + 2)
367 #define MATERIAL_EMIS(index) (18 * index + 3)
368 #define MATERIAL_REFL(index) (18 * index + 4)
369 #define MATERIAL_REFR(index) (18 * index + 5)
370 #define MATERIAL_TRAN(index) (18 * index + 6)
371 #define MATERIAL_TRS1(index) (18 * index + 7)
372 #define MATERIAL_TRS2(index) (18 * index + 8)
373 #define MATERIAL_TRS3(index) (18 * index + 9)
374
375 #define TRS_OFFSET(treelet) treelet.SubData.x
376 #define BVH_OFFSET(treelet) treelet.SubData.y
377 #define VRT_OFFSET(treelet) treelet.SubData.z
378 #define TRG_OFFSET(treelet) treelet.SubData.w
379
380 //! Identifies the absence of intersection.
381 #define INALID_HIT ivec4 (-1)
382
383 //! Global stack shared between traversal functions.
384 int Stack[STACK_SIZE];
385
386 // =======================================================================
387 // function : pop
388 // purpose  :
389 // =======================================================================
390 int pop (inout int theHead)
391 {
392   int aData = Stack[theHead];
393
394   int aMask = aData >> 26;
395   int aNode = aMask & 0x3;
396
397   aMask >>= 2;
398
399   if ((aMask & 0x3) == aNode)
400   {
401     --theHead;
402   }
403   else
404   {
405     aMask |= (aMask << 2) & 0x30;
406
407     Stack[theHead] = (aData & 0x03FFFFFF) | (aMask << 26);
408   }
409
410   return (aData & 0x03FFFFFF) + aNode;
411 }
412
413 // =======================================================================
414 // function : SceneNearestHit
415 // purpose  : Finds intersection with nearest scene triangle
416 // =======================================================================
417 ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
418 {
419   ivec4 aTriIndex = INALID_HIT;
420
421   int aNode =  0; // node to traverse
422   int aHead = -1; // pointer of stack
423   int aStop = -1; // BVH level switch
424
425   SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
426
427   for (bool toContinue = true; toContinue; /* none */)
428   {
429     ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
430
431     if (aData.x == 0) // if inner node
432     {
433       aData.y += BVH_OFFSET (aSubTree);
434
435       vec4 aHitTimes = vec4 (MAXFLOAT,
436                              MAXFLOAT,
437                              MAXFLOAT,
438                              MAXFLOAT);
439
440       vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse;
441
442       vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y +                0).xyz * aSubTree.Inverse + aRayOriginInverse;
443       vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y +                1).xyz * aSubTree.Inverse + aRayOriginInverse;
444       vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
445       vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
446       vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y +                0).xyz * aSubTree.Inverse + aRayOriginInverse;
447       vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y +                1).xyz * aSubTree.Inverse + aRayOriginInverse;
448       vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
449       vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
450
451       vec3 aTimeMax = max (aNodeMin0, aNodeMax0);
452       vec3 aTimeMin = min (aNodeMin0, aNodeMax0);
453
454       float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
455       float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
456
457       aHitTimes.x = mix (MAXFLOAT, aTimeEnter,
458         aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f);
459
460       aTimeMax = max (aNodeMin1, aNodeMax1);
461       aTimeMin = min (aNodeMin1, aNodeMax1);
462
463       aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
464       aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
465
466       aHitTimes.y = mix (MAXFLOAT, aTimeEnter,
467         aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f);
468
469       aTimeMax = max (aNodeMin2, aNodeMax2);
470       aTimeMin = min (aNodeMin2, aNodeMax2);
471
472       aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
473       aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
474
475       aHitTimes.z = mix (MAXFLOAT, aTimeEnter,
476         aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 1);
477
478       aTimeMax = max (aNodeMin3, aNodeMax3);
479       aTimeMin = min (aNodeMin3, aNodeMax3);
480
481       aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
482       aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
483
484       aHitTimes.w = mix (MAXFLOAT, aTimeEnter,
485         aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 2);
486
487       ivec4 aChildren = ivec4 (0, 1, 2, 3);
488
489       aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy;
490       aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy;
491       aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw;
492       aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw;
493       aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz;
494       aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz;
495       aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw;
496       aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw;
497       aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz;
498       aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz;
499
500       if (aHitTimes.x != MAXFLOAT)
501       {
502         int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2
503                      | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y);
504
505         if (aHitTimes.y != MAXFLOAT)
506           Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26;
507
508         aNode = aData.y + aChildren.x;
509       }
510       else
511       {
512         toContinue = (aHead >= 0);
513
514         if (aHead == aStop) // go to top-level BVH
515         {
516           aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
517         }
518
519         if (aHead >= 0)
520           aNode = pop (aHead);
521       }
522     }
523     else if (aData.x < 0) // leaf node (contains triangles)
524     {
525       vec3 aNormal;
526       vec3 aTimeUV;
527
528       for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
529       {
530         ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
531
532         vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;
533         vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;
534         vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;
535
536         IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);
537
538         if (aTimeUV.x < theHit.Time)
539         {
540           aTriIndex = aTriangle;
541
542           theTrsfId = TRS_OFFSET (aSubTree);
543
544           theHit = SIntersect (aTimeUV.x, aTimeUV.yz, aNormal);
545         }
546       }
547
548       toContinue = (aHead >= 0);
549
550       if (aHead == aStop) // go to top-level BVH
551       {
552         aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
553       }
554
555       if (aHead >= 0)
556         aNode = pop (aHead);
557     }
558     else if (aData.x > 0) // switch node
559     {
560       aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
561
562       vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
563       vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
564       vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
565       vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
566
567       aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
568                                                       aInvTransf0,
569                                                       aInvTransf1,
570                                                       aInvTransf2);
571
572       aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) /
573         max (abs (aSubTree.TrsfRay.Direct), SMALL);
574
575       aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
576                                                       aInvTransf0,
577                                                       aInvTransf1,
578                                                       aInvTransf2,
579                                                       aInvTransf3);
580
581       aNode = BVH_OFFSET (aSubTree); // go to sub-root node
582
583       aStop = aHead; // store current stack pointer
584     }
585   }
586
587   return aTriIndex;
588 }
589
590 // =======================================================================
591 // function : SceneAnyHit
592 // purpose  : Finds intersection with any scene triangle
593 // =======================================================================
594 float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
595 {
596   float aFactor = 1.f;
597
598   int aNode =  0; // node to traverse
599   int aHead = -1; // pointer of stack
600   int aStop = -1; // BVH level switch
601
602   SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
603
604   for (bool toContinue = true; toContinue; /* none */)
605   {
606     ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
607
608     if (aData.x == 0) // if inner node
609     {
610       aData.y += BVH_OFFSET (aSubTree);
611
612       vec4 aHitTimes = vec4 (MAXFLOAT,
613                              MAXFLOAT,
614                              MAXFLOAT,
615                              MAXFLOAT);
616
617       vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse;
618
619       vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y +                0).xyz * aSubTree.Inverse + aRayOriginInverse;
620       vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y +                1).xyz * aSubTree.Inverse + aRayOriginInverse;
621       vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
622       vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
623       vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y +                0).xyz * aSubTree.Inverse + aRayOriginInverse;
624       vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y +                1).xyz * aSubTree.Inverse + aRayOriginInverse;
625       vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
626       vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
627
628       vec3 aTimeMax = max (aNodeMin0, aNodeMax0);
629       vec3 aTimeMin = min (aNodeMin0, aNodeMax0);
630
631       float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
632       float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
633
634       aHitTimes.x = mix (MAXFLOAT, aTimeEnter,
635         aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f);
636
637       aTimeMax = max (aNodeMin1, aNodeMax1);
638       aTimeMin = min (aNodeMin1, aNodeMax1);
639
640       aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
641       aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
642
643       aHitTimes.y = mix (MAXFLOAT, aTimeEnter,
644         aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f);
645
646       aTimeMax = max (aNodeMin2, aNodeMax2);
647       aTimeMin = min (aNodeMin2, aNodeMax2);
648
649       aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
650       aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
651
652       aHitTimes.z = mix (MAXFLOAT, aTimeEnter,
653         aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 1);
654
655       aTimeMax = max (aNodeMin3, aNodeMax3);
656       aTimeMin = min (aNodeMin3, aNodeMax3);
657
658       aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
659       aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
660
661       aHitTimes.w = mix (MAXFLOAT, aTimeEnter,
662         aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 2);
663
664       ivec4 aChildren = ivec4 (0, 1, 2, 3);
665
666       aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy;
667       aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy;
668       aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw;
669       aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw;
670       aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz;
671       aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz;
672       aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw;
673       aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw;
674       aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz;
675       aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz;
676
677       if (aHitTimes.x != MAXFLOAT)
678       {
679         int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2
680                      | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y);
681
682         if (aHitTimes.y != MAXFLOAT)
683           Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26;
684
685         aNode = aData.y + aChildren.x;
686       }
687       else
688       {
689         toContinue = (aHead >= 0);
690
691         if (aHead == aStop) // go to top-level BVH
692         {
693           aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
694         }
695
696         if (aHead >= 0)
697           aNode = pop (aHead);
698       }
699     }
700     else if (aData.x < 0) // leaf node
701     {
702       vec3 aNormal;
703       vec3 aTimeUV;
704
705       for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
706       {
707         ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
708
709         vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;
710         vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;
711         vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;
712
713         IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);
714
715 #ifdef TRANSPARENT_SHADOWS
716         if (aTimeUV.x < theDistance)
717         {
718           aFactor *= 1.f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
719         }
720 #else
721         if (aTimeUV.x < theDistance)
722         {
723           aFactor = 0.f;
724         }
725 #endif
726       }
727
728       toContinue = (aHead >= 0);
729
730       if (aHead == aStop) // go to top-level BVH
731       {
732         aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
733       }
734
735       if (aHead >= 0)
736         aNode = pop (aHead);
737     }
738     else if (aData.x > 0) // switch node
739     {
740       aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
741
742       vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
743       vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
744       vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
745       vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
746
747       aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
748                                                       aInvTransf0,
749                                                       aInvTransf1,
750                                                       aInvTransf2);
751
752       aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
753                                                       aInvTransf0,
754                                                       aInvTransf1,
755                                                       aInvTransf2,
756                                                       aInvTransf3);
757
758       aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) / max (abs (aSubTree.TrsfRay.Direct), SMALL);
759
760       aNode = BVH_OFFSET (aSubTree); // go to sub-root node
761
762       aStop = aHead; // store current stack pointer
763     }
764   }
765
766   return aFactor;
767 }
768
769 #define PI 3.1415926f
770
771 // =======================================================================
772 // function : Latlong
773 // purpose  : Converts world direction to environment texture coordinates
774 // =======================================================================
775 vec2 Latlong (in vec3 thePoint, in float theRadius)
776 {
777   float aPsi = acos (-thePoint.z / theRadius);
778
779   float aPhi = atan (thePoint.y, thePoint.x) + PI;
780
781   return vec2 (aPhi * 0.1591549f,
782                aPsi * 0.3183098f);
783 }
784
785 // =======================================================================
786 // function : SmoothNormal
787 // purpose  : Interpolates normal across the triangle
788 // =======================================================================
789 vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
790 {
791   vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz;
792   vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz;
793   vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz;
794
795   return normalize (aNormal1 * theUV.x +
796                     aNormal2 * theUV.y +
797                     aNormal0 * (1.0f - theUV.x - theUV.y));
798 }
799
800 // =======================================================================
801 // function : SmoothUV
802 // purpose  : Interpolates UV coordinates across the triangle
803 // =======================================================================
804 #ifdef USE_TEXTURES
805 vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)
806 {
807   vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;
808   vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;
809   vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;
810
811   return aTexCrd1 * theUV.x +
812          aTexCrd2 * theUV.y +
813          aTexCrd0 * (1.0f - theUV.x - theUV.y);
814 }
815 #endif
816
817 // =======================================================================
818 // function : FetchEnvironment
819 // purpose  :
820 // =======================================================================
821 vec4 FetchEnvironment (in vec2 theTexCoord)
822 {
823   return mix (vec4 (0.0f, 0.0f, 0.0f, 1.0f),
824     textureLod (uEnvironmentMapTexture, theTexCoord, 0.0f), float (uSphereMapEnabled));
825 }
826
827 // =======================================================================
828 // function : Refract
829 // purpose  : Computes refraction ray (also handles TIR)
830 // =======================================================================
831 #ifndef PATH_TRACING
832 vec3 Refract (in vec3 theInput,
833               in vec3 theNormal,
834               in float theRefractIndex,
835               in float theInvRefractIndex)
836 {
837   float aNdotI = dot (theInput, theNormal);
838
839   float anIndex = aNdotI < 0.0f
840                 ? theInvRefractIndex
841                 : theRefractIndex;
842
843   float aSquare = anIndex * anIndex * (1.0f - aNdotI * aNdotI);
844
845   if (aSquare > 1.0f)
846   {
847     return reflect (theInput, theNormal);
848   }
849
850   float aNdotT = sqrt (1.0f - aSquare);
851
852   return normalize (anIndex * theInput -
853     (anIndex * aNdotI + (aNdotI < 0.0f ? aNdotT : -aNdotT)) * theNormal);
854 }
855 #endif
856
857 #define MIN_SLOPE 0.0001f
858 #define EPS_SCALE 8.0000f
859
860 #define THRESHOLD vec3 (0.1f)
861
862 #define INVALID_BOUNCES 1000
863
864 #define LIGHT_POS(index) (2 * index + 1)
865 #define LIGHT_PWR(index) (2 * index + 0)
866
867 // =======================================================================
868 // function : Radiance
869 // purpose  : Computes color along the given ray
870 // =======================================================================
871 #ifndef PATH_TRACING
872 vec4 Radiance (in SRay theRay, in vec3 theInverse)
873 {
874   vec3 aResult = vec3 (0.0f);
875   vec4 aWeight = vec4 (1.0f);
876
877   int aTrsfId;
878
879   float anOpenGlDepth = ComputeOpenGlDepth (theRay);
880   float aRaytraceDepth = MAXFLOAT;
881
882   for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
883   {
884     SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
885
886     ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId);
887
888     if (aTriIndex.x == -1)
889     {
890       vec4 aColor = vec4 (0.0);
891
892       if (bool(uSphereMapForBack) || aWeight.w == 0.0f /* reflection */)
893       {
894         float aTime = IntersectSphere (theRay, uSceneRadius);
895
896         aColor = FetchEnvironment (Latlong (
897           theRay.Direct * aTime + theRay.Origin, uSceneRadius));
898       }
899       else
900       {
901         vec4 aGlColor = ComputeOpenGlColor();
902         aColor = vec4 (mix (aGlColor.rgb, BackgroundColor().rgb, aGlColor.w), aGlColor.w);
903       }
904
905       aResult += aWeight.xyz * aColor.xyz; aWeight.w *= aColor.w;
906
907       break; // terminate path
908     }
909
910     vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz;
911     vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz;
912     vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz;
913
914     aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
915                                    dot (aInvTransf1, aHit.Normal),
916                                    dot (aInvTransf2, aHit.Normal)));
917
918     // For polygons that are parallel to the screen plane, the depth slope
919     // is equal to 1, resulting in small polygon offset. For polygons that
920     // that are at a large angle to the screen, the depth slope tends to 1,
921     // resulting in a larger polygon offset
922     float aPolygonOffset = uSceneEpsilon * EPS_SCALE /
923       max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
924
925     if (anOpenGlDepth < aHit.Time + aPolygonOffset)
926     {
927       vec4 aGlColor = ComputeOpenGlColor();
928
929       aResult += aWeight.xyz * aGlColor.xyz;
930       aWeight *= aGlColor.w;
931     }
932
933     theRay.Origin += theRay.Direct * aHit.Time; // intersection point
934
935     // Evaluate depth
936     if (aDepth == 0)
937     {
938       // Hit point in NDC-space [-1,1] (the polygon offset is applied in the world space)
939       vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin + theRay.Direct * aPolygonOffset, 1.f);
940       aNDCPoint.xyz *= 1.f / aNDCPoint.w;
941
942       aRaytraceDepth = aNDCPoint.z * 0.5f + 0.5f;
943     }
944
945     vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
946
947     aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
948                                dot (aInvTransf1, aNormal),
949                                dot (aInvTransf2, aNormal)));
950
951     vec3 aAmbient  = texelFetch (
952       uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb;
953     vec4 aDiffuse  = texelFetch (
954       uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w));
955     vec4 aSpecular = texelFetch (
956       uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w));
957     vec4 aOpacity  = texelFetch (
958       uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w));
959
960 #ifdef USE_TEXTURES
961     if (aDiffuse.w >= 0.f)
962     {
963       vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);
964
965       vec4 aTrsfRow1 = texelFetch (
966         uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));
967       vec4 aTrsfRow2 = texelFetch (
968         uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));
969
970       aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
971                            dot (aTrsfRow2, aTexCoord));
972
973       vec3 aTexColor = textureLod (
974         sampler2D (uTextureSamplers[int(aDiffuse.w)]), aTexCoord.st, 0.f).rgb;
975
976       aDiffuse.rgb *= aTexColor;
977       aAmbient.rgb *= aTexColor;
978     }
979 #endif
980
981     vec3 aEmission = texelFetch (
982       uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb;
983
984     float aGeomFactor = dot (aNormal, theRay.Direct);
985
986     aResult.xyz += aWeight.xyz * aOpacity.x * (
987       uGlobalAmbient.xyz * aAmbient * max (abs (aGeomFactor), 0.5f) + aEmission);
988
989     vec3 aSidedNormal = mix (aNormal, -aNormal, step (0.0f, aGeomFactor));
990
991     for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
992     {
993       vec4 aLight = texelFetch (
994         uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
995
996       float aDistance = MAXFLOAT;
997
998       if (aLight.w != 0.0f) // point light source
999       {
1000         aDistance = length (aLight.xyz -= theRay.Origin);
1001
1002         aLight.xyz *= 1.0f / aDistance;
1003       }
1004
1005       float aLdotN = dot (aLight.xyz, aSidedNormal);
1006
1007       if (aLdotN > 0.0f) // first check if light source is important
1008       {
1009         float aVisibility = 1.0f;
1010
1011         if (bool(uShadowsEnabled))
1012         {
1013           SRay aShadow = SRay (theRay.Origin, aLight.xyz);
1014
1015           aShadow.Origin += uSceneEpsilon * (aLight.xyz +
1016             mix (-aHit.Normal, aHit.Normal, step (0.0f, dot (aHit.Normal, aLight.xyz))));
1017
1018           vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL);
1019
1020           aVisibility = SceneAnyHit (
1021             aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance);
1022         }
1023
1024         if (aVisibility > 0.0f)
1025         {
1026           vec3 aIntensity = vec3 (texelFetch (
1027             uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
1028
1029           float aRdotV = dot (reflect (aLight.xyz, aSidedNormal), theRay.Direct);
1030
1031           aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity *
1032             (aDiffuse.xyz * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w));
1033         }
1034       }
1035     }
1036
1037     if (aOpacity.x != 1.0f)
1038     {
1039       aWeight *= aOpacity.y;
1040
1041       if (aOpacity.z != 1.0f)
1042       {
1043         theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w);
1044       }
1045       else
1046       {
1047         anOpenGlDepth -= aHit.Time + uSceneEpsilon;
1048       }
1049     }
1050     else
1051     {
1052       aWeight *= bool(uReflectEnabled) ?
1053         texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f);
1054
1055       vec3 aReflect = reflect (theRay.Direct, aNormal);
1056
1057       if (dot (aReflect, aHit.Normal) * dot (theRay.Direct, aHit.Normal) > 0.0f)
1058       {
1059         aReflect = reflect (theRay.Direct, aHit.Normal);
1060       }
1061
1062       theRay.Direct = aReflect;
1063     }
1064
1065     if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
1066     {
1067       aDepth = INVALID_BOUNCES;
1068     }
1069     else if (aOpacity.x == 1.0f || aOpacity.z != 1.0f) // if no simple transparency
1070     {
1071       theRay.Origin += aHit.Normal * mix (
1072         -uSceneEpsilon, uSceneEpsilon, step (0.0f, dot (aHit.Normal, theRay.Direct)));
1073
1074       theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
1075
1076       theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct));
1077
1078       anOpenGlDepth = MAXFLOAT; // disable combining image with OpenGL output
1079     }
1080
1081     theRay.Origin += theRay.Direct * uSceneEpsilon;
1082   }
1083
1084   gl_FragDepth = aRaytraceDepth;
1085
1086   return vec4 (aResult.x,
1087                aResult.y,
1088                aResult.z,
1089                aWeight.w);
1090 }
1091 #endif