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.f))
97 #define ZERO vec3 (0.f, 0.f, 0.f)
98 #define UNIT vec3 (1.f, 1.f, 1.f)
100 #define AXIS_X vec3 (1.f, 0.f, 0.f)
101 #define AXIS_Y vec3 (0.f, 1.f, 0.f)
102 #define AXIS_Z vec3 (0.f, 0.f, 1.f)
105 // =======================================================================
106 // function : MatrixRowMultiply
107 // purpose : Multiplies a vector by matrix
108 // =======================================================================
109 vec3 MatrixRowMultiply (in vec4 v,
115 return vec3 (dot (m0, v),
121 // =======================================================================
122 // function : MatrixColMultiply
123 // purpose : Multiplies a vector by matrix
124 // =======================================================================
125 vec3 MatrixColMultiply (in vec4 v,
131 return vec3 (m0[0] * v.x + m1[0] * v.y + m2[0] * v.z + m3[0] * v.w,
132 m0[1] * v.x + m1[1] * v.y + m2[1] * v.z + m3[1] * v.w,
133 m0[2] * v.x + m1[2] * v.y + m2[2] * v.z + m3[2] * v.w);
136 /////////////////////////////////////////////////////////////////////////////////////////
137 // Functions for compute ray-object intersection
139 // =======================================================================
140 // function : GenerateRay
142 // =======================================================================
143 SRay GenerateRay (in vec2 thePixel)
145 vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
146 vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
148 vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x);
149 vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x);
151 return SRay (mix (aP0, aP1, thePixel.y),
152 mix (aD0, aD1, thePixel.y));
155 // =======================================================================
156 // function : IntersectSphere
157 // purpose : Computes ray-sphere intersection
158 // =======================================================================
159 float IntersectSphere (in SRay theRay, in float theRadius)
161 float aDdotD = dot (theRay.Direct, theRay.Direct);
162 float aDdotO = dot (theRay.Direct, theRay.Origin);
163 float aOdotO = dot (theRay.Origin, theRay.Origin);
165 float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);
169 float aTime = (sqrt (aD) - aDdotO) * (1.f / aDdotD);
171 return aTime > 0.f ? aTime : MAXFLOAT;
177 // =======================================================================
178 // function : IntersectTriangle
179 // purpose : Computes ray-triangle intersection (branchless version)
180 // =======================================================================
181 float IntersectTriangle (in SRay theRay,
188 vec3 aEdge0 = thePnt1 - thePnt0;
189 vec3 aEdge1 = thePnt0 - thePnt2;
191 theNorm = cross (aEdge1, aEdge0);
193 vec3 aEdge2 = (1.f / dot (theNorm, theRay.Direct)) * (thePnt0 - theRay.Origin);
195 float aTime = dot (theNorm, aEdge2);
197 vec3 theVec = cross (theRay.Direct, aEdge2);
199 theUV.x = dot (theVec, aEdge1);
200 theUV.y = dot (theVec, aEdge0);
202 return bool (int(aTime >= 0.f) &
203 int(theUV.x >= 0.f) &
204 int(theUV.y >= 0.f) &
205 int(theUV.x + theUV.y <= 1.f)) ? aTime : MAXFLOAT;
208 //! Identifies the absence of intersection.
209 #define INALID_HIT ivec4 (-1)
211 //! Global stack shared between traversal functions.
212 int Stack[STACK_SIZE];
214 // =======================================================================
215 // function : ObjectNearestHit
216 // purpose : Finds intersection with nearest object triangle
217 // =======================================================================
218 ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
219 in SRay theRay, in vec3 theInverse, inout SIntersect theHit, in int theSentinel)
221 int aHead = theSentinel; // stack pointer
222 int aNode = 0; // node to visit
224 ivec4 aTriIndex = INALID_HIT;
232 ivec3 aData = texelFetch (uObjectNodeInfoTexture, aNode + theBVHOffset).xyz;
234 if (aData.x == 0) // if inner node
236 vec3 aNodeMinLft = texelFetch (uObjectMinPointTexture, aData.y + theBVHOffset).xyz;
237 vec3 aNodeMaxLft = texelFetch (uObjectMaxPointTexture, aData.y + theBVHOffset).xyz;
238 vec3 aNodeMinRgh = texelFetch (uObjectMinPointTexture, aData.z + theBVHOffset).xyz;
239 vec3 aNodeMaxRgh = texelFetch (uObjectMaxPointTexture, aData.z + theBVHOffset).xyz;
241 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
242 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
244 vec3 aTimeMax = max (aTime0, aTime1);
245 vec3 aTimeMin = min (aTime0, aTime1);
247 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
248 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
250 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
251 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
253 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeLft <= theHit.Time);
255 aTimeMax = max (aTime0, aTime1);
256 aTimeMin = min (aTime0, aTime1);
258 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
259 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
261 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeRgh <= theHit.Time);
263 if (bool(aHitLft & aHitRgh))
265 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
267 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
271 if (bool(aHitLft | aHitRgh))
273 aNode = bool(aHitLft) ? aData.y : aData.z;
277 if (aHead == theSentinel)
280 aNode = Stack[aHead--];
289 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
291 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
293 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x + theVrtOffset).xyz;
294 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y + theVrtOffset).xyz;
295 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z + theVrtOffset).xyz;
297 float aTime = IntersectTriangle (theRay,
304 if (aTime < theHit.Time)
306 aTriIndex = aTriangle;
308 theHit = SIntersect (aTime, aParams, aNormal);
312 if (aHead == theSentinel)
315 aNode = Stack[aHead--];
322 // =======================================================================
323 // function : ObjectAnyHit
324 // purpose : Finds intersection with any object triangle
325 // =======================================================================
326 float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
327 in SRay theRay, in vec3 theInverse, in float theDistance, in int theSentinel)
329 int aHead = theSentinel; // stack pointer
330 int aNode = 0; // node to visit
338 ivec4 aData = texelFetch (uObjectNodeInfoTexture, aNode + theBVHOffset);
340 if (aData.x == 0) // if inner node
342 vec3 aNodeMinLft = texelFetch (uObjectMinPointTexture, aData.y + theBVHOffset).xyz;
343 vec3 aNodeMaxLft = texelFetch (uObjectMaxPointTexture, aData.y + theBVHOffset).xyz;
344 vec3 aNodeMinRgh = texelFetch (uObjectMinPointTexture, aData.z + theBVHOffset).xyz;
345 vec3 aNodeMaxRgh = texelFetch (uObjectMaxPointTexture, aData.z + theBVHOffset).xyz;
347 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
348 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
350 vec3 aTimeMax = max (aTime0, aTime1);
351 vec3 aTimeMin = min (aTime0, aTime1);
353 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
354 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
356 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
357 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
359 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeLft <= theDistance);
361 aTimeMax = max (aTime0, aTime1);
362 aTimeMin = min (aTime0, aTime1);
364 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
365 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
367 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeRgh <= theDistance);
369 if (bool(aHitLft & aHitRgh))
371 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
373 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
377 if (bool(aHitLft | aHitRgh))
379 aNode = bool(aHitLft) ? aData.y : aData.z;
383 if (aHead == theSentinel)
386 aNode = Stack[aHead--];
395 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
397 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
399 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x + theVrtOffset).xyz;
400 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y + theVrtOffset).xyz;
401 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z + theVrtOffset).xyz;
403 float aTime = IntersectTriangle (theRay,
410 if (aTime < theDistance)
414 if (aHead == theSentinel)
417 aNode = Stack[aHead--];
424 // =======================================================================
425 // function : SceneNearestHit
426 // purpose : Finds intersection with nearest scene triangle
427 // =======================================================================
428 ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theObjectId)
430 int aHead = -1; // stack pointer
431 int aNode = 0; // node to visit
433 ivec4 aHitObject = INALID_HIT;
441 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
443 if (aData.x != 0) // if leaf node
445 vec3 aNodeMin = texelFetch (uSceneMinPointTexture, aNode).xyz;
446 vec3 aNodeMax = texelFetch (uSceneMaxPointTexture, aNode).xyz;
448 vec3 aTime0 = (aNodeMin - theRay.Origin) * theInverse;
449 vec3 aTime1 = (aNodeMax - theRay.Origin) * theInverse;
451 vec3 aTimes = min (aTime0, aTime1);
453 if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
455 // fetch object transformation
456 int anObjectId = aData.x - 1;
457 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
458 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
459 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
460 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
464 aNewRay.Origin = MatrixColMultiply (vec4 (theRay.Origin, 1.f),
465 aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
467 aNewRay.Direct = MatrixColMultiply (vec4 (theRay.Direct, 0.f),
468 aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
470 vec3 aNewInverse = 1.f / max (abs (aNewRay.Direct), SMALL);
472 aNewInverse.x = aNewRay.Direct.x < 0.f ? -aNewInverse.x : aNewInverse.x;
473 aNewInverse.y = aNewRay.Direct.y < 0.f ? -aNewInverse.y : aNewInverse.y;
474 aNewInverse.z = aNewRay.Direct.z < 0.f ? -aNewInverse.z : aNewInverse.z;
476 ivec4 aTriIndex = ObjectNearestHit (
477 aData.y, aData.z, aData.w, aNewRay, aNewInverse, theHit, aHead);
479 if (aTriIndex.x != -1)
481 aHitObject = ivec4 (aTriIndex.x + aData.z, // vertex 0
482 aTriIndex.y + aData.z, // vertex 1
483 aTriIndex.z + aData.z, // vertex 2
484 aTriIndex.w); // material
486 theObjectId = anObjectId;
493 aNode = Stack[aHead--];
495 else // if inner node
497 vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
498 vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
499 vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
500 vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
502 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
503 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
505 vec3 aTimeMax = max (aTime0, aTime1);
506 vec3 aTimeMin = min (aTime0, aTime1);
508 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
509 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
511 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeLft <= theHit.Time);
513 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
514 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
516 aTimeMax = max (aTime0, aTime1);
517 aTimeMin = min (aTime0, aTime1);
519 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
520 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
522 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeRgh <= theHit.Time);
524 if (bool(aHitLft & aHitRgh))
526 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
528 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
532 if (bool(aHitLft | aHitRgh))
534 aNode = bool(aHitLft) ? aData.y : aData.z;
541 aNode = Stack[aHead--];
550 // =======================================================================
551 // function : SceneAnyHit
552 // purpose : Finds intersection with any scene triangle
553 // =======================================================================
554 float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
556 int aHead = -1; // stack pointer
557 int aNode = 0; // node to visit
565 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
567 if (aData.x != 0) // if leaf node
569 // fetch object transformation
570 int anObjectId = aData.x - 1;
571 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
572 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
573 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
574 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
578 aNewRay.Origin = MatrixColMultiply (vec4 (theRay.Origin, 1.f),
579 aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
581 aNewRay.Direct = MatrixColMultiply (vec4 (theRay.Direct, 0.f),
582 aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
584 vec3 aNewInverse = 1.f / max (abs (aNewRay.Direct), SMALL);
586 aNewInverse.x = aNewRay.Direct.x < 0.f ? -aNewInverse.x : aNewInverse.x;
587 aNewInverse.y = aNewRay.Direct.y < 0.f ? -aNewInverse.y : aNewInverse.y;
588 aNewInverse.z = aNewRay.Direct.z < 0.f ? -aNewInverse.z : aNewInverse.z;
590 bool isShadow = 0.f == ObjectAnyHit (
591 aData.y, aData.z, aData.w, aNewRay, aNewInverse, theDistance, aHead);
593 if (aHead < 0 || isShadow)
594 return isShadow ? 0.f : 1.f;
596 aNode = Stack[aHead--];
598 else // if inner node
600 vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
601 vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
602 vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
603 vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
605 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
606 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
608 vec3 aTimeMax = max (aTime0, aTime1);
609 vec3 aTimeMin = min (aTime0, aTime1);
611 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
612 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
614 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeLft <= theDistance);
616 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
617 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
619 aTimeMax = max (aTime0, aTime1);
620 aTimeMin = min (aTime0, aTime1);
622 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
623 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
625 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeRgh <= theDistance);
627 if (bool(aHitLft & aHitRgh))
629 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
631 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
635 if (bool(aHitLft | aHitRgh))
637 aNode = bool(aHitLft) ? aData.y : aData.z;
644 aNode = Stack[aHead--];
653 #define PI 3.1415926f
655 // =======================================================================
656 // function : Latlong
657 // purpose : Converts world direction to environment texture coordinates
658 // =======================================================================
659 vec2 Latlong (in vec3 thePoint, in float theRadius)
661 float aPsi = acos (-thePoint.z / theRadius);
663 float aPhi = atan (thePoint.y, thePoint.x) + PI;
665 return vec2 (aPhi * 0.1591549f,
669 // =======================================================================
670 // function : SmoothNormal
671 // purpose : Interpolates normal across the triangle
672 // =======================================================================
673 vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
675 vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz;
676 vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz;
677 vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz;
679 return normalize (aNormal1 * theUV.x +
681 aNormal0 * (1.f - theUV.x - theUV.y));
684 #define THRESHOLD vec3 (0.1f, 0.1f, 0.1f)
686 #define MATERIAL_AMBN(index) (7 * index + 0)
687 #define MATERIAL_DIFF(index) (7 * index + 1)
688 #define MATERIAL_SPEC(index) (7 * index + 2)
689 #define MATERIAL_EMIS(index) (7 * index + 3)
690 #define MATERIAL_REFL(index) (7 * index + 4)
691 #define MATERIAL_REFR(index) (7 * index + 5)
692 #define MATERIAL_TRAN(index) (7 * index + 6)
694 #define LIGHT_POS(index) (2 * index + 1)
695 #define LIGHT_PWR(index) (2 * index + 0)
697 // =======================================================================
698 // function : Radiance
699 // purpose : Computes color of specified ray
700 // =======================================================================
701 vec4 Radiance (in SRay theRay, in vec3 theInverse)
703 vec3 aResult = vec3 (0.f);
704 vec4 aWeight = vec4 (1.f);
708 for (int aDepth = 0; aDepth < 5; ++aDepth)
710 SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
712 ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
714 if (aTriIndex.x == -1)
716 if (aWeight.w != 0.f)
718 return vec4 (aResult.x,
724 if (bool(uEnvironmentEnable))
726 float aTime = IntersectSphere (theRay, uSceneRadius);
728 aResult.xyz += aWeight.xyz * textureLod (uEnvironmentMapTexture,
729 Latlong (theRay.Direct * aTime + theRay.Origin, uSceneRadius), 0.f).xyz;
732 return vec4 (aResult.x,
738 vec3 aPoint = theRay.Direct * aHit.Time + theRay.Origin;
740 vec3 aAmbient = vec3 (texelFetch (
741 uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)));
742 vec3 aDiffuse = vec3 (texelFetch (
743 uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w)));
744 vec4 aSpecular = vec4 (texelFetch (
745 uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w)));
746 vec2 aOpacity = vec2 (texelFetch (
747 uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w)));
749 vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
751 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
752 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
753 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
754 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
756 aNormal = MatrixRowMultiply (vec4 (aNormal, 0.f), aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
757 aNormal = normalize (aNormal);
759 aHit.Normal = normalize (aHit.Normal);
761 for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
763 vec4 aLight = texelFetch (
764 uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
766 float aDistance = MAXFLOAT;
768 if (aLight.w != 0.f) // point light source
770 aDistance = length (aLight.xyz -= aPoint);
772 aLight.xyz *= 1.f / aDistance;
775 SRay aShadow = SRay (aPoint + aLight.xyz * uSceneEpsilon, aLight.xyz);
777 aShadow.Origin += aHit.Normal * uSceneEpsilon *
778 (dot (aHit.Normal, aLight.xyz) >= 0.f ? 1.f : -1.f);
780 float aVisibility = 1.f;
782 if (bool(uShadowsEnable))
784 vec3 aInverse = 1.f / max (abs (aLight.xyz), SMALL);
786 aInverse.x = aLight.x < 0.f ? -aInverse.x : aInverse.x;
787 aInverse.y = aLight.y < 0.f ? -aInverse.y : aInverse.y;
788 aInverse.z = aLight.z < 0.f ? -aInverse.z : aInverse.z;
790 aVisibility = SceneAnyHit (aShadow, aInverse, aDistance);
793 if (aVisibility > 0.f)
795 vec3 aIntensity = vec3 (texelFetch (
796 uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
798 float aLdotN = dot (aShadow.Direct, aNormal);
800 if (aOpacity.y > 0.f) // force two-sided lighting
801 aLdotN = abs (aLdotN); // for transparent surfaces
805 float aRdotV = dot (reflect (aShadow.Direct, aNormal), theRay.Direct);
807 aResult.xyz += aWeight.xyz * aOpacity.x * aIntensity *
808 (aDiffuse * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w));
813 aResult.xyz += aWeight.xyz * uGlobalAmbient.xyz *
814 aAmbient * aOpacity.x * max (abs (dot (aNormal, theRay.Direct)), 0.5f);
816 if (aOpacity.x != 1.f)
818 aWeight *= aOpacity.y;
822 aWeight *= bool(uReflectionsEnable) ?
823 texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.f);
825 theRay.Direct = reflect (theRay.Direct, aNormal);
827 if (dot (theRay.Direct, aHit.Normal) < 0.f)
829 theRay.Direct = reflect (theRay.Direct, aHit.Normal);
832 theInverse = 1.0 / max (abs (theRay.Direct), SMALL);
834 theInverse.x = theRay.Direct.x < 0.0 ? -theInverse.x : theInverse.x;
835 theInverse.y = theRay.Direct.y < 0.0 ? -theInverse.y : theInverse.y;
836 theInverse.z = theRay.Direct.z < 0.0 ? -theInverse.z : theInverse.z;
838 aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.f ? uSceneEpsilon : -uSceneEpsilon);
841 if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
843 return vec4 (aResult.x,
849 theRay.Origin = theRay.Direct * uSceneEpsilon + aPoint;
852 return vec4 (aResult.x,