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;
29 //! Texture buffer of data records of bottom-level BVH nodes.
30 uniform isamplerBuffer uObjectNodeInfoTexture;
31 //! Texture buffer of minimum points of bottom-level BVH nodes.
32 uniform samplerBuffer uObjectMinPointTexture;
33 //! Texture buffer of maximum points of bottom-level BVH nodes.
34 uniform samplerBuffer uObjectMaxPointTexture;
36 //! Texture buffer of vertex coords.
37 uniform samplerBuffer uGeometryVertexTexture;
38 //! Texture buffer of vertex normals.
39 uniform samplerBuffer uGeometryNormalTexture;
40 //! Texture buffer of triangle indices.
41 uniform isamplerBuffer uGeometryTriangTexture;
43 //! Texture buffer of material properties.
44 uniform samplerBuffer uRaytraceMaterialTexture;
45 //! Texture buffer of light source properties.
46 uniform samplerBuffer uRaytraceLightSrcTexture;
47 //! Environment map texture.
48 uniform sampler2D uEnvironmentMapTexture;
50 //! Total number of light sources.
51 uniform int uLightCount;
52 //! Intensity of global ambient light.
53 uniform vec4 uGlobalAmbient;
55 //! Enables/disables environment map.
56 uniform int uEnvironmentEnable;
57 //! Enables/disables computation of shadows.
58 uniform int uShadowsEnable;
59 //! Enables/disables computation of reflections.
60 uniform int uReflectionsEnable;
62 //! Radius of bounding sphere of the scene.
63 uniform float uSceneRadius;
64 //! Scene epsilon to prevent self-intersections.
65 uniform float uSceneEpsilon;
67 /////////////////////////////////////////////////////////////////////////////////////////
68 // Specific data types
70 //! Stores ray parameters.
78 //! Stores intersection parameters.
88 /////////////////////////////////////////////////////////////////////////////////////////
89 // Some useful constants
91 #define MAXFLOAT 1e15f
93 #define SMALL vec3 (exp2 (-80.f))
95 #define ZERO vec3 (0.f, 0.f, 0.f)
96 #define UNIT vec3 (1.f, 1.f, 1.f)
98 #define AXIS_X vec3 (1.f, 0.f, 0.f)
99 #define AXIS_Y vec3 (0.f, 1.f, 0.f)
100 #define AXIS_Z vec3 (0.f, 0.f, 1.f)
102 /////////////////////////////////////////////////////////////////////////////////////////
103 // Functions for compute ray-object intersection
105 // =======================================================================
106 // function : GenerateRay
108 // =======================================================================
109 SRay GenerateRay (in vec2 thePixel)
111 vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
112 vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
114 vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x);
115 vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x);
117 return SRay (mix (aP0, aP1, thePixel.y),
118 mix (aD0, aD1, thePixel.y));
121 // =======================================================================
122 // function : IntersectSphere
123 // purpose : Computes ray-sphere intersection
124 // =======================================================================
125 float IntersectSphere (in SRay theRay, in float theRadius)
127 float aDdotD = dot (theRay.Direct, theRay.Direct);
128 float aDdotO = dot (theRay.Direct, theRay.Origin);
129 float aOdotO = dot (theRay.Origin, theRay.Origin);
131 float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);
135 float aTime = (sqrt (aD) - aDdotO) * (1.f / aDdotD);
137 return aTime > 0.f ? aTime : MAXFLOAT;
143 // =======================================================================
144 // function : IntersectTriangle
145 // purpose : Computes ray-triangle intersection (branchless version)
146 // =======================================================================
147 float IntersectTriangle (in SRay theRay,
154 vec3 aEdge0 = thePnt1 - thePnt0;
155 vec3 aEdge1 = thePnt0 - thePnt2;
157 theNorm = cross (aEdge1, aEdge0);
159 vec3 aEdge2 = (1.f / dot (theNorm, theRay.Direct)) * (thePnt0 - theRay.Origin);
161 float aTime = dot (theNorm, aEdge2);
163 vec3 theVec = cross (theRay.Direct, aEdge2);
165 theUV.x = dot (theVec, aEdge1);
166 theUV.y = dot (theVec, aEdge0);
168 return bool (int(aTime >= 0.f) &
169 int(theUV.x >= 0.f) &
170 int(theUV.y >= 0.f) &
171 int(theUV.x + theUV.y <= 1.f)) ? aTime : MAXFLOAT;
174 //! Global stack shared between traversal functions.
175 int Stack[STACK_SIZE];
177 //! Identifies the absence of intersection.
178 #define INALID_HIT ivec4 (-1)
180 // =======================================================================
181 // function : ObjectNearestHit
182 // purpose : Finds intersection with nearest object triangle
183 // =======================================================================
184 ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
185 in SRay theRay, in vec3 theInverse, inout SIntersect theHit, in int theSentinel)
187 int aHead = theSentinel; // stack pointer
188 int aNode = 0; // node to visit
190 ivec4 aTriIndex = INALID_HIT;
198 ivec3 aData = texelFetch (uObjectNodeInfoTexture, aNode + theBVHOffset).xyz;
200 if (aData.x == 0) // if inner node
202 vec3 aNodeMinLft = texelFetch (uObjectMinPointTexture, aData.y + theBVHOffset).xyz;
203 vec3 aNodeMaxLft = texelFetch (uObjectMaxPointTexture, aData.y + theBVHOffset).xyz;
204 vec3 aNodeMinRgh = texelFetch (uObjectMinPointTexture, aData.z + theBVHOffset).xyz;
205 vec3 aNodeMaxRgh = texelFetch (uObjectMaxPointTexture, aData.z + theBVHOffset).xyz;
207 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
208 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
210 vec3 aTimeMax = max (aTime0, aTime1);
211 vec3 aTimeMin = min (aTime0, aTime1);
213 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
214 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
216 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
217 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
219 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeLft <= theHit.Time);
221 aTimeMax = max (aTime0, aTime1);
222 aTimeMin = min (aTime0, aTime1);
224 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
225 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
227 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeRgh <= theHit.Time);
229 if (bool(aHitLft & aHitRgh))
231 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
233 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
237 if (bool(aHitLft | aHitRgh))
239 aNode = bool(aHitLft) ? aData.y : aData.z;
243 if (aHead == theSentinel)
246 aNode = Stack[aHead--];
255 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
257 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
259 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x + theVrtOffset).xyz;
260 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y + theVrtOffset).xyz;
261 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z + theVrtOffset).xyz;
263 float aTime = IntersectTriangle (theRay,
270 if (aTime < theHit.Time)
272 aTriIndex = aTriangle;
274 theHit = SIntersect (aTime, aParams, aNormal);
278 if (aHead == theSentinel)
281 aNode = Stack[aHead--];
288 // =======================================================================
289 // function : ObjectAnyHit
290 // purpose : Finds intersection with any object triangle
291 // =======================================================================
292 float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
293 in SRay theRay, in vec3 theInverse, in float theDistance, in int theSentinel)
295 int aHead = theSentinel; // stack pointer
296 int aNode = 0; // node to visit
304 ivec4 aData = texelFetch (uObjectNodeInfoTexture, aNode + theBVHOffset);
306 if (aData.x == 0) // if inner node
308 vec3 aNodeMinLft = texelFetch (uObjectMinPointTexture, aData.y + theBVHOffset).xyz;
309 vec3 aNodeMaxLft = texelFetch (uObjectMaxPointTexture, aData.y + theBVHOffset).xyz;
310 vec3 aNodeMinRgh = texelFetch (uObjectMinPointTexture, aData.z + theBVHOffset).xyz;
311 vec3 aNodeMaxRgh = texelFetch (uObjectMaxPointTexture, aData.z + theBVHOffset).xyz;
313 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
314 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
316 vec3 aTimeMax = max (aTime0, aTime1);
317 vec3 aTimeMin = min (aTime0, aTime1);
319 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
320 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
322 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
323 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
325 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeLft <= theDistance);
327 aTimeMax = max (aTime0, aTime1);
328 aTimeMin = min (aTime0, aTime1);
330 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
331 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
333 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeRgh <= theDistance);
335 if (bool(aHitLft & aHitRgh))
337 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
339 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
343 if (bool(aHitLft | aHitRgh))
345 aNode = bool(aHitLft) ? aData.y : aData.z;
349 if (aHead == theSentinel)
352 aNode = Stack[aHead--];
361 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
363 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
365 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x + theVrtOffset).xyz;
366 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y + theVrtOffset).xyz;
367 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z + theVrtOffset).xyz;
369 float aTime = IntersectTriangle (theRay,
376 if (aTime < theDistance)
380 if (aHead == theSentinel)
383 aNode = Stack[aHead--];
390 // =======================================================================
391 // function : SceneNearestHit
392 // purpose : Finds intersection with nearest scene triangle
393 // =======================================================================
394 ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit)
396 int aHead = -1; // stack pointer
397 int aNode = 0; // node to visit
399 ivec4 aHitObject = INALID_HIT;
407 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
409 if (aData.x != 0) // if leaf node
411 vec3 aNodeMin = texelFetch (uSceneMinPointTexture, aNode).xyz;
412 vec3 aNodeMax = texelFetch (uSceneMaxPointTexture, aNode).xyz;
414 vec3 aTime0 = (aNodeMin - theRay.Origin) * theInverse;
415 vec3 aTime1 = (aNodeMax - theRay.Origin) * theInverse;
417 vec3 aTimes = min (aTime0, aTime1);
419 if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
421 ivec4 aTriIndex = ObjectNearestHit (
422 aData.y, aData.z, aData.w, theRay, theInverse, theHit, aHead);
424 if (aTriIndex.x != -1)
426 aHitObject = ivec4 (aTriIndex.x + aData.z, // vertex 0
427 aTriIndex.y + aData.z, // vertex 1
428 aTriIndex.z + aData.z, // vertex 2
429 aTriIndex.w); // material
436 aNode = Stack[aHead--];
438 else // if inner node
440 vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
441 vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
442 vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
443 vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
445 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
446 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
448 vec3 aTimeMax = max (aTime0, aTime1);
449 vec3 aTimeMin = min (aTime0, aTime1);
451 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
452 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
454 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeLft <= theHit.Time);
456 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
457 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
459 aTimeMax = max (aTime0, aTime1);
460 aTimeMin = min (aTime0, aTime1);
462 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
463 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
465 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeRgh <= theHit.Time);
467 if (bool(aHitLft & aHitRgh))
469 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
471 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
475 if (bool(aHitLft | aHitRgh))
477 aNode = bool(aHitLft) ? aData.y : aData.z;
484 aNode = Stack[aHead--];
493 // =======================================================================
494 // function : SceneAnyHit
495 // purpose : Finds intersection with any scene triangle
496 // =======================================================================
497 float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
499 int aHead = -1; // stack pointer
500 int aNode = 0; // node to visit
508 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
510 if (aData.x != 0) // if leaf node
512 bool isShadow = 0.f == ObjectAnyHit (
513 aData.y, aData.z, aData.w, theRay, theInverse, theDistance, aHead);
515 if (aHead < 0 || isShadow)
516 return isShadow ? 0.f : 1.f;
518 aNode = Stack[aHead--];
520 else // if inner node
522 vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
523 vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
524 vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
525 vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
527 vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
528 vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
530 vec3 aTimeMax = max (aTime0, aTime1);
531 vec3 aTimeMin = min (aTime0, aTime1);
533 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
534 aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
536 int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeLft <= theDistance);
538 aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
539 aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
541 aTimeMax = max (aTime0, aTime1);
542 aTimeMin = min (aTime0, aTime1);
544 aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
545 aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
547 int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.f) & int(aTimeRgh <= theDistance);
549 if (bool(aHitLft & aHitRgh))
551 aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
553 Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
557 if (bool(aHitLft | aHitRgh))
559 aNode = bool(aHitLft) ? aData.y : aData.z;
566 aNode = Stack[aHead--];
575 #define PI 3.1415926f
577 // =======================================================================
578 // function : Latlong
579 // purpose : Converts world direction to environment texture coordinates
580 // =======================================================================
581 vec2 Latlong (in vec3 thePoint, in float theRadius)
583 float aPsi = acos (-thePoint.z / theRadius);
585 float aPhi = atan (thePoint.y, thePoint.x) + PI;
587 return vec2 (aPhi * 0.1591549f,
591 // =======================================================================
592 // function : SmoothNormal
593 // purpose : Interpolates normal across the triangle
594 // =======================================================================
595 vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
597 vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz;
598 vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz;
599 vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz;
601 return normalize (aNormal1 * theUV.x +
603 aNormal0 * (1.f - theUV.x - theUV.y));
606 #define THRESHOLD vec3 (0.1f, 0.1f, 0.1f)
608 #define MATERIAL_AMBN(index) (7 * index + 0)
609 #define MATERIAL_DIFF(index) (7 * index + 1)
610 #define MATERIAL_SPEC(index) (7 * index + 2)
611 #define MATERIAL_EMIS(index) (7 * index + 3)
612 #define MATERIAL_REFL(index) (7 * index + 4)
613 #define MATERIAL_REFR(index) (7 * index + 5)
614 #define MATERIAL_TRAN(index) (7 * index + 6)
616 #define LIGHT_POS(index) (2 * index + 1)
617 #define LIGHT_PWR(index) (2 * index + 0)
619 // =======================================================================
620 // function : Radiance
621 // purpose : Computes color of specified ray
622 // =======================================================================
623 vec4 Radiance (in SRay theRay, in vec3 theInverse)
625 vec3 aResult = vec3 (0.f);
626 vec4 aWeight = vec4 (1.f);
628 for (int aDepth = 0; aDepth < 5; ++aDepth)
630 SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
632 ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit);
634 if (aTriIndex.x == -1)
636 if (aWeight.w != 0.f)
638 return vec4 (aResult.x,
644 if (bool(uEnvironmentEnable))
646 float aTime = IntersectSphere (theRay, uSceneRadius);
648 aResult.xyz += aWeight.xyz * textureLod (uEnvironmentMapTexture,
649 Latlong (theRay.Direct * aTime + theRay.Origin, uSceneRadius), 0.f).xyz;
652 return vec4 (aResult.x,
658 vec3 aPoint = theRay.Direct * aHit.Time + theRay.Origin;
660 vec3 aAmbient = vec3 (texelFetch (
661 uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)));
662 vec3 aDiffuse = vec3 (texelFetch (
663 uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w)));
664 vec4 aSpecular = vec4 (texelFetch (
665 uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w)));
666 vec2 aOpacity = vec2 (texelFetch (
667 uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w)));
669 vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
671 aHit.Normal = normalize (aHit.Normal);
673 for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
675 vec4 aLight = texelFetch (
676 uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
678 float aDistance = MAXFLOAT;
680 if (aLight.w != 0.f) // point light source
682 aDistance = length (aLight.xyz -= aPoint);
684 aLight.xyz *= 1.f / aDistance;
687 SRay aShadow = SRay (aPoint + aLight.xyz * uSceneEpsilon, aLight.xyz);
689 aShadow.Origin += aHit.Normal * uSceneEpsilon *
690 (dot (aHit.Normal, aLight.xyz) >= 0.f ? 1.f : -1.f);
692 float aVisibility = 1.f;
694 if (bool(uShadowsEnable))
696 vec3 aInverse = 1.f / max (abs (aLight.xyz), SMALL);
698 aInverse.x = aLight.x < 0.f ? -aInverse.x : aInverse.x;
699 aInverse.y = aLight.y < 0.f ? -aInverse.y : aInverse.y;
700 aInverse.z = aLight.z < 0.f ? -aInverse.z : aInverse.z;
702 aVisibility = SceneAnyHit (aShadow, aInverse, aDistance);
705 if (aVisibility > 0.f)
707 vec3 aIntensity = vec3 (texelFetch (
708 uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
710 float aLdotN = dot (aShadow.Direct, aNormal);
712 if (aOpacity.y > 0.f) // force two-sided lighting
713 aLdotN = abs (aLdotN); // for transparent surfaces
717 float aRdotV = dot (reflect (aShadow.Direct, aNormal), theRay.Direct);
719 aResult.xyz += aWeight.xyz * aOpacity.x * aIntensity *
720 (aDiffuse * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w));
725 aResult.xyz += aWeight.xyz * uGlobalAmbient.xyz *
726 aAmbient * aOpacity.x * max (abs (dot (aNormal, theRay.Direct)), 0.5f);
728 if (aOpacity.x != 1.f)
730 aWeight *= aOpacity.y;
734 aWeight *= bool(uReflectionsEnable) ?
735 texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.f);
737 theRay.Direct = reflect (theRay.Direct, aNormal);
739 if (dot (theRay.Direct, aHit.Normal) < 0.f)
741 theRay.Direct = reflect (theRay.Direct, aHit.Normal);
744 theInverse = 1.0 / max (abs (theRay.Direct), SMALL);
746 theInverse.x = theRay.Direct.x < 0.0 ? -theInverse.x : theInverse.x;
747 theInverse.y = theRay.Direct.y < 0.0 ? -theInverse.y : theInverse.y;
748 theInverse.z = theRay.Direct.z < 0.0 ? -theInverse.z : theInverse.z;
750 aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.f ? uSceneEpsilon : -uSceneEpsilon);
753 if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
755 return vec4 (aResult.x,
761 theRay.Origin = theRay.Direct * uSceneEpsilon + aPoint;
764 return vec4 (aResult.x,