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 high-level BVH nodes.
40 uniform isamplerBuffer uSceneNodeInfoTexture;
41 //! Texture buffer of minimum points of high-level BVH nodes.
42 uniform samplerBuffer uSceneMinPointTexture;
43 //! Texture buffer of maximum points of high-level BVH nodes.
44 uniform samplerBuffer uSceneMaxPointTexture;
45 //! Texture buffer of transformations of high-level BVH nodes.
46 uniform samplerBuffer uSceneTransformTexture;
48 //! Texture buffer of data records of bottom-level BVH nodes.
49 uniform isamplerBuffer uObjectNodeInfoTexture;
50 //! Texture buffer of minimum points of bottom-level BVH nodes.
51 uniform samplerBuffer uObjectMinPointTexture;
52 //! Texture buffer of maximum points of bottom-level BVH nodes.
53 uniform samplerBuffer uObjectMaxPointTexture;
55 //! Texture buffer of vertex coords.
56 uniform samplerBuffer uGeometryVertexTexture;
57 //! Texture buffer of vertex normals.
58 uniform samplerBuffer uGeometryNormalTexture;
60 //! Texture buffer of per-vertex UV-coordinates.
61 uniform samplerBuffer uGeometryTexCrdTexture;
63 //! Texture buffer of triangle indices.
64 uniform isamplerBuffer uGeometryTriangTexture;
66 //! Texture buffer of material properties.
67 uniform samplerBuffer uRaytraceMaterialTexture;
68 //! Texture buffer of light source properties.
69 uniform samplerBuffer uRaytraceLightSrcTexture;
70 //! Environment map texture.
71 uniform sampler2D uEnvironmentMapTexture;
73 //! Input pre-raytracing image rendered by OpenGL.
74 uniform sampler2D uOpenGlColorTexture;
75 //! Input pre-raytracing depth image rendered by OpenGL.
76 uniform sampler2D uOpenGlDepthTexture;
78 //! Total number of light sources.
79 uniform int uLightCount;
80 //! Intensity of global ambient light.
81 uniform vec4 uGlobalAmbient;
83 //! Enables/disables environment map.
84 uniform int uEnvironmentEnable;
85 //! Enables/disables computation of shadows.
86 uniform int uShadowsEnable;
87 //! Enables/disables computation of reflections.
88 uniform int uReflectionsEnable;
90 //! Radius of bounding sphere of the scene.
91 uniform float uSceneRadius;
92 //! Scene epsilon to prevent self-intersections.
93 uniform float uSceneEpsilon;
96 //! Unique 64-bit handles of OpenGL textures.
97 uniform sampler2D uTextureSamplers[MAX_TEX_NUMBER];
100 /////////////////////////////////////////////////////////////////////////////////////////
101 // Specific data types
103 //! Stores ray parameters.
111 //! Stores intersection parameters.
121 /////////////////////////////////////////////////////////////////////////////////////////
122 // Some useful constants
124 #define MAXFLOAT 1e15f
126 #define SMALL vec3 (exp2 (-80.0f))
128 #define ZERO vec3 (0.0f, 0.0f, 0.0f)
129 #define UNIT vec3 (1.0f, 1.0f, 1.0f)
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)
135 // =======================================================================
136 // function : MatrixRowMultiplyDir
137 // purpose : Multiplies a vector by matrix
138 // =======================================================================
139 vec3 MatrixRowMultiplyDir (in vec3 v,
144 return vec3 (dot (m0.xyz, v),
149 //! 32-bit state of random number generator.
152 // =======================================================================
153 // function : SeedRand
154 // purpose : Applies hash function by Thomas Wang to randomize seeds
155 // (see http://www.burtleburtle.net/bob/hash/integer.html)
156 // =======================================================================
157 void SeedRand (in int theSeed)
159 RandState = uint (int (gl_FragCoord.y) * uWinSizeX + int (gl_FragCoord.x) + theSeed);
161 RandState = (RandState + 0x479ab41du) + (RandState << 8);
162 RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >> 5);
163 RandState = (RandState + 0x9942f0a6u) - (RandState << 14);
164 RandState = (RandState ^ 0x5aedd67du) ^ (RandState >> 3);
165 RandState = (RandState + 0x17bea992u) + (RandState << 7);
168 // =======================================================================
169 // function : RandInt
170 // purpose : Generates integer using Xorshift algorithm by G. Marsaglia
171 // =======================================================================
174 RandState ^= (RandState << 13);
175 RandState ^= (RandState >> 17);
176 RandState ^= (RandState << 5);
181 // =======================================================================
182 // function : RandFloat
183 // purpose : Generates a random float in [0, 1) range
184 // =======================================================================
187 return float (RandInt()) * (1.f / 4294967296.f);
190 // =======================================================================
191 // function : MatrixColMultiplyPnt
192 // purpose : Multiplies a vector by matrix
193 // =======================================================================
194 vec3 MatrixColMultiplyPnt (in vec3 v,
200 return vec3 (m0[0] * v.x + m1[0] * v.y + m2[0] * v.z + m3[0],
201 m0[1] * v.x + m1[1] * v.y + m2[1] * v.z + m3[1],
202 m0[2] * v.x + m1[2] * v.y + m2[2] * v.z + m3[2]);
205 // =======================================================================
206 // function : MatrixColMultiplyDir
207 // purpose : Multiplies a vector by matrix
208 // =======================================================================
209 vec3 MatrixColMultiplyDir (in vec3 v,
215 return vec3 (m0[0] * v.x + m1[0] * v.y + m2[0] * v.z,
216 m0[1] * v.x + m1[1] * v.y + m2[1] * v.z,
217 m0[2] * v.x + m1[2] * v.y + m2[2] * v.z);
220 /////////////////////////////////////////////////////////////////////////////////////////
221 // Functions for compute ray-object intersection
223 // =======================================================================
224 // function : GenerateRay
226 // =======================================================================
227 SRay GenerateRay (in vec2 thePixel)
229 vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
230 vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
232 vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x);
233 vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x);
235 vec3 aDirection = normalize (mix (aD0, aD1, thePixel.y));
237 return SRay (mix (aP0, aP1, thePixel.y), aDirection);
240 // =======================================================================
241 // function : ComputeOpenGlDepth
243 // =======================================================================
244 float ComputeOpenGlDepth (in SRay theRay)
246 // a depth in range [0,1]
247 float anOpenGlDepth = texelFetch (uOpenGlDepthTexture, ivec2 (gl_FragCoord.xy), 0).r;
248 // pixel point in NDC-space [-1,1]
249 vec4 aPoint = vec4 (2.0f * vPixel.x - 1.0f,
250 2.0f * vPixel.y - 1.0f,
251 2.0f * anOpenGlDepth - 1.0f,
253 vec4 aFinal = uUnviewMat * aPoint;
254 aFinal.xyz *= 1.f / aFinal.w;
256 return (anOpenGlDepth < 1.f) ? length (aFinal.xyz - theRay.Origin) : MAXFLOAT;
259 // =======================================================================
260 // function : ComputeOpenGlColor
262 // =======================================================================
263 vec4 ComputeOpenGlColor (in SRay theRay)
265 vec4 anOpenGlColor = texelFetch (uOpenGlColorTexture, ivec2 (gl_FragCoord.xy), 0);
266 // During blending with factors GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA (for text and markers)
267 // the alpha channel (written in the color buffer) was squared.
268 anOpenGlColor.a = 1.f - sqrt (anOpenGlColor.a);
270 return anOpenGlColor;
273 // =======================================================================
274 // function : IntersectSphere
275 // purpose : Computes ray-sphere intersection
276 // =======================================================================
277 float IntersectSphere (in SRay theRay, in float theRadius)
279 float aDdotD = dot (theRay.Direct, theRay.Direct);
280 float aDdotO = dot (theRay.Direct, theRay.Origin);
281 float aOdotO = dot (theRay.Origin, theRay.Origin);
283 float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);
287 float aTime = (sqrt (aD) - aDdotO) * (1.0f / aDdotD);
289 return aTime > 0.0f ? aTime : MAXFLOAT;
295 // =======================================================================
296 // function : IntersectTriangle
297 // purpose : Computes ray-triangle intersection (branchless version)
298 // =======================================================================
299 float IntersectTriangle (in SRay theRay,
306 vec3 aEdge0 = thePnt1 - thePnt0;
307 vec3 aEdge1 = thePnt0 - thePnt2;
309 theNorm = cross (aEdge1, aEdge0);
311 vec3 aEdge2 = (1.0f / dot (theNorm, theRay.Direct)) * (thePnt0 - theRay.Origin);
313 float aTime = dot (theNorm, aEdge2);
315 vec3 theVec = cross (theRay.Direct, aEdge2);
317 theUV.x = dot (theVec, aEdge1);
318 theUV.y = dot (theVec, aEdge0);
320 return bool (int(aTime >= 0.0f) &
321 int(theUV.x >= 0.0f) &
322 int(theUV.y >= 0.0f) &
323 int(theUV.x + theUV.y <= 1.0f)) ? aTime : MAXFLOAT;
326 //! Identifies the absence of intersection.
327 #define INALID_HIT ivec4 (-1)
329 //! Global stack shared between traversal functions.
330 int Stack[STACK_SIZE];
332 // =======================================================================
333 // function : ObjectNearestHit
334 // purpose : Finds intersection with nearest object triangle
335 // =======================================================================
336 ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
337 in SRay theRay, in vec3 theInverse, inout SIntersect theHit, in int theSentinel)
339 int aHead = theSentinel; // stack pointer
340 int aNode = theBVHOffset; // node to visit
342 ivec4 aTriIndex = INALID_HIT;
346 ivec3 aData = texelFetch (uObjectNodeInfoTexture, aNode).xyz;
348 if (aData.x == 0) // if inner node
354 aData.y += theBVHOffset;
355 aData.z += theBVHOffset;
357 vec3 aNodeMinLft = texelFetch (uObjectMinPointTexture, aData.y).xyz;
358 vec3 aNodeMaxLft = texelFetch (uObjectMaxPointTexture, aData.y).xyz;
359 vec3 aNodeMinRgh = texelFetch (uObjectMinPointTexture, aData.z).xyz;
360 vec3 aNodeMaxRgh = texelFetch (uObjectMaxPointTexture, aData.z).xyz;
362 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
363 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
365 vec3 aTimeMax = max (aTime0, aTime1);
366 vec3 aTimeMin = min (aTime0, aTime1);
368 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
369 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
371 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
372 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
374 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theHit.Time);
376 aTimeMax = max (aTime0, aTime1);
377 aTimeMin = min (aTime0, aTime1);
379 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
380 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
382 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
384 if (bool(aHitLft & aHitRgh))
386 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
388 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
392 if (bool(aHitLft | aHitRgh))
394 aNode = bool(aHitLft) ? aData.y : aData.z;
398 if (aHead == theSentinel)
401 aNode = Stack[aHead--];
410 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
412 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
414 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += theVrtOffset).xyz;
415 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += theVrtOffset).xyz;
416 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += theVrtOffset).xyz;
418 float aTime = IntersectTriangle (theRay,
425 if (aTime < theHit.Time)
427 aTriIndex = aTriangle;
429 theHit = SIntersect (aTime, aParams, aNormal);
433 if (aHead == theSentinel)
436 aNode = Stack[aHead--];
443 #define MATERIAL_AMBN(index) (11 * index + 0)
444 #define MATERIAL_DIFF(index) (11 * index + 1)
445 #define MATERIAL_SPEC(index) (11 * index + 2)
446 #define MATERIAL_EMIS(index) (11 * index + 3)
447 #define MATERIAL_REFL(index) (11 * index + 4)
448 #define MATERIAL_REFR(index) (11 * index + 5)
449 #define MATERIAL_TRAN(index) (11 * index + 6)
450 #define MATERIAL_TRS1(index) (11 * index + 7)
451 #define MATERIAL_TRS2(index) (11 * index + 8)
452 #define MATERIAL_TRS3(index) (11 * index + 9)
454 // =======================================================================
455 // function : ObjectAnyHit
456 // purpose : Finds intersection with any object triangle
457 // =======================================================================
458 float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
459 in SRay theRay, in vec3 theInverse, in float theDistance, in int theSentinel)
461 int aHead = theSentinel; // stack pointer
462 int aNode = theBVHOffset; // node to visit
464 #ifdef TRANSPARENT_SHADOWS
465 float aFactor = 1.0f;
470 ivec4 aData = texelFetch (uObjectNodeInfoTexture, aNode);
472 if (aData.x == 0) // if inner node
478 aData.y += theBVHOffset;
479 aData.z += theBVHOffset;
481 vec3 aNodeMinLft = texelFetch (uObjectMinPointTexture, aData.y).xyz;
482 vec3 aNodeMaxLft = texelFetch (uObjectMaxPointTexture, aData.y).xyz;
483 vec3 aNodeMinRgh = texelFetch (uObjectMinPointTexture, aData.z).xyz;
484 vec3 aNodeMaxRgh = texelFetch (uObjectMaxPointTexture, aData.z).xyz;
486 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
487 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
489 vec3 aTimeMax = max (aTime0, aTime1);
490 vec3 aTimeMin = min (aTime0, aTime1);
492 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
493 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
495 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
496 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
498 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
500 aTimeMax = max (aTime0, aTime1);
501 aTimeMin = min (aTime0, aTime1);
503 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
504 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
506 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
508 if (bool(aHitLft & aHitRgh))
510 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
512 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
516 if (bool(aHitLft | aHitRgh))
518 aNode = bool(aHitLft) ? aData.y : aData.z;
522 #ifdef TRANSPARENT_SHADOWS
523 if (aHead == theSentinel)
526 if (aHead == theSentinel)
530 aNode = Stack[aHead--];
539 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
541 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
543 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x + theVrtOffset).xyz;
544 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y + theVrtOffset).xyz;
545 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z + theVrtOffset).xyz;
547 float aTime = IntersectTriangle (theRay,
554 #ifdef TRANSPARENT_SHADOWS
555 if (aTime < theDistance)
557 aFactor *= 1.0f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
560 if (aTime < theDistance)
565 #ifdef TRANSPARENT_SHADOWS
566 if (aHead == theSentinel || aFactor < 0.1f)
569 if (aHead == theSentinel)
573 aNode = Stack[aHead--];
577 #ifdef TRANSPARENT_SHADOWS
584 // =======================================================================
585 // function : SceneNearestHit
586 // purpose : Finds intersection with nearest scene triangle
587 // =======================================================================
588 ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theObjectId)
590 int aHead = -1; // stack pointer
591 int aNode = 0; // node to visit
593 ivec4 aHitObject = INALID_HIT;
597 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
599 if (aData.x != 0) // if leaf node
601 vec3 aNodeMin = texelFetch (uSceneMinPointTexture, aNode).xyz;
602 vec3 aNodeMax = texelFetch (uSceneMaxPointTexture, aNode).xyz;
604 vec3 aTime0 = (aNodeMin - theRay.Origin) * theInverse;
605 vec3 aTime1 = (aNodeMax - theRay.Origin) * theInverse;
607 vec3 aTimes = min (aTime0, aTime1);
609 if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
611 // fetch object transformation
612 int anObjectId = aData.x - 1;
614 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
615 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
616 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
617 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
619 SRay aTrsfRay = SRay (
620 MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
621 MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
623 vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
625 aTrsfInverse.x = aTrsfRay.Direct.x < 0.f ? -aTrsfInverse.x : aTrsfInverse.x;
626 aTrsfInverse.y = aTrsfRay.Direct.y < 0.f ? -aTrsfInverse.y : aTrsfInverse.y;
627 aTrsfInverse.z = aTrsfRay.Direct.z < 0.f ? -aTrsfInverse.z : aTrsfInverse.z;
629 ivec4 aTriIndex = ObjectNearestHit (
630 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theHit, aHead);
632 if (aTriIndex.x != -1)
634 aHitObject = ivec4 (aTriIndex.x, // vertex 0
635 aTriIndex.y, // vertex 1
636 aTriIndex.z, // vertex 2
637 aTriIndex.w); // material
639 theObjectId = anObjectId;
646 aNode = Stack[aHead--];
648 else // if inner node
654 vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
655 vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
656 vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
657 vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
659 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
660 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
662 vec3 aTimeMax = max (aTime0, aTime1);
663 vec3 aTimeMin = min (aTime0, aTime1);
665 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
666 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
668 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theHit.Time);
670 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
671 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
673 aTimeMax = max (aTime0, aTime1);
674 aTimeMin = min (aTime0, aTime1);
676 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
677 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
679 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
681 if (bool(aHitLft & aHitRgh))
683 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
685 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
689 if (bool(aHitLft | aHitRgh))
691 aNode = bool(aHitLft) ? aData.y : aData.z;
698 aNode = Stack[aHead--];
707 // =======================================================================
708 // function : SceneAnyHit
709 // purpose : Finds intersection with any scene triangle
710 // =======================================================================
711 float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
713 int aHead = -1; // stack pointer
714 int aNode = 0; // node to visit
716 #ifdef TRANSPARENT_SHADOWS
717 float aFactor = 1.0f;
722 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
724 if (aData.x != 0) // if leaf node
726 // fetch object transformation
727 int anObjectId = aData.x - 1;
729 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
730 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
731 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
732 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
734 SRay aTrsfRay = SRay (
735 MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
736 MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
738 vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
740 aTrsfInverse.x = aTrsfRay.Direct.x < 0.0f ? -aTrsfInverse.x : aTrsfInverse.x;
741 aTrsfInverse.y = aTrsfRay.Direct.y < 0.0f ? -aTrsfInverse.y : aTrsfInverse.y;
742 aTrsfInverse.z = aTrsfRay.Direct.z < 0.0f ? -aTrsfInverse.z : aTrsfInverse.z;
744 #ifdef TRANSPARENT_SHADOWS
745 aFactor *= ObjectAnyHit (
746 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
748 if (aHead < 0 || aFactor < 0.1f)
751 bool isShadow = 0.0f == ObjectAnyHit (
752 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
754 if (aHead < 0 || isShadow)
755 return isShadow ? 0.0f : 1.0f;
758 aNode = Stack[aHead--];
760 else // if inner node
766 vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
767 vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
768 vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
769 vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
771 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
772 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
774 vec3 aTimeMax = max (aTime0, aTime1);
775 vec3 aTimeMin = min (aTime0, aTime1);
777 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
778 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
780 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
782 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
783 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
785 aTimeMax = max (aTime0, aTime1);
786 aTimeMin = min (aTime0, aTime1);
788 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
789 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
791 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
793 if (bool(aHitLft & aHitRgh))
795 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
797 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
801 if (bool(aHitLft | aHitRgh))
803 aNode = bool(aHitLft) ? aData.y : aData.z;
807 #ifdef TRANSPARENT_SHADOWS
815 aNode = Stack[aHead--];
821 #ifdef TRANSPARENT_SHADOWS
828 #define PI 3.1415926f
830 // =======================================================================
831 // function : Latlong
832 // purpose : Converts world direction to environment texture coordinates
833 // =======================================================================
834 vec2 Latlong (in vec3 thePoint, in float theRadius)
836 float aPsi = acos (-thePoint.z / theRadius);
838 float aPhi = atan (thePoint.y, thePoint.x) + PI;
840 return vec2 (aPhi * 0.1591549f,
844 // =======================================================================
845 // function : SmoothNormal
846 // purpose : Interpolates normal across the triangle
847 // =======================================================================
848 vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
850 vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz;
851 vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz;
852 vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz;
854 return normalize (aNormal1 * theUV.x +
856 aNormal0 * (1.0f - theUV.x - theUV.y));
859 // =======================================================================
860 // function : SmoothUV
861 // purpose : Interpolates UV coordinates across the triangle
862 // =======================================================================
864 vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)
866 vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;
867 vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;
868 vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;
870 return aTexCrd1 * theUV.x +
872 aTexCrd0 * (1.0f - theUV.x - theUV.y);
876 // =======================================================================
877 // function : Refract
878 // purpose : Computes refraction ray (also handles TIR)
879 // =======================================================================
880 vec3 Refract (in vec3 theInput,
882 in float theRefractIndex,
883 in float theInvRefractIndex)
885 float aNdotI = dot (theInput, theNormal);
887 float anIndex = aNdotI < 0.0f
891 float aSquare = anIndex * anIndex * (1.0f - aNdotI * aNdotI);
895 return reflect (theInput, theNormal);
898 float aNdotT = sqrt (1.0f - aSquare);
900 return normalize (anIndex * theInput -
901 (anIndex * aNdotI + (aNdotI < 0.0f ? aNdotT : -aNdotT)) * theNormal);
904 #define MIN_SLOPE 0.0001f
905 #define EPS_SCALE 8.0000f
907 #define THRESHOLD vec3 (0.1f)
909 #define LIGHT_POS(index) (2 * index + 1)
910 #define LIGHT_PWR(index) (2 * index + 0)
912 // =======================================================================
913 // function : Radiance
914 // purpose : Computes color along the given ray
915 // =======================================================================
916 vec4 Radiance (in SRay theRay, in vec3 theInverse)
918 vec3 aResult = vec3 (0.0f);
919 vec4 aWeight = vec4 (1.0f);
923 float anOpenGlDepth = ComputeOpenGlDepth (theRay);
925 for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
927 SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
929 ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
931 if (aTriIndex.x == -1)
933 vec4 aColor = vec4 (0.0f, 0.0f, 0.0f, 1.0f);
935 if (aWeight.w != 0.0f)
937 if (anOpenGlDepth != MAXFLOAT)
938 aColor = ComputeOpenGlColor (theRay);
940 else if (bool(uEnvironmentEnable))
942 float aTime = IntersectSphere (theRay, uSceneRadius);
944 aColor = textureLod (uEnvironmentMapTexture, Latlong (
945 theRay.Direct * aTime + theRay.Origin, uSceneRadius), 0.0f);
948 return vec4 (aResult.xyz + aWeight.xyz * aColor.xyz, aWeight.w * aColor.w);
951 aHit.Normal = normalize (aHit.Normal);
953 // For polygons that are parallel to the screen plane, the depth slope
954 // is equal to 1, resulting in small polygon offset. For polygons that
955 // that are at a large angle to the screen, the depth slope tends to 1,
956 // resulting in a larger polygon offset
957 float aPolygonOffset = uSceneEpsilon * min (
958 EPS_SCALE / abs (dot (theRay.Direct, aHit.Normal)), EPS_SCALE / MIN_SLOPE);
960 if (anOpenGlDepth - aPolygonOffset < aHit.Time)
962 vec4 aColor = ComputeOpenGlColor (theRay);
964 aResult += aWeight.xyz * aColor.xyz;
968 vec3 aPoint = theRay.Direct * aHit.Time + theRay.Origin;
970 vec3 aAmbient = texelFetch (
971 uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb;
972 vec4 aDiffuse = texelFetch (
973 uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w));
974 vec4 aSpecular = texelFetch (
975 uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w));
976 vec4 aOpacity = texelFetch (
977 uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w));
978 vec3 aEmission = texelFetch (
979 uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb;
982 if (aDiffuse.w >= 0.f)
984 vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);
986 vec4 aTrsfRow1 = texelFetch (
987 uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));
988 vec4 aTrsfRow2 = texelFetch (
989 uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));
991 aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
992 dot (aTrsfRow2, aTexCoord));
994 vec3 aTexColor = textureLod (
995 uTextureSamplers[int(aDiffuse.w)], aTexCoord.st, 0.f).rgb;
997 aDiffuse.rgb *= aTexColor;
998 aAmbient.rgb *= aTexColor;
1002 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
1003 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
1004 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
1006 vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
1008 aNormal = normalize (MatrixRowMultiplyDir (
1009 aNormal, aInvTransf0, aInvTransf1, aInvTransf2));
1011 for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
1013 vec4 aLight = texelFetch (
1014 uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
1016 float aDistance = MAXFLOAT;
1018 if (aLight.w != 0.0f) // point light source
1020 aDistance = length (aLight.xyz -= aPoint);
1022 aLight.xyz *= 1.0f / aDistance;
1025 SRay aShadow = SRay (aPoint + aLight.xyz * uSceneEpsilon, aLight.xyz);
1027 aShadow.Origin += aHit.Normal * uSceneEpsilon *
1028 (dot (aHit.Normal, aLight.xyz) >= 0.0f ? 1.0f : -1.0f);
1030 float aVisibility = 1.0f;
1032 if (bool(uShadowsEnable))
1034 vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL);
1036 aInverse.x = aLight.x < 0.0f ? -aInverse.x : aInverse.x;
1037 aInverse.y = aLight.y < 0.0f ? -aInverse.y : aInverse.y;
1038 aInverse.z = aLight.z < 0.0f ? -aInverse.z : aInverse.z;
1040 aVisibility = SceneAnyHit (aShadow, aInverse, aDistance);
1043 if (aVisibility > 0.0f)
1045 vec3 aIntensity = vec3 (texelFetch (
1046 uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
1048 float aLdotN = dot (aShadow.Direct, aNormal);
1050 if (aOpacity.y > 0.0f) // force two-sided lighting
1051 aLdotN = abs (aLdotN); // for transparent surfaces
1055 float aRdotV = dot (reflect (aShadow.Direct, aNormal), theRay.Direct);
1057 aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity *
1058 (aDiffuse.rgb * aLdotN + aSpecular.xyz * pow (max (0.0f, aRdotV), aSpecular.w));
1063 aResult.xyz += aWeight.xyz * aOpacity.x * (uGlobalAmbient.xyz *
1064 aAmbient * max (abs (dot (aNormal, theRay.Direct)), 0.5f) + aEmission);
1066 if (aOpacity.x != 1.0f)
1068 aWeight *= aOpacity.y;
1070 if (aOpacity.z != 1.0f)
1072 theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w);
1074 theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
1076 theInverse.x = theRay.Direct.x < 0.0f ? -theInverse.x : theInverse.x;
1077 theInverse.y = theRay.Direct.y < 0.0f ? -theInverse.y : theInverse.y;
1078 theInverse.z = theRay.Direct.z < 0.0f ? -theInverse.z : theInverse.z;
1080 aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.0f ? uSceneEpsilon : -uSceneEpsilon);
1082 // Disable combining image with OpenGL output
1083 anOpenGlDepth = MAXFLOAT;
1087 anOpenGlDepth -= aHit.Time + uSceneEpsilon;
1092 aWeight *= bool(uReflectionsEnable) ?
1093 texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f);
1095 theRay.Direct = reflect (theRay.Direct, aNormal);
1097 if (dot (theRay.Direct, aHit.Normal) < 0.0f)
1099 theRay.Direct = reflect (theRay.Direct, aHit.Normal);
1102 theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
1104 theInverse.x = theRay.Direct.x < 0.0f ? -theInverse.x : theInverse.x;
1105 theInverse.y = theRay.Direct.y < 0.0f ? -theInverse.y : theInverse.y;
1106 theInverse.z = theRay.Direct.z < 0.0f ? -theInverse.z : theInverse.z;
1108 aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.0f ? uSceneEpsilon : -uSceneEpsilon);
1110 // Disable combining image with OpenGL output
1111 anOpenGlDepth = MAXFLOAT;
1114 if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
1116 return vec4 (aResult.x,
1122 theRay.Origin = theRay.Direct * uSceneEpsilon + aPoint;
1125 return vec4 (aResult.x,