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 //! 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;
48 //! Texture buffer of vertex coords.
49 uniform samplerBuffer uGeometryVertexTexture;
50 //! Texture buffer of vertex normals.
51 uniform samplerBuffer uGeometryNormalTexture;
53 //! Texture buffer of per-vertex UV-coordinates.
54 uniform samplerBuffer uGeometryTexCrdTexture;
56 //! Texture buffer of triangle indices.
57 uniform isamplerBuffer uGeometryTriangTexture;
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;
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;
71 //! Total number of light sources.
72 uniform int uLightCount;
73 //! Intensity of global ambient light.
74 uniform vec4 uGlobalAmbient;
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;
83 //! Radius of bounding sphere of the scene.
84 uniform float uSceneRadius;
85 //! Scene epsilon to prevent self-intersections.
86 uniform float uSceneEpsilon;
89 //! Unique 64-bit handles of OpenGL textures.
90 uniform sampler2D uTextureSamplers[MAX_TEX_NUMBER];
93 /////////////////////////////////////////////////////////////////////////////////////////
94 // Specific data types
96 //! Stores ray parameters.
104 //! Stores intersection parameters.
114 /////////////////////////////////////////////////////////////////////////////////////////
115 // Some useful constants
117 #define MAXFLOAT 1e15f
119 #define SMALL vec3 (exp2 (-80.0f))
121 #define ZERO vec3 (0.0f, 0.0f, 0.0f)
122 #define UNIT vec3 (1.0f, 1.0f, 1.0f)
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)
128 //! 32-bit state of random number generator.
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)
138 RandState = uint (int (gl_FragCoord.y) * uWinSizeX + int (gl_FragCoord.x) + theSeed);
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);
147 // =======================================================================
148 // function : RandInt
149 // purpose : Generates integer using Xorshift algorithm by G. Marsaglia
150 // =======================================================================
153 RandState ^= (RandState << 13);
154 RandState ^= (RandState >> 17);
155 RandState ^= (RandState << 5);
160 // =======================================================================
161 // function : RandFloat
162 // purpose : Generates a random float in [0, 1) range
163 // =======================================================================
166 return float (RandInt()) * (1.f / 4294967296.f);
169 // =======================================================================
170 // function : MatrixColMultiplyPnt
171 // purpose : Multiplies a vector by matrix
172 // =======================================================================
173 vec3 MatrixColMultiplyPnt (in vec3 v,
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]);
184 // =======================================================================
185 // function : MatrixColMultiplyDir
186 // purpose : Multiplies a vector by matrix
187 // =======================================================================
188 vec3 MatrixColMultiplyDir (in vec3 v,
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);
199 /////////////////////////////////////////////////////////////////////////////////////////
200 // Functions for compute ray-object intersection
202 // =======================================================================
203 // function : GenerateRay
205 // =======================================================================
206 SRay GenerateRay (in vec2 thePixel)
208 vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
209 vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
211 vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x);
212 vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x);
214 vec3 aDirection = normalize (mix (aD0, aD1, thePixel.y));
216 return SRay (mix (aP0, aP1, thePixel.y), aDirection);
219 // =======================================================================
220 // function : ComputeOpenGlDepth
222 // =======================================================================
223 float ComputeOpenGlDepth (in SRay theRay)
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,
232 vec4 aFinal = uUnviewMat * aPoint;
233 aFinal.xyz *= 1.f / aFinal.w;
235 return (anOpenGlDepth < 1.f) ? length (aFinal.xyz - theRay.Origin) : MAXFLOAT;
238 // =======================================================================
239 // function : ComputeOpenGlColor
241 // =======================================================================
242 vec4 ComputeOpenGlColor (in SRay theRay)
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);
249 return anOpenGlColor;
252 // =======================================================================
253 // function : IntersectSphere
254 // purpose : Computes ray-sphere intersection
255 // =======================================================================
256 float IntersectSphere (in SRay theRay, in float theRadius)
258 float aDdotD = dot (theRay.Direct, theRay.Direct);
259 float aDdotO = dot (theRay.Direct, theRay.Origin);
260 float aOdotO = dot (theRay.Origin, theRay.Origin);
262 float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);
266 float aTime = (sqrt (aD) - aDdotO) * (1.0f / aDdotD);
268 return aTime > 0.0f ? aTime : MAXFLOAT;
274 // =======================================================================
275 // function : IntersectTriangle
276 // purpose : Computes ray-triangle intersection (branchless version)
277 // =======================================================================
278 float IntersectTriangle (in SRay theRay,
285 vec3 aEdge0 = thePnt1 - thePnt0;
286 vec3 aEdge1 = thePnt0 - thePnt2;
288 theNorm = cross (aEdge1, aEdge0);
290 vec3 aEdge2 = (1.0f / dot (theNorm, theRay.Direct)) * (thePnt0 - theRay.Origin);
292 float aTime = dot (theNorm, aEdge2);
294 vec3 theVec = cross (theRay.Direct, aEdge2);
296 theUV.x = dot (theVec, aEdge1);
297 theUV.y = dot (theVec, aEdge0);
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;
305 //! Identifies the absence of intersection.
306 #define INALID_HIT ivec4 (-1)
308 //! Global stack shared between traversal functions.
309 int Stack[STACK_SIZE];
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)
318 int aHead = theSentinel; // stack pointer
319 int aNode = theBVHOffset; // node to visit
321 ivec4 aTriIndex = INALID_HIT;
323 bool toContinue = true;
327 ivec3 aData = texelFetch (uSceneNodeInfoTexture, aNode).xyz;
329 if (aData.x == 0) // if inner node
335 aData.y += theBVHOffset;
336 aData.z += theBVHOffset;
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;
343 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
344 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
346 vec3 aTimeMax = max (aTime0, aTime1);
347 vec3 aTimeMin = min (aTime0, aTime1);
349 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
350 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
352 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
353 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
355 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theHit.Time);
357 aTimeMax = max (aTime0, aTime1);
358 aTimeMin = min (aTime0, aTime1);
360 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
361 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
363 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
365 if (bool(aHitLft & aHitRgh))
367 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
369 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
373 if (bool(aHitLft | aHitRgh))
375 aNode = bool(aHitLft) ? aData.y : aData.z;
379 toContinue = (aHead != theSentinel);
382 aNode = Stack[aHead--];
391 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
393 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
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;
399 float aTime = IntersectTriangle (theRay,
406 if (aTime < theHit.Time)
408 aTriIndex = aTriangle;
410 theHit = SIntersect (aTime, aParams, aNormal);
414 toContinue = (aHead != theSentinel);
417 aNode = Stack[aHead--];
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)
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)
442 int aHead = theSentinel; // stack pointer
443 int aNode = theBVHOffset; // node to visit
445 #ifdef TRANSPARENT_SHADOWS
446 float aFactor = 1.0f;
451 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
453 if (aData.x == 0) // if inner node
459 aData.y += theBVHOffset;
460 aData.z += theBVHOffset;
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;
467 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
468 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
470 vec3 aTimeMax = max (aTime0, aTime1);
471 vec3 aTimeMin = min (aTime0, aTime1);
473 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
474 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
476 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
477 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
479 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
481 aTimeMax = max (aTime0, aTime1);
482 aTimeMin = min (aTime0, aTime1);
484 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
485 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
487 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
489 if (bool(aHitLft & aHitRgh))
491 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
493 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
497 if (bool(aHitLft | aHitRgh))
499 aNode = bool(aHitLft) ? aData.y : aData.z;
503 #ifdef TRANSPARENT_SHADOWS
504 if (aHead == theSentinel)
507 if (aHead == theSentinel)
511 aNode = Stack[aHead--];
520 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
522 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
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;
528 float aTime = IntersectTriangle (theRay,
535 #ifdef TRANSPARENT_SHADOWS
536 if (aTime < theDistance)
538 aFactor *= 1.0f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
541 if (aTime < theDistance)
546 #ifdef TRANSPARENT_SHADOWS
547 if (aHead == theSentinel || aFactor < 0.1f)
550 if (aHead == theSentinel)
554 aNode = Stack[aHead--];
558 #ifdef TRANSPARENT_SHADOWS
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)
571 int aHead = -1; // stack pointer
572 int aNode = 0; // node to visit
574 ivec4 aHitObject = INALID_HIT;
578 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
580 if (aData.x != 0) // if leaf node
582 vec3 aNodeMin = texelFetch (uSceneMinPointTexture, aNode).xyz;
583 vec3 aNodeMax = texelFetch (uSceneMaxPointTexture, aNode).xyz;
585 vec3 aTime0 = (aNodeMin - theRay.Origin) * theInverse;
586 vec3 aTime1 = (aNodeMax - theRay.Origin) * theInverse;
588 vec3 aTimes = min (aTime0, aTime1);
590 if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
592 // fetch object transformation
593 int anObjectId = aData.x - 1;
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);
600 SRay aTrsfRay = SRay (
601 MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
602 MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
604 vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
606 aTrsfInverse = mix (-aTrsfInverse, aTrsfInverse, step (ZERO, aTrsfRay.Direct));
608 ivec4 aTriIndex = ObjectNearestHit (
609 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theHit, aHead);
611 if (aTriIndex.x != -1)
613 aHitObject = ivec4 (aTriIndex.x, // vertex 0
614 aTriIndex.y, // vertex 1
615 aTriIndex.z, // vertex 2
616 aTriIndex.w); // material
618 theObjectId = anObjectId;
625 aNode = Stack[aHead--];
627 else // if inner node
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;
638 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
639 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
641 vec3 aTimeMax = max (aTime0, aTime1);
642 vec3 aTimeMin = min (aTime0, aTime1);
644 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
645 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
647 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theHit.Time);
649 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
650 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
652 aTimeMax = max (aTime0, aTime1);
653 aTimeMin = min (aTime0, aTime1);
655 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
656 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
658 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
660 if (bool(aHitLft & aHitRgh))
662 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
664 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
668 if (bool(aHitLft | aHitRgh))
670 aNode = bool(aHitLft) ? aData.y : aData.z;
677 aNode = Stack[aHead--];
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)
692 int aHead = -1; // stack pointer
693 int aNode = 0; // node to visit
695 #ifdef TRANSPARENT_SHADOWS
696 float aFactor = 1.0f;
701 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
703 if (aData.x != 0) // if leaf node
705 // fetch object transformation
706 int anObjectId = aData.x - 1;
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);
713 SRay aTrsfRay = SRay (
714 MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
715 MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
717 vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
719 aTrsfInverse = mix (-aTrsfInverse, aTrsfInverse, step (ZERO, aTrsfRay.Direct));
721 #ifdef TRANSPARENT_SHADOWS
722 aFactor *= ObjectAnyHit (
723 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
725 if (aHead < 0 || aFactor < 0.1f)
728 bool isShadow = 0.0f == ObjectAnyHit (
729 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
731 if (aHead < 0 || isShadow)
732 return isShadow ? 0.0f : 1.0f;
735 aNode = Stack[aHead--];
737 else // if inner node
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;
748 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
749 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
751 vec3 aTimeMax = max (aTime0, aTime1);
752 vec3 aTimeMin = min (aTime0, aTime1);
754 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
755 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
757 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
759 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
760 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
762 aTimeMax = max (aTime0, aTime1);
763 aTimeMin = min (aTime0, aTime1);
765 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
766 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
768 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
770 if (bool(aHitLft & aHitRgh))
772 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
774 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
778 if (bool(aHitLft | aHitRgh))
780 aNode = bool(aHitLft) ? aData.y : aData.z;
784 #ifdef TRANSPARENT_SHADOWS
792 aNode = Stack[aHead--];
798 #ifdef TRANSPARENT_SHADOWS
805 #define PI 3.1415926f
807 // =======================================================================
808 // function : Latlong
809 // purpose : Converts world direction to environment texture coordinates
810 // =======================================================================
811 vec2 Latlong (in vec3 thePoint, in float theRadius)
813 float aPsi = acos (-thePoint.z / theRadius);
815 float aPhi = atan (thePoint.y, thePoint.x) + PI;
817 return vec2 (aPhi * 0.1591549f,
821 // =======================================================================
822 // function : SmoothNormal
823 // purpose : Interpolates normal across the triangle
824 // =======================================================================
825 vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
827 vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz;
828 vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz;
829 vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz;
831 return normalize (aNormal1 * theUV.x +
833 aNormal0 * (1.0f - theUV.x - theUV.y));
836 // =======================================================================
837 // function : SmoothUV
838 // purpose : Interpolates UV coordinates across the triangle
839 // =======================================================================
841 vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)
843 vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;
844 vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;
845 vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;
847 return aTexCrd1 * theUV.x +
849 aTexCrd0 * (1.0f - theUV.x - theUV.y);
853 // =======================================================================
854 // function : Refract
855 // purpose : Computes refraction ray (also handles TIR)
856 // =======================================================================
857 vec3 Refract (in vec3 theInput,
859 in float theRefractIndex,
860 in float theInvRefractIndex)
862 float aNdotI = dot (theInput, theNormal);
864 float anIndex = aNdotI < 0.0f
868 float aSquare = anIndex * anIndex * (1.0f - aNdotI * aNdotI);
872 return reflect (theInput, theNormal);
875 float aNdotT = sqrt (1.0f - aSquare);
877 return normalize (anIndex * theInput -
878 (anIndex * aNdotI + (aNdotI < 0.0f ? aNdotT : -aNdotT)) * theNormal);
881 #define MIN_SLOPE 0.0001f
882 #define EPS_SCALE 8.0000f
884 #define THRESHOLD vec3 (0.1f)
886 #define INVALID_BOUNCES 1000
888 #define LIGHT_POS(index) (2 * index + 1)
889 #define LIGHT_PWR(index) (2 * index + 0)
891 // =======================================================================
892 // function : Radiance
893 // purpose : Computes color along the given ray
894 // =======================================================================
895 vec4 Radiance (in SRay theRay, in vec3 theInverse)
897 vec3 aResult = vec3 (0.0f);
898 vec4 aWeight = vec4 (1.0f);
902 float anOpenGlDepth = ComputeOpenGlDepth (theRay);
904 for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
906 SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
908 ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
910 if (aTriIndex.x == -1)
912 vec4 aColor = vec4 (0.0f);
914 if (aWeight.w != 0.0f)
916 aColor = anOpenGlDepth != MAXFLOAT ?
917 ComputeOpenGlColor (theRay) : vec4 (0.0f, 0.0f, 0.0f, 1.0f);
919 else if (bool(uEnvironmentEnable))
921 float aTime = IntersectSphere (theRay, uSceneRadius);
923 aColor = textureLod (uEnvironmentMapTexture, Latlong (
924 theRay.Direct * aTime + theRay.Origin, uSceneRadius), 0.0f);
927 return vec4 (aResult.xyz + aWeight.xyz * aColor.xyz, aWeight.w * aColor.w);
930 aHit.Normal = normalize (aHit.Normal);
932 // For polygons that are parallel to the screen plane, the depth slope
933 // is equal to 1, resulting in small polygon offset. For polygons that
934 // that are at a large angle to the screen, the depth slope tends to 1,
935 // resulting in a larger polygon offset
936 float aPolygonOffset = uSceneEpsilon * EPS_SCALE /
937 max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
939 if (anOpenGlDepth < aHit.Time + aPolygonOffset)
941 vec4 aGlColor = ComputeOpenGlColor (theRay);
943 aResult += aWeight.xyz * aGlColor.xyz;
944 aWeight *= aGlColor.w;
947 theRay.Origin += theRay.Direct * aHit.Time; // intersection point
949 vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0).xyz;
950 vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1).xyz;
951 vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2).xyz;
953 vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
955 aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
956 dot (aInvTransf1, aNormal),
957 dot (aInvTransf2, aNormal)));
959 vec3 aAmbient = texelFetch (
960 uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb;
961 vec4 aDiffuse = texelFetch (
962 uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w));
963 vec4 aSpecular = texelFetch (
964 uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w));
965 vec4 aOpacity = texelFetch (
966 uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w));
969 if (aDiffuse.w >= 0.f)
971 vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);
973 vec4 aTrsfRow1 = texelFetch (
974 uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));
975 vec4 aTrsfRow2 = texelFetch (
976 uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));
978 aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
979 dot (aTrsfRow2, aTexCoord));
981 vec3 aTexColor = textureLod (
982 uTextureSamplers[int(aDiffuse.w)], aTexCoord.st, 0.f).rgb;
984 aDiffuse.rgb *= aTexColor;
985 aAmbient.rgb *= aTexColor;
989 vec3 aEmission = texelFetch (
990 uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb;
992 float aGeomFactor = dot (aNormal, theRay.Direct);
994 aResult.xyz += aWeight.xyz * aOpacity.x * (
995 uGlobalAmbient.xyz * aAmbient * max (abs (aGeomFactor), 0.5f) + aEmission);
997 vec3 aSidedNormal = mix (aNormal, -aNormal, step (0.0f, aGeomFactor));
999 for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
1001 vec4 aLight = texelFetch (
1002 uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
1004 float aDistance = MAXFLOAT;
1006 if (aLight.w != 0.0f) // point light source
1008 aDistance = length (aLight.xyz -= theRay.Origin);
1010 aLight.xyz *= 1.0f / aDistance;
1013 float aLdotN = dot (aLight.xyz, aSidedNormal);
1015 if (aLdotN > 0.0f) // first check if light source is important
1017 float aVisibility = 1.0f;
1019 if (bool(uShadowsEnable))
1021 SRay aShadow = SRay (theRay.Origin, aLight.xyz);
1023 aShadow.Origin += uSceneEpsilon * (aLight.xyz +
1024 mix (-aHit.Normal, aHit.Normal, step (0.0f, dot (aHit.Normal, aLight.xyz))));
1026 vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL);
1028 aVisibility = SceneAnyHit (
1029 aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance);
1032 if (aVisibility > 0.0f)
1034 vec3 aIntensity = vec3 (texelFetch (
1035 uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
1037 float aRdotV = dot (reflect (aLight.xyz, aSidedNormal), theRay.Direct);
1039 aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity *
1040 (aDiffuse.xyz * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w));
1045 if (aOpacity.x != 1.0f)
1047 aWeight *= aOpacity.y;
1049 if (aOpacity.z != 1.0f)
1051 theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w);
1055 anOpenGlDepth -= aHit.Time + uSceneEpsilon;
1060 aWeight *= bool(uReflectionsEnable) ?
1061 texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f);
1063 vec3 aReflect = reflect (theRay.Direct, aNormal);
1065 if (dot (aReflect, aHit.Normal) * dot (theRay.Direct, aHit.Normal) > 0.0f)
1067 aReflect = reflect (theRay.Direct, aHit.Normal);
1070 theRay.Direct = aReflect;
1073 if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
1075 aDepth = INVALID_BOUNCES;
1077 else if (aOpacity.x == 1.0f || aOpacity.z != 1.0f) // if no simple transparency
1079 theRay.Origin += aHit.Normal * mix (
1080 -uSceneEpsilon, uSceneEpsilon, step (0.0f, dot (aHit.Normal, theRay.Direct)));
1082 theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
1084 theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct));
1086 anOpenGlDepth = MAXFLOAT; // disable combining image with OpenGL output
1089 theRay.Origin += theRay.Direct * uSceneEpsilon;
1092 return vec4 (aResult.x,