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