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