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