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