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