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