0027607: Visualization - Implement adaptive screen space sampling in path tracing
[occt.git] / src / Shaders / RaytraceBase.fs
CommitLineData
3a9b5dc8 1#ifdef ADAPTIVE_SAMPLING
2 #extension GL_ARB_shader_image_load_store : require
3 #extension GL_NV_shader_atomic_float : require
4#endif
5
25ef750e 6#ifdef USE_TEXTURES
7 #extension GL_ARB_bindless_texture : require
8#endif
9
fc73a202 10//! Normalized pixel coordinates.
11in vec2 vPixel;
12
50d0e1ce 13//! Sub-pixel offset in X direction for FSAA.
14uniform float uOffsetX = 0.f;
15//! Sub-pixel offset in Y direction for FSAA.
16uniform float uOffsetY = 0.f;
17
fc73a202 18//! Origin of viewing ray in left-top corner.
19uniform vec3 uOriginLT;
20//! Origin of viewing ray in left-bottom corner.
21uniform vec3 uOriginLB;
22//! Origin of viewing ray in right-top corner.
23uniform vec3 uOriginRT;
24//! Origin of viewing ray in right-bottom corner.
25uniform vec3 uOriginRB;
26
312a4043 27//! Width of the rendering window.
28uniform int uWinSizeX;
29//! Height of the rendering window.
30uniform int uWinSizeY;
31
fc73a202 32//! Direction of viewing ray in left-top corner.
33uniform vec3 uDirectLT;
34//! Direction of viewing ray in left-bottom corner.
35uniform vec3 uDirectLB;
36//! Direction of viewing ray in right-top corner.
37uniform vec3 uDirectRT;
38//! Direction of viewing ray in right-bottom corner.
39uniform vec3 uDirectRB;
40
a89742cf 41//! Inverse model-view-projection matrix.
25ef750e 42uniform mat4 uUnviewMat;
43
1d865689 44//! Model-view-projection matrix.
45uniform mat4 uViewMat;
46
e2da917a 47//! Texture buffer of data records of bottom-level BVH nodes.
fc73a202 48uniform isamplerBuffer uSceneNodeInfoTexture;
e2da917a 49//! Texture buffer of minimum points of bottom-level BVH nodes.
fc73a202 50uniform samplerBuffer uSceneMinPointTexture;
e2da917a 51//! Texture buffer of maximum points of bottom-level BVH nodes.
fc73a202 52uniform samplerBuffer uSceneMaxPointTexture;
84c71f29 53//! Texture buffer of transformations of high-level BVH nodes.
54uniform samplerBuffer uSceneTransformTexture;
fc73a202 55
fc73a202 56//! Texture buffer of vertex coords.
57uniform samplerBuffer uGeometryVertexTexture;
58//! Texture buffer of vertex normals.
59uniform samplerBuffer uGeometryNormalTexture;
25ef750e 60#ifdef USE_TEXTURES
61 //! Texture buffer of per-vertex UV-coordinates.
62 uniform samplerBuffer uGeometryTexCrdTexture;
63#endif
fc73a202 64//! Texture buffer of triangle indices.
65uniform isamplerBuffer uGeometryTriangTexture;
66
67//! Texture buffer of material properties.
68uniform samplerBuffer uRaytraceMaterialTexture;
69//! Texture buffer of light source properties.
70uniform samplerBuffer uRaytraceLightSrcTexture;
71//! Environment map texture.
72uniform sampler2D uEnvironmentMapTexture;
73
74//! Total number of light sources.
75uniform int uLightCount;
76//! Intensity of global ambient light.
77uniform vec4 uGlobalAmbient;
78
189f85a3 79//! Enables/disables hard shadows.
80uniform int uShadowsEnabled;
81//! Enables/disables specular reflections.
82uniform int uReflectEnabled;
83//! Enables/disables spherical environment map.
84uniform int uSphereMapEnabled;
85//! Enables/disables environment map background.
86uniform int uSphereMapForBack;
fc73a202 87
88//! Radius of bounding sphere of the scene.
89uniform float uSceneRadius;
90//! Scene epsilon to prevent self-intersections.
91uniform float uSceneEpsilon;
92
25ef750e 93#ifdef USE_TEXTURES
94 //! Unique 64-bit handles of OpenGL textures.
47e9c178 95 uniform uvec2 uTextureSamplers[MAX_TEX_NUMBER];
25ef750e 96#endif
97
3a9b5dc8 98#ifdef ADAPTIVE_SAMPLING
99 //! OpenGL image used for accumulating rendering result.
100 volatile restrict layout(size1x32) uniform image2D uRenderImage;
101
102 //! OpenGL image storing offsets of sampled pixels blocks.
103 coherent restrict layout(size2x32) uniform iimage2D uOffsetImage;
104#endif
105
189f85a3 106//! Top color of gradient background.
107uniform vec4 uBackColorTop = vec4 (0.0);
108//! Bottom color of gradient background.
109uniform vec4 uBackColorBot = vec4 (0.0);
110
fc73a202 111/////////////////////////////////////////////////////////////////////////////////////////
112// Specific data types
189f85a3 113
fc73a202 114//! Stores ray parameters.
115struct SRay
116{
117 vec3 Origin;
189f85a3 118
fc73a202 119 vec3 Direct;
120};
121
122//! Stores intersection parameters.
123struct SIntersect
124{
125 float Time;
189f85a3 126
fc73a202 127 vec2 UV;
189f85a3 128
fc73a202 129 vec3 Normal;
130};
131
132/////////////////////////////////////////////////////////////////////////////////////////
133// Some useful constants
134
135#define MAXFLOAT 1e15f
136
dc9ef964 137#define SMALL vec3 (exp2 (-80.0f))
fc73a202 138
dc9ef964 139#define ZERO vec3 (0.0f, 0.0f, 0.0f)
140#define UNIT vec3 (1.0f, 1.0f, 1.0f)
fc73a202 141
dc9ef964 142#define AXIS_X vec3 (1.0f, 0.0f, 0.0f)
143#define AXIS_Y vec3 (0.0f, 1.0f, 0.0f)
144#define AXIS_Z vec3 (0.0f, 0.0f, 1.0f)
fc73a202 145
189f85a3 146#define M_PI 3.14159265f
147
148#define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)
149
150// =======================================================================
151// function : MatrixRowMultiplyDir
152// purpose : Multiplies a vector by matrix
153// =======================================================================
154vec3 MatrixRowMultiplyDir (in vec3 v,
155 in vec4 m0,
156 in vec4 m1,
157 in vec4 m2)
158{
159 return vec3 (dot (m0.xyz, v),
160 dot (m1.xyz, v),
161 dot (m2.xyz, v));
162}
163
312a4043 164//! 32-bit state of random number generator.
165uint RandState;
166
167// =======================================================================
168// function : SeedRand
169// purpose : Applies hash function by Thomas Wang to randomize seeds
170// (see http://www.burtleburtle.net/bob/hash/integer.html)
171// =======================================================================
8c820969 172void SeedRand (in int theSeed, in int theSizeX, in int theRadius)
312a4043 173{
8c820969 174 RandState = uint (int (gl_FragCoord.y) / theRadius * theSizeX + int (gl_FragCoord.x) / theRadius + theSeed);
312a4043 175
176 RandState = (RandState + 0x479ab41du) + (RandState << 8);
177 RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >> 5);
178 RandState = (RandState + 0x9942f0a6u) - (RandState << 14);
179 RandState = (RandState ^ 0x5aedd67du) ^ (RandState >> 3);
180 RandState = (RandState + 0x17bea992u) + (RandState << 7);
181}
182
183// =======================================================================
184// function : RandInt
185// purpose : Generates integer using Xorshift algorithm by G. Marsaglia
186// =======================================================================
187uint RandInt()
188{
189 RandState ^= (RandState << 13);
190 RandState ^= (RandState >> 17);
191 RandState ^= (RandState << 5);
192
193 return RandState;
194}
195
196// =======================================================================
197// function : RandFloat
198// purpose : Generates a random float in [0, 1) range
199// =======================================================================
200float RandFloat()
201{
202 return float (RandInt()) * (1.f / 4294967296.f);
203}
204
bc8c79bb 205// =======================================================================
206// function : MatrixColMultiplyPnt
207// purpose : Multiplies a vector by matrix
208// =======================================================================
209vec3 MatrixColMultiplyPnt (in vec3 v,
210 in vec4 m0,
211 in vec4 m1,
212 in vec4 m2,
213 in vec4 m3)
214{
47e9c178 215 return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z + m3.x,
216 m0.y * v.x + m1.y * v.y + m2.y * v.z + m3.y,
217 m0.z * v.x + m1.z * v.y + m2.z * v.z + m3.z);
bc8c79bb 218}
84c71f29 219
220// =======================================================================
bc8c79bb 221// function : MatrixColMultiplyDir
84c71f29 222// purpose : Multiplies a vector by matrix
223// =======================================================================
bc8c79bb 224vec3 MatrixColMultiplyDir (in vec3 v,
225 in vec4 m0,
226 in vec4 m1,
47e9c178 227 in vec4 m2)
84c71f29 228{
47e9c178 229 return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z,
230 m0.y * v.x + m1.y * v.y + m2.y * v.z,
231 m0.z * v.x + m1.z * v.y + m2.z * v.z);
84c71f29 232}
233
189f85a3 234//=======================================================================
235// function : InverseDirection
236// purpose : Returns safely inverted direction of the given one
237//=======================================================================
238vec3 InverseDirection (in vec3 theInput)
239{
240 vec3 anInverse = 1.f / max (abs (theInput), SMALL);
241
242 return mix (-anInverse, anInverse, step (ZERO, theInput));
243}
244
245//=======================================================================
246// function : BackgroundColor
247// purpose : Returns color of gradient background
248//=======================================================================
249vec4 BackgroundColor()
250{
3a9b5dc8 251#ifdef ADAPTIVE_SAMPLING
252
253 ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);
254
255 ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,
256 aFragCoord.y / BLOCK_SIZE)).xy;
257
258 aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, BLOCK_SIZE);
259
260 return mix (uBackColorBot, uBackColorTop, float (aTileXY.y) / uWinSizeY);
261
262#else
263
189f85a3 264 return mix (uBackColorBot, uBackColorTop, vPixel.y);
3a9b5dc8 265
266#endif
189f85a3 267}
268
fc73a202 269/////////////////////////////////////////////////////////////////////////////////////////
270// Functions for compute ray-object intersection
271
272// =======================================================================
273// function : GenerateRay
274// purpose :
275// =======================================================================
276SRay GenerateRay (in vec2 thePixel)
277{
278 vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
279 vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
280
281 vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x);
282 vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x);
a89742cf 283
284 vec3 aDirection = normalize (mix (aD0, aD1, thePixel.y));
285
286 return SRay (mix (aP0, aP1, thePixel.y), aDirection);
a89742cf 287}
288
fc73a202 289// =======================================================================
290// function : IntersectSphere
291// purpose : Computes ray-sphere intersection
292// =======================================================================
293float IntersectSphere (in SRay theRay, in float theRadius)
294{
295 float aDdotD = dot (theRay.Direct, theRay.Direct);
296 float aDdotO = dot (theRay.Direct, theRay.Origin);
297 float aOdotO = dot (theRay.Origin, theRay.Origin);
e2da917a 298
fc73a202 299 float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius);
e2da917a 300
dc9ef964 301 if (aD > 0.0f)
fc73a202 302 {
dc9ef964 303 float aTime = (sqrt (aD) - aDdotO) * (1.0f / aDdotD);
fc73a202 304
dc9ef964 305 return aTime > 0.0f ? aTime : MAXFLOAT;
fc73a202 306 }
e2da917a 307
fc73a202 308 return MAXFLOAT;
309}
310
311// =======================================================================
312// function : IntersectTriangle
313// purpose : Computes ray-triangle intersection (branchless version)
314// =======================================================================
f2474958 315void IntersectTriangle (in SRay theRay,
316 in vec3 thePnt0,
317 in vec3 thePnt1,
318 in vec3 thePnt2,
319 out vec3 theUVT,
320 out vec3 theNorm)
fc73a202 321{
f2474958 322 vec3 aToTrg = thePnt0 - theRay.Origin;
323
fc73a202 324 vec3 aEdge0 = thePnt1 - thePnt0;
325 vec3 aEdge1 = thePnt0 - thePnt2;
e2da917a 326
fc73a202 327 theNorm = cross (aEdge1, aEdge0);
328
f2474958 329 vec3 theVect = cross (theRay.Direct, aToTrg);
e2da917a 330
f2474958 331 theUVT = vec3 (dot (theNorm, aToTrg),
332 dot (theVect, aEdge1),
333 dot (theVect, aEdge0)) * (1.f / dot (theNorm, theRay.Direct));
fc73a202 334
f2474958 335 theUVT.x = any (lessThan (theUVT, ZERO)) || (theUVT.y + theUVT.z) > 1.f ? MAXFLOAT : theUVT.x;
336}
e2da917a 337
f2474958 338#define EMPTY_ROOT ivec4(0)
e2da917a 339
f2474958 340//! Utility structure containing information about
341//! currently traversing sub-tree of scene's BVH.
342struct SSubTree
343{
344 //! Transformed ray.
345 SRay TrsfRay;
fc73a202 346
f2474958 347 //! Inversed ray direction.
348 vec3 Inverse;
fc73a202 349
f2474958 350 //! Parameters of sub-root node.
351 ivec4 SubData;
352};
84c71f29 353
47e9c178 354#define MATERIAL_AMBN(index) (18 * index + 0)
355#define MATERIAL_DIFF(index) (18 * index + 1)
356#define MATERIAL_SPEC(index) (18 * index + 2)
357#define MATERIAL_EMIS(index) (18 * index + 3)
358#define MATERIAL_REFL(index) (18 * index + 4)
359#define MATERIAL_REFR(index) (18 * index + 5)
360#define MATERIAL_TRAN(index) (18 * index + 6)
361#define MATERIAL_TRS1(index) (18 * index + 7)
362#define MATERIAL_TRS2(index) (18 * index + 8)
363#define MATERIAL_TRS3(index) (18 * index + 9)
364
47e9c178 365#define TRS_OFFSET(treelet) treelet.SubData.x
366#define BVH_OFFSET(treelet) treelet.SubData.y
367#define VRT_OFFSET(treelet) treelet.SubData.z
368#define TRG_OFFSET(treelet) treelet.SubData.w
369
f2474958 370//! Identifies the absence of intersection.
371#define INALID_HIT ivec4 (-1)
372
373//! Global stack shared between traversal functions.
374int Stack[STACK_SIZE];
375
376// =======================================================================
377// function : pop
378// purpose :
379// =======================================================================
380int pop (inout int theHead)
381{
382 int aData = Stack[theHead];
383
384 int aMask = aData >> 26;
385 int aNode = aMask & 0x3;
386
387 aMask >>= 2;
388
389 if ((aMask & 0x3) == aNode)
390 {
391 --theHead;
392 }
393 else
394 {
395 aMask |= (aMask << 2) & 0x30;
396
397 Stack[theHead] = (aData & 0x03FFFFFF) | (aMask << 26);
398 }
399
400 return (aData & 0x03FFFFFF) + aNode;
401}
47e9c178 402
fc73a202 403// =======================================================================
47e9c178 404// function : SceneNearestHit
405// purpose : Finds intersection with nearest scene triangle
fc73a202 406// =======================================================================
47e9c178 407ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
fc73a202 408{
fc73a202 409 ivec4 aTriIndex = INALID_HIT;
410
47e9c178 411 int aNode = 0; // node to traverse
412 int aHead = -1; // pointer of stack
413 int aStop = -1; // BVH level switch
414
415 SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
416
f2474958 417 for (bool toContinue = true; toContinue; /* none */)
fc73a202 418 {
47e9c178 419 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
fc73a202 420
421 if (aData.x == 0) // if inner node
422 {
47e9c178 423 aData.y += BVH_OFFSET (aSubTree);
e2da917a 424
f2474958 425 vec4 aHitTimes = vec4 (MAXFLOAT,
426 MAXFLOAT,
427 MAXFLOAT,
428 MAXFLOAT);
429
430 vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse;
fc73a202 431
f2474958 432 vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
433 vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
434 vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
435 vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
436 vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
437 vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
438 vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
439 vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
e2da917a 440
f2474958 441 vec3 aTimeMax = max (aNodeMin0, aNodeMax0);
442 vec3 aTimeMin = min (aNodeMin0, aNodeMax0);
fc73a202 443
f2474958 444 float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
445 float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
e2da917a 446
f2474958 447 aHitTimes.x = mix (MAXFLOAT, aTimeEnter,
448 aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f);
fc73a202 449
f2474958 450 aTimeMax = max (aNodeMin1, aNodeMax1);
451 aTimeMin = min (aNodeMin1, aNodeMax1);
fc73a202 452
f2474958 453 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
454 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
fc73a202 455
f2474958 456 aHitTimes.y = mix (MAXFLOAT, aTimeEnter,
457 aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f);
fc73a202 458
f2474958 459 aTimeMax = max (aNodeMin2, aNodeMax2);
460 aTimeMin = min (aNodeMin2, aNodeMax2);
fc73a202 461
f2474958 462 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
463 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
47e9c178 464
f2474958 465 aHitTimes.z = mix (MAXFLOAT, aTimeEnter,
466 aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 1);
467
468 aTimeMax = max (aNodeMin3, aNodeMax3);
469 aTimeMin = min (aNodeMin3, aNodeMax3);
470
471 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
472 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
473
474 aHitTimes.w = mix (MAXFLOAT, aTimeEnter,
475 aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 2);
476
477 ivec4 aChildren = ivec4 (0, 1, 2, 3);
478
479 aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy;
480 aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy;
481 aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw;
482 aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw;
483 aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz;
484 aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz;
485 aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw;
486 aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw;
487 aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz;
488 aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz;
489
490 if (aHitTimes.x != MAXFLOAT)
fc73a202 491 {
f2474958 492 int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2
493 | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y);
494
495 if (aHitTimes.y != MAXFLOAT)
496 Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26;
e2da917a 497
f2474958 498 aNode = aData.y + aChildren.x;
fc73a202 499 }
f2474958 500 else
fc73a202 501 {
47e9c178 502 toContinue = (aHead >= 0);
503
504 if (aHead == aStop) // go to top-level BVH
fc73a202 505 {
47e9c178 506 aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
fc73a202 507 }
25ef750e 508
f2474958 509 if (aHead >= 0)
510 aNode = pop (aHead);
fc73a202 511 }
512 }
f2474958 513 else if (aData.x < 0) // leaf node (contains triangles)
fc73a202 514 {
515 vec3 aNormal;
f2474958 516 vec3 aTimeUV;
84c71f29 517
fc73a202 518 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
519 {
47e9c178 520 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
fc73a202 521
47e9c178 522 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;
523 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;
524 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;
fc73a202 525
f2474958 526 IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);
e2da917a 527
f2474958 528 if (aTimeUV.x < theHit.Time)
fc73a202 529 {
530 aTriIndex = aTriangle;
a89742cf 531
47e9c178 532 theTrsfId = TRS_OFFSET (aSubTree);
533
f2474958 534 theHit = SIntersect (aTimeUV.x, aTimeUV.yz, aNormal);
fc73a202 535 }
536 }
fc73a202 537
47e9c178 538 toContinue = (aHead >= 0);
539
540 if (aHead == aStop) // go to top-level BVH
541 {
542 aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
543 }
544
f2474958 545 if (aHead >= 0)
546 aNode = pop (aHead);
47e9c178 547 }
548 else if (aData.x > 0) // switch node
549 {
550 aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
551
552 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
553 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
554 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
555 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
556
557 aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
558 aInvTransf0,
559 aInvTransf1,
560 aInvTransf2);
561
562 aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) /
563 max (abs (aSubTree.TrsfRay.Direct), SMALL);
e2da917a 564
47e9c178 565 aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
566 aInvTransf0,
567 aInvTransf1,
568 aInvTransf2,
569 aInvTransf3);
570
571 aNode = BVH_OFFSET (aSubTree); // go to sub-root node
572
573 aStop = aHead; // store current stack pointer
fc73a202 574 }
575 }
576
577 return aTriIndex;
578}
579
580// =======================================================================
47e9c178 581// function : SceneAnyHit
582// purpose : Finds intersection with any scene triangle
fc73a202 583// =======================================================================
47e9c178 584float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
fc73a202 585{
8c820969 586 float aFactor = 1.f;
fc73a202 587
47e9c178 588 int aNode = 0; // node to traverse
589 int aHead = -1; // pointer of stack
590 int aStop = -1; // BVH level switch
591
592 SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
593
f2474958 594 for (bool toContinue = true; toContinue; /* none */)
fc73a202 595 {
e2da917a 596 ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
fc73a202 597
598 if (aData.x == 0) // if inner node
599 {
47e9c178 600 aData.y += BVH_OFFSET (aSubTree);
e2da917a 601
f2474958 602 vec4 aHitTimes = vec4 (MAXFLOAT,
603 MAXFLOAT,
604 MAXFLOAT,
605 MAXFLOAT);
606
607 vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse;
fc73a202 608
f2474958 609 vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
610 vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
611 vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
612 vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
613 vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
614 vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
615 vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
616 vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
fc73a202 617
f2474958 618 vec3 aTimeMax = max (aNodeMin0, aNodeMax0);
619 vec3 aTimeMin = min (aNodeMin0, aNodeMax0);
fc73a202 620
f2474958 621 float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
622 float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
e2da917a 623
f2474958 624 aHitTimes.x = mix (MAXFLOAT, aTimeEnter,
625 aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f);
fc73a202 626
f2474958 627 aTimeMax = max (aNodeMin1, aNodeMax1);
628 aTimeMin = min (aNodeMin1, aNodeMax1);
fc73a202 629
f2474958 630 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
631 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
fc73a202 632
f2474958 633 aHitTimes.y = mix (MAXFLOAT, aTimeEnter,
634 aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f);
fc73a202 635
f2474958 636 aTimeMax = max (aNodeMin2, aNodeMax2);
637 aTimeMin = min (aNodeMin2, aNodeMax2);
fc73a202 638
f2474958 639 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
640 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
47e9c178 641
f2474958 642 aHitTimes.z = mix (MAXFLOAT, aTimeEnter,
643 aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 1);
644
645 aTimeMax = max (aNodeMin3, aNodeMax3);
646 aTimeMin = min (aNodeMin3, aNodeMax3);
647
648 aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
649 aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
650
651 aHitTimes.w = mix (MAXFLOAT, aTimeEnter,
652 aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 2);
653
654 ivec4 aChildren = ivec4 (0, 1, 2, 3);
655
656 aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy;
657 aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy;
658 aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw;
659 aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw;
660 aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz;
661 aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz;
662 aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw;
663 aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw;
664 aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz;
665 aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz;
666
667 if (aHitTimes.x != MAXFLOAT)
fc73a202 668 {
f2474958 669 int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2
670 | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y);
fc73a202 671
f2474958 672 if (aHitTimes.y != MAXFLOAT)
673 Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26;
674
675 aNode = aData.y + aChildren.x;
fc73a202 676 }
f2474958 677 else
fc73a202 678 {
47e9c178 679 toContinue = (aHead >= 0);
680
681 if (aHead == aStop) // go to top-level BVH
fc73a202 682 {
47e9c178 683 aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
fc73a202 684 }
fc73a202 685
f2474958 686 if (aHead >= 0)
687 aNode = pop (aHead);
fc73a202 688 }
689 }
47e9c178 690 else if (aData.x < 0) // leaf node
fc73a202 691 {
692 vec3 aNormal;
f2474958 693 vec3 aTimeUV;
25ef750e 694
fc73a202 695 for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
696 {
47e9c178 697 ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
fc73a202 698
47e9c178 699 vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;
700 vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;
701 vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;
fc73a202 702
f2474958 703 IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);
bc8c79bb 704
705#ifdef TRANSPARENT_SHADOWS
f2474958 706 if (aTimeUV.x < theDistance)
bc8c79bb 707 {
8c820969 708 aFactor *= 1.f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
bc8c79bb 709 }
710#else
f2474958 711 if (aTimeUV.x < theDistance)
8c820969 712 {
713 aFactor = 0.f;
714 }
bc8c79bb 715#endif
fc73a202 716 }
25ef750e 717
3a9b5dc8 718 toContinue = (aHead >= 0) && (aFactor > 0.1f);
25ef750e 719
47e9c178 720 if (aHead == aStop) // go to top-level BVH
fc73a202 721 {
47e9c178 722 aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
fc73a202 723 }
e2da917a 724
f2474958 725 if (aHead >= 0)
726 aNode = pop (aHead);
fc73a202 727 }
47e9c178 728 else if (aData.x > 0) // switch node
fc73a202 729 {
47e9c178 730 aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
bc8c79bb 731
47e9c178 732 vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
733 vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
734 vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
735 vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
fc73a202 736
47e9c178 737 aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
738 aInvTransf0,
739 aInvTransf1,
740 aInvTransf2);
bc8c79bb 741
47e9c178 742 aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
743 aInvTransf0,
744 aInvTransf1,
745 aInvTransf2,
746 aInvTransf3);
fc73a202 747
47e9c178 748 aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) / max (abs (aSubTree.TrsfRay.Direct), SMALL);
bc8c79bb 749
47e9c178 750 aNode = BVH_OFFSET (aSubTree); // go to sub-root node
84c71f29 751
47e9c178 752 aStop = aHead; // store current stack pointer
fc73a202 753 }
754 }
25ef750e 755
bc8c79bb 756 return aFactor;
fc73a202 757}
758
759#define PI 3.1415926f
760
761// =======================================================================
762// function : Latlong
763// purpose : Converts world direction to environment texture coordinates
764// =======================================================================
765vec2 Latlong (in vec3 thePoint, in float theRadius)
766{
767 float aPsi = acos (-thePoint.z / theRadius);
25ef750e 768
fc73a202 769 float aPhi = atan (thePoint.y, thePoint.x) + PI;
25ef750e 770
fc73a202 771 return vec2 (aPhi * 0.1591549f,
772 aPsi * 0.3183098f);
773}
774
775// =======================================================================
776// function : SmoothNormal
777// purpose : Interpolates normal across the triangle
778// =======================================================================
779vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle)
780{
781 vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz;
782 vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz;
783 vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz;
25ef750e 784
fc73a202 785 return normalize (aNormal1 * theUV.x +
786 aNormal2 * theUV.y +
dc9ef964 787 aNormal0 * (1.0f - theUV.x - theUV.y));
788}
789
25ef750e 790// =======================================================================
791// function : SmoothUV
792// purpose : Interpolates UV coordinates across the triangle
793// =======================================================================
794#ifdef USE_TEXTURES
795vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)
796{
797 vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;
798 vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;
799 vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;
800
801 return aTexCrd1 * theUV.x +
802 aTexCrd2 * theUV.y +
803 aTexCrd0 * (1.0f - theUV.x - theUV.y);
804}
805#endif
806
189f85a3 807// =======================================================================
808// function : FetchEnvironment
809// purpose :
810// =======================================================================
811vec4 FetchEnvironment (in vec2 theTexCoord)
812{
813 return mix (vec4 (0.0f, 0.0f, 0.0f, 1.0f),
814 textureLod (uEnvironmentMapTexture, theTexCoord, 0.0f), float (uSphereMapEnabled));
815}
816
dc9ef964 817// =======================================================================
818// function : Refract
bc8c79bb 819// purpose : Computes refraction ray (also handles TIR)
dc9ef964 820// =======================================================================
189f85a3 821#ifndef PATH_TRACING
dc9ef964 822vec3 Refract (in vec3 theInput,
823 in vec3 theNormal,
824 in float theRefractIndex,
825 in float theInvRefractIndex)
826{
25ef750e 827 float aNdotI = dot (theInput, theNormal);
828
dc9ef964 829 float anIndex = aNdotI < 0.0f
830 ? theInvRefractIndex
831 : theRefractIndex;
25ef750e 832
dc9ef964 833 float aSquare = anIndex * anIndex * (1.0f - aNdotI * aNdotI);
25ef750e 834
dc9ef964 835 if (aSquare > 1.0f)
836 {
837 return reflect (theInput, theNormal);
838 }
25ef750e 839
dc9ef964 840 float aNdotT = sqrt (1.0f - aSquare);
25ef750e 841
dc9ef964 842 return normalize (anIndex * theInput -
bc8c79bb 843 (anIndex * aNdotI + (aNdotI < 0.0f ? aNdotT : -aNdotT)) * theNormal);
fc73a202 844}
189f85a3 845#endif
fc73a202 846
a89742cf 847#define MIN_SLOPE 0.0001f
848#define EPS_SCALE 8.0000f
849
bc8c79bb 850#define THRESHOLD vec3 (0.1f)
fc73a202 851
1804bb99 852#define INVALID_BOUNCES 1000
853
fc73a202 854#define LIGHT_POS(index) (2 * index + 1)
855#define LIGHT_PWR(index) (2 * index + 0)
856
857// =======================================================================
858// function : Radiance
25ef750e 859// purpose : Computes color along the given ray
fc73a202 860// =======================================================================
189f85a3 861#ifndef PATH_TRACING
fc73a202 862vec4 Radiance (in SRay theRay, in vec3 theInverse)
863{
dc9ef964 864 vec3 aResult = vec3 (0.0f);
865 vec4 aWeight = vec4 (1.0f);
84c71f29 866
8c820969 867 int aTrsfId;
a89742cf 868
1d865689 869 float aRaytraceDepth = MAXFLOAT;
a89742cf 870
25ef750e 871 for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
fc73a202 872 {
873 SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
a89742cf 874
8c820969 875 ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId);
fc73a202 876
877 if (aTriIndex.x == -1)
878 {
189f85a3 879 vec4 aColor = vec4 (0.0);
25ef750e 880
189f85a3 881 if (bool(uSphereMapForBack) || aWeight.w == 0.0f /* reflection */)
fc73a202 882 {
883 float aTime = IntersectSphere (theRay, uSceneRadius);
25ef750e 884
189f85a3 885 aColor = FetchEnvironment (Latlong (
886 theRay.Direct * aTime + theRay.Origin, uSceneRadius));
887 }
888 else
889 {
3a9b5dc8 890 aColor = BackgroundColor();
fc73a202 891 }
25ef750e 892
8c820969 893 aResult += aWeight.xyz * aColor.xyz; aWeight.w *= aColor.w;
894
895 break; // terminate path
fc73a202 896 }
a89742cf 897
8c820969 898 vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz;
899 vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz;
900 vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz;
cf537aac 901
902 aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
903 dot (aInvTransf1, aHit.Normal),
904 dot (aInvTransf2, aHit.Normal)));
1804bb99 905
1804bb99 906 theRay.Origin += theRay.Direct * aHit.Time; // intersection point
907
3a9b5dc8 908 // Evaluate depth on first hit
1d865689 909 if (aDepth == 0)
910 {
3a9b5dc8 911 // For polygons that are parallel to the screen plane, the depth slope
912 // is equal to 1, resulting in small polygon offset. For polygons that
913 // that are at a large angle to the screen, the depth slope tends to 1,
914 // resulting in a larger polygon offset
915 float aPolygonOffset = uSceneEpsilon * EPS_SCALE /
916 max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
917
1d865689 918 // Hit point in NDC-space [-1,1] (the polygon offset is applied in the world space)
919 vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin + theRay.Direct * aPolygonOffset, 1.f);
1d865689 920
3a9b5dc8 921 aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w) * 0.5f + 0.5f;
1d865689 922 }
923
1804bb99 924 vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
925
926 aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
927 dot (aInvTransf1, aNormal),
928 dot (aInvTransf2, aNormal)));
25ef750e 929
dc9ef964 930 vec3 aAmbient = texelFetch (
931 uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb;
25ef750e 932 vec4 aDiffuse = texelFetch (
933 uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w));
dc9ef964 934 vec4 aSpecular = texelFetch (
935 uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w));
936 vec4 aOpacity = texelFetch (
937 uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w));
25ef750e 938
939#ifdef USE_TEXTURES
940 if (aDiffuse.w >= 0.f)
941 {
942 vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);
943
944 vec4 aTrsfRow1 = texelFetch (
945 uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));
946 vec4 aTrsfRow2 = texelFetch (
947 uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));
948
949 aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
950 dot (aTrsfRow2, aTexCoord));
951
952 vec3 aTexColor = textureLod (
47e9c178 953 sampler2D (uTextureSamplers[int(aDiffuse.w)]), aTexCoord.st, 0.f).rgb;
25ef750e 954
955 aDiffuse.rgb *= aTexColor;
956 aAmbient.rgb *= aTexColor;
957 }
958#endif
84c71f29 959
1804bb99 960 vec3 aEmission = texelFetch (
961 uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb;
84c71f29 962
1804bb99 963 float aGeomFactor = dot (aNormal, theRay.Direct);
964
965 aResult.xyz += aWeight.xyz * aOpacity.x * (
966 uGlobalAmbient.xyz * aAmbient * max (abs (aGeomFactor), 0.5f) + aEmission);
25ef750e 967
1804bb99 968 vec3 aSidedNormal = mix (aNormal, -aNormal, step (0.0f, aGeomFactor));
a89742cf 969
fc73a202 970 for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)
971 {
972 vec4 aLight = texelFetch (
973 uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));
e2da917a 974
fc73a202 975 float aDistance = MAXFLOAT;
e2da917a 976
dc9ef964 977 if (aLight.w != 0.0f) // point light source
fc73a202 978 {
1804bb99 979 aDistance = length (aLight.xyz -= theRay.Origin);
e2da917a 980
dc9ef964 981 aLight.xyz *= 1.0f / aDistance;
fc73a202 982 }
983
1804bb99 984 float aLdotN = dot (aLight.xyz, aSidedNormal);
e2da917a 985
1804bb99 986 if (aLdotN > 0.0f) // first check if light source is important
fc73a202 987 {
1804bb99 988 float aVisibility = 1.0f;
25ef750e 989
189f85a3 990 if (bool(uShadowsEnabled))
1804bb99 991 {
992 SRay aShadow = SRay (theRay.Origin, aLight.xyz);
e2da917a 993
1804bb99 994 aShadow.Origin += uSceneEpsilon * (aLight.xyz +
995 mix (-aHit.Normal, aHit.Normal, step (0.0f, dot (aHit.Normal, aLight.xyz))));
25ef750e 996
1804bb99 997 vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL);
25ef750e 998
1804bb99 999 aVisibility = SceneAnyHit (
1000 aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance);
1001 }
25ef750e 1002
1804bb99 1003 if (aVisibility > 0.0f)
fc73a202 1004 {
1804bb99 1005 vec3 aIntensity = vec3 (texelFetch (
1006 uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
1007
1008 float aRdotV = dot (reflect (aLight.xyz, aSidedNormal), theRay.Direct);
25ef750e 1009
bc8c79bb 1010 aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity *
1804bb99 1011 (aDiffuse.xyz * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w));
fc73a202 1012 }
1013 }
1014 }
0e330c8c 1015
dc9ef964 1016 if (aOpacity.x != 1.0f)
fc73a202 1017 {
1018 aWeight *= aOpacity.y;
a89742cf 1019
bc8c79bb 1020 if (aOpacity.z != 1.0f)
1021 {
1022 theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w);
a89742cf 1023 }
fc73a202 1024 }
1025 else
1026 {
189f85a3 1027 aWeight *= bool(uReflectEnabled) ?
dc9ef964 1028 texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f);
25ef750e 1029
1804bb99 1030 vec3 aReflect = reflect (theRay.Direct, aNormal);
25ef750e 1031
1804bb99 1032 if (dot (aReflect, aHit.Normal) * dot (theRay.Direct, aHit.Normal) > 0.0f)
fc73a202 1033 {
1804bb99 1034 aReflect = reflect (theRay.Direct, aHit.Normal);
fc73a202 1035 }
1036
1804bb99 1037 theRay.Direct = aReflect;
fc73a202 1038 }
25ef750e 1039
fc73a202 1040 if (all (lessThanEqual (aWeight.xyz, THRESHOLD)))
1041 {
1804bb99 1042 aDepth = INVALID_BOUNCES;
1043 }
1044 else if (aOpacity.x == 1.0f || aOpacity.z != 1.0f) // if no simple transparency
1045 {
1046 theRay.Origin += aHit.Normal * mix (
1047 -uSceneEpsilon, uSceneEpsilon, step (0.0f, dot (aHit.Normal, theRay.Direct)));
1048
1049 theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
1050
1051 theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct));
fc73a202 1052 }
25ef750e 1053
1804bb99 1054 theRay.Origin += theRay.Direct * uSceneEpsilon;
fc73a202 1055 }
1056
1d865689 1057 gl_FragDepth = aRaytraceDepth;
1058
fc73a202 1059 return vec4 (aResult.x,
1060 aResult.y,
1061 aResult.z,
1062 aWeight.w);
1063}
189f85a3 1064#endif