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