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