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