2 #extension GL_ARB_bindless_texture : require
5 //! Normalized pixel coordinates.
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;
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;
22 //! Width of the rendering window.
23 uniform int uWinSizeX;
24 //! Height of the rendering window.
25 uniform int uWinSizeY;
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;
36 //! Inverse model-view-projection matrix.
37 uniform mat4 uUnviewMat;
39 //! Model-view-projection matrix.
40 uniform mat4 uViewMat;
42 //! Texture buffer of data records of bottom-level BVH nodes.
43 uniform isamplerBuffer uSceneNodeInfoTexture;
44 //! Texture buffer of minimum points of bottom-level BVH nodes.
45 uniform samplerBuffer uSceneMinPointTexture;
46 //! Texture buffer of maximum points of bottom-level BVH nodes.
47 uniform samplerBuffer uSceneMaxPointTexture;
48 //! Texture buffer of transformations of high-level BVH nodes.
49 uniform samplerBuffer uSceneTransformTexture;
51 //! Texture buffer of vertex coords.
52 uniform samplerBuffer uGeometryVertexTexture;
53 //! Texture buffer of vertex normals.
54 uniform samplerBuffer uGeometryNormalTexture;
56 //! Texture buffer of per-vertex UV-coordinates.
57 uniform samplerBuffer uGeometryTexCrdTexture;
59 //! Texture buffer of triangle indices.
60 uniform isamplerBuffer uGeometryTriangTexture;
62 //! Texture buffer of material properties.
63 uniform samplerBuffer uRaytraceMaterialTexture;
64 //! Texture buffer of light source properties.
65 uniform samplerBuffer uRaytraceLightSrcTexture;
66 //! Environment map texture.
67 uniform sampler2D uEnvironmentMapTexture;
69 //! Input pre-raytracing image rendered by OpenGL.
70 uniform sampler2D uOpenGlColorTexture;
71 //! Input pre-raytracing depth image rendered by OpenGL.
72 uniform sampler2D uOpenGlDepthTexture;
74 //! Total number of light sources.
75 uniform int uLightCount;
76 //! Intensity of global ambient light.
77 uniform vec4 uGlobalAmbient;
79 //! Enables/disables hard shadows.
80 uniform int uShadowsEnabled;
81 //! Enables/disables specular reflections.
82 uniform int uReflectEnabled;
83 //! Enables/disables spherical environment map.
84 uniform int uSphereMapEnabled;
85 //! Enables/disables environment map background.
86 uniform int uSphereMapForBack;
88 //! Radius of bounding sphere of the scene.
89 uniform float uSceneRadius;
90 //! Scene epsilon to prevent self-intersections.
91 uniform float uSceneEpsilon;
94 //! Unique 64-bit handles of OpenGL textures.
95 uniform uvec2 uTextureSamplers[MAX_TEX_NUMBER];
98 //! Top color of gradient background.
99 uniform vec4 uBackColorTop = vec4 (0.0);
100 //! Bottom color of gradient background.
101 uniform vec4 uBackColorBot = vec4 (0.0);
103 /////////////////////////////////////////////////////////////////////////////////////////
104 // Specific data types
106 //! Stores ray parameters.
114 //! Stores intersection parameters.
124 /////////////////////////////////////////////////////////////////////////////////////////
125 // Some useful constants
127 #define MAXFLOAT 1e15f
129 #define SMALL vec3 (exp2 (-80.0f))
131 #define ZERO vec3 (0.0f, 0.0f, 0.0f)
132 #define UNIT vec3 (1.0f, 1.0f, 1.0f)
134 #define AXIS_X vec3 (1.0f, 0.0f, 0.0f)
135 #define AXIS_Y vec3 (0.0f, 1.0f, 0.0f)
136 #define AXIS_Z vec3 (0.0f, 0.0f, 1.0f)
138 #define M_PI 3.14159265f
140 #define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)
142 // =======================================================================
143 // function : MatrixRowMultiplyDir
144 // purpose : Multiplies a vector by matrix
145 // =======================================================================
146 vec3 MatrixRowMultiplyDir (in vec3 v,
151 return vec3 (dot (m0.xyz, v),
156 //! 32-bit state of random number generator.
159 // =======================================================================
160 // function : SeedRand
161 // purpose : Applies hash function by Thomas Wang to randomize seeds
162 // (see http://www.burtleburtle.net/bob/hash/integer.html)
163 // =======================================================================
164 void SeedRand (in int theSeed, in int theSizeX, in int theRadius)
166 RandState = uint (int (gl_FragCoord.y) / theRadius * theSizeX + int (gl_FragCoord.x) / theRadius + theSeed);
168 RandState = (RandState + 0x479ab41du) + (RandState << 8);
169 RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >> 5);
170 RandState = (RandState + 0x9942f0a6u) - (RandState << 14);
171 RandState = (RandState ^ 0x5aedd67du) ^ (RandState >> 3);
172 RandState = (RandState + 0x17bea992u) + (RandState << 7);
175 // =======================================================================
176 // function : RandInt
177 // purpose : Generates integer using Xorshift algorithm by G. Marsaglia
178 // =======================================================================
181 RandState ^= (RandState << 13);
182 RandState ^= (RandState >> 17);
183 RandState ^= (RandState << 5);
188 // =======================================================================
189 // function : RandFloat
190 // purpose : Generates a random float in [0, 1) range
191 // =======================================================================
194 return float (RandInt()) * (1.f / 4294967296.f);
197 // =======================================================================
198 // function : MatrixColMultiplyPnt
199 // purpose : Multiplies a vector by matrix
200 // =======================================================================
201 vec3 MatrixColMultiplyPnt (in vec3 v,
207 return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z + m3.x,
208 m0.y * v.x + m1.y * v.y + m2.y * v.z + m3.y,
209 m0.z * v.x + m1.z * v.y + m2.z * v.z + m3.z);
212 // =======================================================================
213 // function : MatrixColMultiplyDir
214 // purpose : Multiplies a vector by matrix
215 // =======================================================================
216 vec3 MatrixColMultiplyDir (in vec3 v,
221 return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z,
222 m0.y * v.x + m1.y * v.y + m2.y * v.z,
223 m0.z * v.x + m1.z * v.y + m2.z * v.z);
226 //=======================================================================
227 // function : InverseDirection
228 // purpose : Returns safely inverted direction of the given one
229 //=======================================================================
230 vec3 InverseDirection (in vec3 theInput)
232 vec3 anInverse = 1.f / max (abs (theInput), SMALL);
234 return mix (-anInverse, anInverse, step (ZERO, theInput));
237 //=======================================================================
238 // function : BackgroundColor
239 // purpose : Returns color of gradient background
240 //=======================================================================
241 vec4 BackgroundColor()
243 return mix (uBackColorBot, uBackColorTop, vPixel.y);
246 /////////////////////////////////////////////////////////////////////////////////////////
247 // Functions for compute ray-object intersection
249 // =======================================================================
250 // function : GenerateRay
252 // =======================================================================
253 SRay GenerateRay (in vec2 thePixel)
255 vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
256 vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
258 vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x);
259 vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x);
261 vec3 aDirection = normalize (mix (aD0, aD1, thePixel.y));
263 return SRay (mix (aP0, aP1, thePixel.y), aDirection);
266 // =======================================================================
267 // function : ComputeOpenGlDepth
269 // =======================================================================
270 float ComputeOpenGlDepth (in SRay theRay)
272 // a depth in range [0,1]
273 float anOpenGlDepth = texelFetch (uOpenGlDepthTexture, ivec2 (gl_FragCoord.xy), 0).r;
274 // pixel point in NDC-space [-1,1]
275 vec4 aPoint = vec4 (2.0f * vPixel.x - 1.0f,
276 2.0f * vPixel.y - 1.0f,
277 2.0f * anOpenGlDepth - 1.0f,
279 vec4 aFinal = uUnviewMat * aPoint;
280 aFinal.xyz *= 1.f / aFinal.w;
282 return (anOpenGlDepth < 1.f) ? length (aFinal.xyz - theRay.Origin) : MAXFLOAT;
285 // =======================================================================
286 // function : ComputeOpenGlColor
288 // =======================================================================
289 vec4 ComputeOpenGlColor()
291 vec4 anOpenGlColor = texelFetch (uOpenGlColorTexture, ivec2 (gl_FragCoord.xy), 0);
292 // During blending with factors GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA (for text and markers)
293 // the alpha channel (written in the color buffer) was squared.
294 anOpenGlColor.a = 1.f - sqrt (anOpenGlColor.a);
296 return anOpenGlColor;
299 // =======================================================================
300 // function : IntersectSphere
301 // purpose : Computes ray-sphere intersection
302 // =======================================================================
303 float IntersectSphere (in SRay theRay, in float theRadius)
305 float aDdotD = dot (theRay.Direct, theRay.Direct);
306 float aDdotO = dot (theRay.Direct, theRay.Origin);
307 float aOdotO = dot (theRay.Origin, theRay.Origin);
309 float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);
313 float aTime = (sqrt (aD) - aDdotO) * (1.0f / aDdotD);
315 return aTime > 0.0f ? aTime : MAXFLOAT;
321 // =======================================================================
322 // function : IntersectTriangle
323 // purpose : Computes ray-triangle intersection (branchless version)
324 // =======================================================================
325 void IntersectTriangle (in SRay theRay,
332 vec3 aToTrg = thePnt0 - theRay.Origin;
334 vec3 aEdge0 = thePnt1 - thePnt0;
335 vec3 aEdge1 = thePnt0 - thePnt2;
337 theNorm = cross (aEdge1, aEdge0);
339 vec3 theVect = cross (theRay.Direct, aToTrg);
341 theUVT = vec3 (dot (theNorm, aToTrg),
342 dot (theVect, aEdge1),
343 dot (theVect, aEdge0)) * (1.f / dot (theNorm, theRay.Direct));
345 theUVT.x = any (lessThan (theUVT, ZERO)) || (theUVT.y + theUVT.z) > 1.f ? MAXFLOAT : theUVT.x;
348 #define EMPTY_ROOT ivec4(0)
350 //! Utility structure containing information about
351 //! currently traversing sub-tree of scene's BVH.
357 //! Inversed ray direction.
360 //! Parameters of sub-root node.
364 #define MATERIAL_AMBN(index) (18 * index + 0)
365 #define MATERIAL_DIFF(index) (18 * index + 1)
366 #define MATERIAL_SPEC(index) (18 * index + 2)
367 #define MATERIAL_EMIS(index) (18 * index + 3)
368 #define MATERIAL_REFL(index) (18 * index + 4)
369 #define MATERIAL_REFR(index) (18 * index + 5)
370 #define MATERIAL_TRAN(index) (18 * index + 6)
371 #define MATERIAL_TRS1(index) (18 * index + 7)
372 #define MATERIAL_TRS2(index) (18 * index + 8)
373 #define MATERIAL_TRS3(index) (18 * index + 9)
375 #define TRS_OFFSET(treelet) treelet.SubData.x
376 #define BVH_OFFSET(treelet) treelet.SubData.y
377 #define VRT_OFFSET(treelet) treelet.SubData.z
378 #define TRG_OFFSET(treelet) treelet.SubData.w
380 //! Identifies the absence of intersection.
381 #define INALID_HIT ivec4 (-1)
383 //! Global stack shared between traversal functions.
384 int Stack[STACK_SIZE];
386 // =======================================================================
389 // =======================================================================
390 int pop (inout int theHead)
392 int aData = Stack[theHead];
394 int aMask = aData >> 26;
395 int aNode = aMask & 0x3;
399 if ((aMask & 0x3) == aNode)
405 aMask |= (aMask << 2) & 0x30;
407 Stack[theHead] = (aData & 0x03FFFFFF) | (aMask << 26);
410 return (aData & 0x03FFFFFF) + aNode;
413 // =======================================================================
414 // function : SceneNearestHit
415 // purpose : Finds intersection with nearest scene triangle
416 // =======================================================================
417 ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
419 ivec4 aTriIndex = INALID_HIT;
421 int aNode = 0; // node to traverse
422 int aHead = -1; // pointer of stack
423 int aStop = -1; // BVH level switch
425 SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
427 for (bool toContinue = true; toContinue; /* none */)
429 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
431 if (aData.x == 0) // if inner node
433 aData.y += BVH_OFFSET (aSubTree);
435 vec4 aHitTimes = vec4 (MAXFLOAT,
440 vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse;
442 vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
443 vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
444 vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
445 vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
446 vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
447 vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
448 vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
449 vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
451 vec3 aTimeMax = max (aNodeMin0, aNodeMax0);
452 vec3 aTimeMin = min (aNodeMin0, aNodeMax0);
454 float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
455 float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
457 aHitTimes.x = mix (MAXFLOAT, aTimeEnter,
458 aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f);
460 aTimeMax = max (aNodeMin1, aNodeMax1);
461 aTimeMin = min (aNodeMin1, aNodeMax1);
463 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
464 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
466 aHitTimes.y = mix (MAXFLOAT, aTimeEnter,
467 aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f);
469 aTimeMax = max (aNodeMin2, aNodeMax2);
470 aTimeMin = min (aNodeMin2, aNodeMax2);
472 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
473 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
475 aHitTimes.z = mix (MAXFLOAT, aTimeEnter,
476 aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 1);
478 aTimeMax = max (aNodeMin3, aNodeMax3);
479 aTimeMin = min (aNodeMin3, aNodeMax3);
481 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
482 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
484 aHitTimes.w = mix (MAXFLOAT, aTimeEnter,
485 aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 2);
487 ivec4 aChildren = ivec4 (0, 1, 2, 3);
489 aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy;
490 aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy;
491 aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw;
492 aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw;
493 aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz;
494 aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz;
495 aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw;
496 aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw;
497 aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz;
498 aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz;
500 if (aHitTimes.x != MAXFLOAT)
502 int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2
503 | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y);
505 if (aHitTimes.y != MAXFLOAT)
506 Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26;
508 aNode = aData.y + aChildren.x;
512 toContinue = (aHead >= 0);
514 if (aHead == aStop) // go to top-level BVH
516 aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
523 else if (aData.x < 0) // leaf node (contains triangles)
528 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
530 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
532 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;
533 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;
534 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;
536 IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);
538 if (aTimeUV.x < theHit.Time)
540 aTriIndex = aTriangle;
542 theTrsfId = TRS_OFFSET (aSubTree);
544 theHit = SIntersect (aTimeUV.x, aTimeUV.yz, aNormal);
548 toContinue = (aHead >= 0);
550 if (aHead == aStop) // go to top-level BVH
552 aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
558 else if (aData.x > 0) // switch node
560 aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
562 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
563 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
564 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
565 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
567 aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
572 aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) /
573 max (abs (aSubTree.TrsfRay.Direct), SMALL);
575 aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
581 aNode = BVH_OFFSET (aSubTree); // go to sub-root node
583 aStop = aHead; // store current stack pointer
590 // =======================================================================
591 // function : SceneAnyHit
592 // purpose : Finds intersection with any scene triangle
593 // =======================================================================
594 float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
598 int aNode = 0; // node to traverse
599 int aHead = -1; // pointer of stack
600 int aStop = -1; // BVH level switch
602 SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
604 for (bool toContinue = true; toContinue; /* none */)
606 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
608 if (aData.x == 0) // if inner node
610 aData.y += BVH_OFFSET (aSubTree);
612 vec4 aHitTimes = vec4 (MAXFLOAT,
617 vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse;
619 vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
620 vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
621 vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
622 vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
623 vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
624 vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
625 vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
626 vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
628 vec3 aTimeMax = max (aNodeMin0, aNodeMax0);
629 vec3 aTimeMin = min (aNodeMin0, aNodeMax0);
631 float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
632 float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
634 aHitTimes.x = mix (MAXFLOAT, aTimeEnter,
635 aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f);
637 aTimeMax = max (aNodeMin1, aNodeMax1);
638 aTimeMin = min (aNodeMin1, aNodeMax1);
640 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
641 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
643 aHitTimes.y = mix (MAXFLOAT, aTimeEnter,
644 aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f);
646 aTimeMax = max (aNodeMin2, aNodeMax2);
647 aTimeMin = min (aNodeMin2, aNodeMax2);
649 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
650 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
652 aHitTimes.z = mix (MAXFLOAT, aTimeEnter,
653 aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 1);
655 aTimeMax = max (aNodeMin3, aNodeMax3);
656 aTimeMin = min (aNodeMin3, aNodeMax3);
658 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
659 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
661 aHitTimes.w = mix (MAXFLOAT, aTimeEnter,
662 aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 2);
664 ivec4 aChildren = ivec4 (0, 1, 2, 3);
666 aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy;
667 aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy;
668 aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw;
669 aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw;
670 aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz;
671 aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz;
672 aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw;
673 aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw;
674 aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz;
675 aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz;
677 if (aHitTimes.x != MAXFLOAT)
679 int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2
680 | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y);
682 if (aHitTimes.y != MAXFLOAT)
683 Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26;
685 aNode = aData.y + aChildren.x;
689 toContinue = (aHead >= 0);
691 if (aHead == aStop) // go to top-level BVH
693 aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
700 else if (aData.x < 0) // leaf node
705 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
707 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
709 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;
710 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;
711 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;
713 IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);
715 #ifdef TRANSPARENT_SHADOWS
716 if (aTimeUV.x < theDistance)
718 aFactor *= 1.f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
721 if (aTimeUV.x < theDistance)
728 toContinue = (aHead >= 0);
730 if (aHead == aStop) // go to top-level BVH
732 aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
738 else if (aData.x > 0) // switch node
740 aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
742 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
743 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
744 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
745 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
747 aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
752 aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
758 aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) / max (abs (aSubTree.TrsfRay.Direct), SMALL);
760 aNode = BVH_OFFSET (aSubTree); // go to sub-root node
762 aStop = aHead; // store current stack pointer
769 #define PI 3.1415926f
771 // =======================================================================
772 // function : Latlong
773 // purpose : Converts world direction to environment texture coordinates
774 // =======================================================================
775 vec2 Latlong (in vec3 thePoint, in float theRadius)
777 float aPsi = acos (-thePoint.z / theRadius);
779 float aPhi = atan (thePoint.y, thePoint.x) + PI;
781 return vec2 (aPhi * 0.1591549f,
785 // =======================================================================
786 // function : SmoothNormal
787 // purpose : Interpolates normal across the triangle
788 // =======================================================================
789 vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
791 vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz;
792 vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz;
793 vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz;
795 return normalize (aNormal1 * theUV.x +
797 aNormal0 * (1.0f - theUV.x - theUV.y));
800 // =======================================================================
801 // function : SmoothUV
802 // purpose : Interpolates UV coordinates across the triangle
803 // =======================================================================
805 vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)
807 vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;
808 vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;
809 vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;
811 return aTexCrd1 * theUV.x +
813 aTexCrd0 * (1.0f - theUV.x - theUV.y);
817 // =======================================================================
818 // function : FetchEnvironment
820 // =======================================================================
821 vec4 FetchEnvironment (in vec2 theTexCoord)
823 return mix (vec4 (0.0f, 0.0f, 0.0f, 1.0f),
824 textureLod (uEnvironmentMapTexture, theTexCoord, 0.0f), float (uSphereMapEnabled));
827 // =======================================================================
828 // function : Refract
829 // purpose : Computes refraction ray (also handles TIR)
830 // =======================================================================
832 vec3 Refract (in vec3 theInput,
834 in float theRefractIndex,
835 in float theInvRefractIndex)
837 float aNdotI = dot (theInput, theNormal);
839 float anIndex = aNdotI < 0.0f
843 float aSquare = anIndex * anIndex * (1.0f - aNdotI * aNdotI);
847 return reflect (theInput, theNormal);
850 float aNdotT = sqrt (1.0f - aSquare);
852 return normalize (anIndex * theInput -
853 (anIndex * aNdotI + (aNdotI < 0.0f ? aNdotT : -aNdotT)) * theNormal);
857 #define MIN_SLOPE 0.0001f
858 #define EPS_SCALE 8.0000f
860 #define THRESHOLD vec3 (0.1f)
862 #define INVALID_BOUNCES 1000
864 #define LIGHT_POS(index) (2 * index + 1)
865 #define LIGHT_PWR(index) (2 * index + 0)
867 // =======================================================================
868 // function : Radiance
869 // purpose : Computes color along the given ray
870 // =======================================================================
872 vec4 Radiance (in SRay theRay, in vec3 theInverse)
874 vec3 aResult = vec3 (0.0f);
875 vec4 aWeight = vec4 (1.0f);
879 float anOpenGlDepth = ComputeOpenGlDepth (theRay);
880 float aRaytraceDepth = MAXFLOAT;
882 for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
884 SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
886 ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId);
888 if (aTriIndex.x == -1)
890 vec4 aColor = vec4 (0.0);
892 if (bool(uSphereMapForBack) || aWeight.w == 0.0f /* reflection */)
894 float aTime = IntersectSphere (theRay, uSceneRadius);
896 aColor = FetchEnvironment (Latlong (
897 theRay.Direct * aTime + theRay.Origin, uSceneRadius));
901 vec4 aGlColor = ComputeOpenGlColor();
902 aColor = vec4 (mix (aGlColor.rgb, BackgroundColor().rgb, aGlColor.w), aGlColor.w);
905 aResult += aWeight.xyz * aColor.xyz; aWeight.w *= aColor.w;
907 break; // terminate path
910 vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz;
911 vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz;
912 vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz;
914 aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
915 dot (aInvTransf1, aHit.Normal),
916 dot (aInvTransf2, aHit.Normal)));
918 // For polygons that are parallel to the screen plane, the depth slope
919 // is equal to 1, resulting in small polygon offset. For polygons that
920 // that are at a large angle to the screen, the depth slope tends to 1,
921 // resulting in a larger polygon offset
922 float aPolygonOffset = uSceneEpsilon * EPS_SCALE /
923 max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
925 if (anOpenGlDepth < aHit.Time + aPolygonOffset)
927 vec4 aGlColor = ComputeOpenGlColor();
929 aResult += aWeight.xyz * aGlColor.xyz;
930 aWeight *= aGlColor.w;
933 theRay.Origin += theRay.Direct * aHit.Time; // intersection point
938 // Hit point in NDC-space [-1,1] (the polygon offset is applied in the world space)
939 vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin + theRay.Direct * aPolygonOffset, 1.f);
940 aNDCPoint.xyz *= 1.f / aNDCPoint.w;
942 aRaytraceDepth = aNDCPoint.z * 0.5f + 0.5f;
945 vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
947 aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
948 dot (aInvTransf1, aNormal),
949 dot (aInvTransf2, aNormal)));
951 vec3 aAmbient = texelFetch (
952 uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb;
953 vec4 aDiffuse = texelFetch (
954 uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w));
955 vec4 aSpecular = texelFetch (
956 uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w));
957 vec4 aOpacity = texelFetch (
958 uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w));
961 if (aDiffuse.w >= 0.f)
963 vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);
965 vec4 aTrsfRow1 = texelFetch (
966 uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));
967 vec4 aTrsfRow2 = texelFetch (
968 uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));
970 aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
971 dot (aTrsfRow2, aTexCoord));
973 vec3 aTexColor = textureLod (
974 sampler2D (uTextureSamplers[int(aDiffuse.w)]), aTexCoord.st, 0.f).rgb;
976 aDiffuse.rgb *= aTexColor;
977 aAmbient.rgb *= aTexColor;
981 vec3 aEmission = texelFetch (
982 uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb;
984 float aGeomFactor = dot (aNormal, theRay.Direct);
986 aResult.xyz += aWeight.xyz * aOpacity.x * (
987 uGlobalAmbient.xyz * aAmbient * max (abs (aGeomFactor), 0.5f) + aEmission);
989 vec3 aSidedNormal = mix (aNormal, -aNormal, step (0.0f, aGeomFactor));
991 for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
993 vec4 aLight = texelFetch (
994 uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
996 float aDistance = MAXFLOAT;
998 if (aLight.w != 0.0f) // point light source
1000 aDistance = length (aLight.xyz -= theRay.Origin);
1002 aLight.xyz *= 1.0f / aDistance;
1005 float aLdotN = dot (aLight.xyz, aSidedNormal);
1007 if (aLdotN > 0.0f) // first check if light source is important
1009 float aVisibility = 1.0f;
1011 if (bool(uShadowsEnabled))
1013 SRay aShadow = SRay (theRay.Origin, aLight.xyz);
1015 aShadow.Origin += uSceneEpsilon * (aLight.xyz +
1016 mix (-aHit.Normal, aHit.Normal, step (0.0f, dot (aHit.Normal, aLight.xyz))));
1018 vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL);
1020 aVisibility = SceneAnyHit (
1021 aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance);
1024 if (aVisibility > 0.0f)
1026 vec3 aIntensity = vec3 (texelFetch (
1027 uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
1029 float aRdotV = dot (reflect (aLight.xyz, aSidedNormal), theRay.Direct);
1031 aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity *
1032 (aDiffuse.xyz * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w));
1037 if (aOpacity.x != 1.0f)
1039 aWeight *= aOpacity.y;
1041 if (aOpacity.z != 1.0f)
1043 theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w);
1047 anOpenGlDepth -= aHit.Time + uSceneEpsilon;
1052 aWeight *= bool(uReflectEnabled) ?
1053 texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f);
1055 vec3 aReflect = reflect (theRay.Direct, aNormal);
1057 if (dot (aReflect, aHit.Normal) * dot (theRay.Direct, aHit.Normal) > 0.0f)
1059 aReflect = reflect (theRay.Direct, aHit.Normal);
1062 theRay.Direct = aReflect;
1065 if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
1067 aDepth = INVALID_BOUNCES;
1069 else if (aOpacity.x == 1.0f || aOpacity.z != 1.0f) // if no simple transparency
1071 theRay.Origin += aHit.Normal * mix (
1072 -uSceneEpsilon, uSceneEpsilon, step (0.0f, dot (aHit.Normal, theRay.Direct)));
1074 theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
1076 theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct));
1078 anOpenGlDepth = MAXFLOAT; // disable combining image with OpenGL output
1081 theRay.Origin += theRay.Direct * uSceneEpsilon;
1084 gl_FragDepth = aRaytraceDepth;
1086 return vec4 (aResult.x,