1 //! Normalized pixel coordinates.
4 //! Origin of viewing ray in left-top corner.
5 uniform vec3 uOriginLT;
6 //! Origin of viewing ray in left-bottom corner.
7 uniform vec3 uOriginLB;
8 //! Origin of viewing ray in right-top corner.
9 uniform vec3 uOriginRT;
10 //! Origin of viewing ray in right-bottom corner.
11 uniform vec3 uOriginRB;
13 //! Direction of viewing ray in left-top corner.
14 uniform vec3 uDirectLT;
15 //! Direction of viewing ray in left-bottom corner.
16 uniform vec3 uDirectLB;
17 //! Direction of viewing ray in right-top corner.
18 uniform vec3 uDirectRT;
19 //! Direction of viewing ray in right-bottom corner.
20 uniform vec3 uDirectRB;
22 //! Texture buffer of data records of high-level BVH nodes.
23 uniform isamplerBuffer uSceneNodeInfoTexture;
24 //! Texture buffer of minimum points of high-level BVH nodes.
25 uniform samplerBuffer uSceneMinPointTexture;
26 //! Texture buffer of maximum points of high-level BVH nodes.
27 uniform samplerBuffer uSceneMaxPointTexture;
28 //! Texture buffer of transformations of high-level BVH nodes.
29 uniform samplerBuffer uSceneTransformTexture;
31 //! Texture buffer of data records of bottom-level BVH nodes.
32 uniform isamplerBuffer uObjectNodeInfoTexture;
33 //! Texture buffer of minimum points of bottom-level BVH nodes.
34 uniform samplerBuffer uObjectMinPointTexture;
35 //! Texture buffer of maximum points of bottom-level BVH nodes.
36 uniform samplerBuffer uObjectMaxPointTexture;
38 //! Texture buffer of vertex coords.
39 uniform samplerBuffer uGeometryVertexTexture;
40 //! Texture buffer of vertex normals.
41 uniform samplerBuffer uGeometryNormalTexture;
42 //! Texture buffer of triangle indices.
43 uniform isamplerBuffer uGeometryTriangTexture;
45 //! Texture buffer of material properties.
46 uniform samplerBuffer uRaytraceMaterialTexture;
47 //! Texture buffer of light source properties.
48 uniform samplerBuffer uRaytraceLightSrcTexture;
49 //! Environment map texture.
50 uniform sampler2D uEnvironmentMapTexture;
52 //! Total number of light sources.
53 uniform int uLightCount;
54 //! Intensity of global ambient light.
55 uniform vec4 uGlobalAmbient;
57 //! Enables/disables environment map.
58 uniform int uEnvironmentEnable;
59 //! Enables/disables computation of shadows.
60 uniform int uShadowsEnable;
61 //! Enables/disables computation of reflections.
62 uniform int uReflectionsEnable;
64 //! Radius of bounding sphere of the scene.
65 uniform float uSceneRadius;
66 //! Scene epsilon to prevent self-intersections.
67 uniform float uSceneEpsilon;
69 /////////////////////////////////////////////////////////////////////////////////////////
70 // Specific data types
72 //! Stores ray parameters.
80 //! Stores intersection parameters.
90 /////////////////////////////////////////////////////////////////////////////////////////
91 // Some useful constants
93 #define MAXFLOAT 1e15f
95 #define SMALL vec3 (exp2 (-80.0f))
97 #define ZERO vec3 (0.0f, 0.0f, 0.0f)
98 #define UNIT vec3 (1.0f, 1.0f, 1.0f)
100 #define AXIS_X vec3 (1.0f, 0.0f, 0.0f)
101 #define AXIS_Y vec3 (0.0f, 1.0f, 0.0f)
102 #define AXIS_Z vec3 (0.0f, 0.0f, 1.0f)
105 // =======================================================================
106 // function : MatrixRowMultiplyDir
107 // purpose : Multiplies a vector by matrix
108 // =======================================================================
109 vec3 MatrixRowMultiplyDir (in vec3 v,
114 return vec3 (dot (m0.xyz, v),
119 // =======================================================================
120 // function : MatrixColMultiplyPnt
121 // purpose : Multiplies a vector by matrix
122 // =======================================================================
123 vec3 MatrixColMultiplyPnt (in vec3 v,
129 return vec3 (m0[0] * v.x + m1[0] * v.y + m2[0] * v.z + m3[0],
130 m0[1] * v.x + m1[1] * v.y + m2[1] * v.z + m3[1],
131 m0[2] * v.x + m1[2] * v.y + m2[2] * v.z + m3[2]);
134 // =======================================================================
135 // function : MatrixColMultiplyDir
136 // purpose : Multiplies a vector by matrix
137 // =======================================================================
138 vec3 MatrixColMultiplyDir (in vec3 v,
144 return vec3 (m0[0] * v.x + m1[0] * v.y + m2[0] * v.z,
145 m0[1] * v.x + m1[1] * v.y + m2[1] * v.z,
146 m0[2] * v.x + m1[2] * v.y + m2[2] * v.z);
149 /////////////////////////////////////////////////////////////////////////////////////////
150 // Functions for compute ray-object intersection
152 // =======================================================================
153 // function : GenerateRay
155 // =======================================================================
156 SRay GenerateRay (in vec2 thePixel)
158 vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
159 vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
161 vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x);
162 vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x);
164 return SRay (mix (aP0, aP1, thePixel.y),
165 mix (aD0, aD1, thePixel.y));
168 // =======================================================================
169 // function : IntersectSphere
170 // purpose : Computes ray-sphere intersection
171 // =======================================================================
172 float IntersectSphere (in SRay theRay, in float theRadius)
174 float aDdotD = dot (theRay.Direct, theRay.Direct);
175 float aDdotO = dot (theRay.Direct, theRay.Origin);
176 float aOdotO = dot (theRay.Origin, theRay.Origin);
178 float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);
182 float aTime = (sqrt (aD) - aDdotO) * (1.0f / aDdotD);
184 return aTime > 0.0f ? aTime : MAXFLOAT;
190 // =======================================================================
191 // function : IntersectTriangle
192 // purpose : Computes ray-triangle intersection (branchless version)
193 // =======================================================================
194 float IntersectTriangle (in SRay theRay,
201 vec3 aEdge0 = thePnt1 - thePnt0;
202 vec3 aEdge1 = thePnt0 - thePnt2;
204 theNorm = cross (aEdge1, aEdge0);
206 vec3 aEdge2 = (1.0f / dot (theNorm, theRay.Direct)) * (thePnt0 - theRay.Origin);
208 float aTime = dot (theNorm, aEdge2);
210 vec3 theVec = cross (theRay.Direct, aEdge2);
212 theUV.x = dot (theVec, aEdge1);
213 theUV.y = dot (theVec, aEdge0);
215 return bool (int(aTime >= 0.0f) &
216 int(theUV.x >= 0.0f) &
217 int(theUV.y >= 0.0f) &
218 int(theUV.x + theUV.y <= 1.0f)) ? aTime : MAXFLOAT;
221 //! Identifies the absence of intersection.
222 #define INALID_HIT ivec4 (-1)
224 //! Global stack shared between traversal functions.
225 int Stack[STACK_SIZE];
227 // =======================================================================
228 // function : ObjectNearestHit
229 // purpose : Finds intersection with nearest object triangle
230 // =======================================================================
231 ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
232 in SRay theRay, in vec3 theInverse, inout SIntersect theHit, in int theSentinel)
234 int aHead = theSentinel; // stack pointer
235 int aNode = theBVHOffset; // node to visit
237 ivec4 aTriIndex = INALID_HIT;
241 ivec3 aData = texelFetch (uObjectNodeInfoTexture, aNode).xyz;
243 if (aData.x == 0) // if inner node
249 aData.y += theBVHOffset;
250 aData.z += theBVHOffset;
252 vec3 aNodeMinLft = texelFetch (uObjectMinPointTexture, aData.y).xyz;
253 vec3 aNodeMaxLft = texelFetch (uObjectMaxPointTexture, aData.y).xyz;
254 vec3 aNodeMinRgh = texelFetch (uObjectMinPointTexture, aData.z).xyz;
255 vec3 aNodeMaxRgh = texelFetch (uObjectMaxPointTexture, aData.z).xyz;
257 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
258 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
260 vec3 aTimeMax = max (aTime0, aTime1);
261 vec3 aTimeMin = min (aTime0, aTime1);
263 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
264 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
266 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
267 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
269 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theHit.Time);
271 aTimeMax = max (aTime0, aTime1);
272 aTimeMin = min (aTime0, aTime1);
274 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
275 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
277 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
279 if (bool(aHitLft & aHitRgh))
281 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
283 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
287 if (bool(aHitLft | aHitRgh))
289 aNode = bool(aHitLft) ? aData.y : aData.z;
293 if (aHead == theSentinel)
296 aNode = Stack[aHead--];
305 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
307 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
309 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += theVrtOffset).xyz;
310 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += theVrtOffset).xyz;
311 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += theVrtOffset).xyz;
313 float aTime = IntersectTriangle (theRay,
320 if (aTime < theHit.Time)
322 aTriIndex = aTriangle;
324 theHit = SIntersect (aTime, aParams, aNormal);
328 if (aHead == theSentinel)
331 aNode = Stack[aHead--];
338 #define MATERIAL_AMBN(index) (7 * index + 0)
339 #define MATERIAL_DIFF(index) (7 * index + 1)
340 #define MATERIAL_SPEC(index) (7 * index + 2)
341 #define MATERIAL_EMIS(index) (7 * index + 3)
342 #define MATERIAL_REFL(index) (7 * index + 4)
343 #define MATERIAL_REFR(index) (7 * index + 5)
344 #define MATERIAL_TRAN(index) (7 * index + 6)
346 // =======================================================================
347 // function : ObjectAnyHit
348 // purpose : Finds intersection with any object triangle
349 // =======================================================================
350 float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
351 in SRay theRay, in vec3 theInverse, in float theDistance, in int theSentinel)
353 int aHead = theSentinel; // stack pointer
354 int aNode = theBVHOffset; // node to visit
356 #ifdef TRANSPARENT_SHADOWS
357 float aFactor = 1.0f;
362 ivec4 aData = texelFetch (uObjectNodeInfoTexture, aNode);
364 if (aData.x == 0) // if inner node
370 aData.y += theBVHOffset;
371 aData.z += theBVHOffset;
373 vec3 aNodeMinLft = texelFetch (uObjectMinPointTexture, aData.y).xyz;
374 vec3 aNodeMaxLft = texelFetch (uObjectMaxPointTexture, aData.y).xyz;
375 vec3 aNodeMinRgh = texelFetch (uObjectMinPointTexture, aData.z).xyz;
376 vec3 aNodeMaxRgh = texelFetch (uObjectMaxPointTexture, aData.z).xyz;
378 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
379 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
381 vec3 aTimeMax = max (aTime0, aTime1);
382 vec3 aTimeMin = min (aTime0, aTime1);
384 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
385 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
387 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
388 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
390 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
392 aTimeMax = max (aTime0, aTime1);
393 aTimeMin = min (aTime0, aTime1);
395 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
396 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
398 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
400 if (bool(aHitLft & aHitRgh))
402 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
404 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
408 if (bool(aHitLft | aHitRgh))
410 aNode = bool(aHitLft) ? aData.y : aData.z;
414 #ifdef TRANSPARENT_SHADOWS
415 if (aHead == theSentinel)
418 if (aHead == theSentinel)
422 aNode = Stack[aHead--];
431 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
433 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
435 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x + theVrtOffset).xyz;
436 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y + theVrtOffset).xyz;
437 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z + theVrtOffset).xyz;
439 float aTime = IntersectTriangle (theRay,
446 #ifdef TRANSPARENT_SHADOWS
447 if (aTime < theDistance)
449 aFactor *= 1.0f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
452 if (aTime < theDistance)
457 #ifdef TRANSPARENT_SHADOWS
458 if (aHead == theSentinel || aFactor < 0.1f)
461 if (aHead == theSentinel)
465 aNode = Stack[aHead--];
469 #ifdef TRANSPARENT_SHADOWS
476 // =======================================================================
477 // function : SceneNearestHit
478 // purpose : Finds intersection with nearest scene triangle
479 // =======================================================================
480 ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theObjectId)
482 int aHead = -1; // stack pointer
483 int aNode = 0; // node to visit
485 ivec4 aHitObject = INALID_HIT;
489 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
491 if (aData.x != 0) // if leaf node
493 vec3 aNodeMin = texelFetch (uSceneMinPointTexture, aNode).xyz;
494 vec3 aNodeMax = texelFetch (uSceneMaxPointTexture, aNode).xyz;
496 vec3 aTime0 = (aNodeMin - theRay.Origin) * theInverse;
497 vec3 aTime1 = (aNodeMax - theRay.Origin) * theInverse;
499 vec3 aTimes = min (aTime0, aTime1);
501 if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
503 // fetch object transformation
504 int anObjectId = aData.x - 1;
506 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
507 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
508 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
509 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
511 SRay aTrsfRay = SRay (
512 MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
513 MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
515 vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
517 aTrsfInverse.x = aTrsfRay.Direct.x < 0.f ? -aTrsfInverse.x : aTrsfInverse.x;
518 aTrsfInverse.y = aTrsfRay.Direct.y < 0.f ? -aTrsfInverse.y : aTrsfInverse.y;
519 aTrsfInverse.z = aTrsfRay.Direct.z < 0.f ? -aTrsfInverse.z : aTrsfInverse.z;
521 ivec4 aTriIndex = ObjectNearestHit (
522 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theHit, aHead);
524 if (aTriIndex.x != -1)
526 aHitObject = ivec4 (aTriIndex.x, // vertex 0
527 aTriIndex.y, // vertex 1
528 aTriIndex.z, // vertex 2
529 aTriIndex.w); // material
531 theObjectId = anObjectId;
538 aNode = Stack[aHead--];
540 else // if inner node
546 vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
547 vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
548 vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
549 vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
551 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
552 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
554 vec3 aTimeMax = max (aTime0, aTime1);
555 vec3 aTimeMin = min (aTime0, aTime1);
557 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
558 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
560 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theHit.Time);
562 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
563 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
565 aTimeMax = max (aTime0, aTime1);
566 aTimeMin = min (aTime0, aTime1);
568 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
569 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
571 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
573 if (bool(aHitLft & aHitRgh))
575 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
577 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
581 if (bool(aHitLft | aHitRgh))
583 aNode = bool(aHitLft) ? aData.y : aData.z;
590 aNode = Stack[aHead--];
599 // =======================================================================
600 // function : SceneAnyHit
601 // purpose : Finds intersection with any scene triangle
602 // =======================================================================
603 float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
605 int aHead = -1; // stack pointer
606 int aNode = 0; // node to visit
608 #ifdef TRANSPARENT_SHADOWS
609 float aFactor = 1.0f;
614 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
616 if (aData.x != 0) // if leaf node
618 // fetch object transformation
619 int anObjectId = aData.x - 1;
621 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
622 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
623 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
624 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
626 SRay aTrsfRay = SRay (
627 MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
628 MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
630 vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
632 aTrsfInverse.x = aTrsfRay.Direct.x < 0.0f ? -aTrsfInverse.x : aTrsfInverse.x;
633 aTrsfInverse.y = aTrsfRay.Direct.y < 0.0f ? -aTrsfInverse.y : aTrsfInverse.y;
634 aTrsfInverse.z = aTrsfRay.Direct.z < 0.0f ? -aTrsfInverse.z : aTrsfInverse.z;
636 #ifdef TRANSPARENT_SHADOWS
637 aFactor *= ObjectAnyHit (
638 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
640 if (aHead < 0 || aFactor < 0.1f)
643 bool isShadow = 0.0f == ObjectAnyHit (
644 aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
646 if (aHead < 0 || isShadow)
647 return isShadow ? 0.0f : 1.0f;
650 aNode = Stack[aHead--];
652 else // if inner node
658 vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
659 vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
660 vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
661 vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
663 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
664 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
666 vec3 aTimeMax = max (aTime0, aTime1);
667 vec3 aTimeMin = min (aTime0, aTime1);
669 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
670 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
672 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
674 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
675 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
677 aTimeMax = max (aTime0, aTime1);
678 aTimeMin = min (aTime0, aTime1);
680 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
681 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
683 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
685 if (bool(aHitLft & aHitRgh))
687 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
689 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
693 if (bool(aHitLft | aHitRgh))
695 aNode = bool(aHitLft) ? aData.y : aData.z;
699 #ifdef TRANSPARENT_SHADOWS
707 aNode = Stack[aHead--];
713 #ifdef TRANSPARENT_SHADOWS
720 #define PI 3.1415926f
722 // =======================================================================
723 // function : Latlong
724 // purpose : Converts world direction to environment texture coordinates
725 // =======================================================================
726 vec2 Latlong (in vec3 thePoint, in float theRadius)
728 float aPsi = acos (-thePoint.z / theRadius);
730 float aPhi = atan (thePoint.y, thePoint.x) + PI;
732 return vec2 (aPhi * 0.1591549f,
736 // =======================================================================
737 // function : SmoothNormal
738 // purpose : Interpolates normal across the triangle
739 // =======================================================================
740 vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
742 vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz;
743 vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz;
744 vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz;
746 return normalize (aNormal1 * theUV.x +
748 aNormal0 * (1.0f - theUV.x - theUV.y));
751 // =======================================================================
752 // function : Refract
753 // purpose : Computes refraction ray (also handles TIR)
754 // =======================================================================
755 vec3 Refract (in vec3 theInput,
757 in float theRefractIndex,
758 in float theInvRefractIndex)
760 float aNdotI = dot (theInput, theNormal);
762 float anIndex = aNdotI < 0.0f
766 float aSquare = anIndex * anIndex * (1.0f - aNdotI * aNdotI);
770 return reflect (theInput, theNormal);
773 float aNdotT = sqrt (1.0f - aSquare);
775 return normalize (anIndex * theInput -
776 (anIndex * aNdotI + (aNdotI < 0.0f ? aNdotT : -aNdotT)) * theNormal);
779 #define THRESHOLD vec3 (0.1f)
781 #define LIGHT_POS(index) (2 * index + 1)
782 #define LIGHT_PWR(index) (2 * index + 0)
784 // =======================================================================
785 // function : Radiance
786 // purpose : Computes color of specified ray
787 // =======================================================================
788 vec4 Radiance (in SRay theRay, in vec3 theInverse)
790 vec3 aResult = vec3 (0.0f);
791 vec4 aWeight = vec4 (1.0f);
795 for (int aDepth = 0; aDepth < TRACE_DEPTH; ++aDepth)
797 SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
799 ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
801 if (aTriIndex.x == -1)
803 if (aWeight.w != 0.0f)
805 return vec4 (aResult.x,
811 if (bool(uEnvironmentEnable))
813 float aTime = IntersectSphere (theRay, uSceneRadius);
815 aResult.xyz += aWeight.xyz * textureLod (uEnvironmentMapTexture,
816 Latlong (theRay.Direct * aTime + theRay.Origin, uSceneRadius), 0.0f).xyz;
819 return vec4 (aResult.x,
825 vec3 aPoint = theRay.Direct * aHit.Time + theRay.Origin;
827 vec3 aAmbient = texelFetch (
828 uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb;
829 vec3 aDiffuse = texelFetch (
830 uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w)).rgb;
831 vec4 aSpecular = texelFetch (
832 uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w));
833 vec4 aOpacity = texelFetch (
834 uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w));
836 vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
838 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
839 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
840 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
842 aNormal = normalize (MatrixRowMultiplyDir (
843 aNormal, aInvTransf0, aInvTransf1, aInvTransf2));
845 aHit.Normal = normalize (aHit.Normal);
847 for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
849 vec4 aLight = texelFetch (
850 uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
852 float aDistance = MAXFLOAT;
854 if (aLight.w != 0.0f) // point light source
856 aDistance = length (aLight.xyz -= aPoint);
858 aLight.xyz *= 1.0f / aDistance;
861 SRay aShadow = SRay (aPoint + aLight.xyz * uSceneEpsilon, aLight.xyz);
863 aShadow.Origin += aHit.Normal * uSceneEpsilon *
864 (dot (aHit.Normal, aLight.xyz) >= 0.0f ? 1.0f : -1.0f);
866 float aVisibility = 1.0f;
868 if (bool(uShadowsEnable))
870 vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL);
872 aInverse.x = aLight.x < 0.0f ? -aInverse.x : aInverse.x;
873 aInverse.y = aLight.y < 0.0f ? -aInverse.y : aInverse.y;
874 aInverse.z = aLight.z < 0.0f ? -aInverse.z : aInverse.z;
876 aVisibility = SceneAnyHit (aShadow, aInverse, aDistance);
879 if (aVisibility > 0.0f)
881 vec3 aIntensity = vec3 (texelFetch (
882 uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
884 float aLdotN = dot (aShadow.Direct, aNormal);
886 if (aOpacity.y > 0.0f) // force two-sided lighting
887 aLdotN = abs (aLdotN); // for transparent surfaces
891 float aRdotV = dot (reflect (aShadow.Direct, aNormal), theRay.Direct);
893 aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity *
894 (aDiffuse * aLdotN + aSpecular.xyz * pow (max (0.0f, aRdotV), aSpecular.w));
899 aResult.xyz += aWeight.xyz * uGlobalAmbient.xyz *
900 aAmbient * aOpacity.x * max (abs (dot (aNormal, theRay.Direct)), 0.5f);
902 if (aOpacity.x != 1.0f)
904 aWeight *= aOpacity.y;
906 if (aOpacity.z != 1.0f)
908 theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w);
910 theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
912 theInverse.x = theRay.Direct.x < 0.0f ? -theInverse.x : theInverse.x;
913 theInverse.y = theRay.Direct.y < 0.0f ? -theInverse.y : theInverse.y;
914 theInverse.z = theRay.Direct.z < 0.0f ? -theInverse.z : theInverse.z;
916 aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.0f ? uSceneEpsilon : -uSceneEpsilon);
921 aWeight *= bool(uReflectionsEnable) ?
922 texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f);
924 theRay.Direct = reflect (theRay.Direct, aNormal);
926 if (dot (theRay.Direct, aHit.Normal) < 0.0f)
928 theRay.Direct = reflect (theRay.Direct, aHit.Normal);
931 theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
933 theInverse.x = theRay.Direct.x < 0.0f ? -theInverse.x : theInverse.x;
934 theInverse.y = theRay.Direct.y < 0.0f ? -theInverse.y : theInverse.y;
935 theInverse.z = theRay.Direct.z < 0.0f ? -theInverse.z : theInverse.z;
937 aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.0f ? uSceneEpsilon : -uSceneEpsilon);
940 if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
942 return vec4 (aResult.x,
948 theRay.Origin = theRay.Direct * uSceneEpsilon + aPoint;
951 return vec4 (aResult.x,