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