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