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