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