fc73a202 |
1 | //! Normalized pixel coordinates. |
2 | in vec2 vPixel; |
3 | |
4 | //! Origin of viewing ray in left-top corner. |
5 | uniform vec3 uOriginLT; |
6 | //! Origin of viewing ray in left-bottom corner. |
7 | uniform vec3 uOriginLB; |
8 | //! Origin of viewing ray in right-top corner. |
9 | uniform vec3 uOriginRT; |
10 | //! Origin of viewing ray in right-bottom corner. |
11 | uniform vec3 uOriginRB; |
12 | |
13 | //! Direction of viewing ray in left-top corner. |
14 | uniform vec3 uDirectLT; |
15 | //! Direction of viewing ray in left-bottom corner. |
16 | uniform vec3 uDirectLB; |
17 | //! Direction of viewing ray in right-top corner. |
18 | uniform vec3 uDirectRT; |
19 | //! Direction of viewing ray in right-bottom corner. |
20 | uniform vec3 uDirectRB; |
21 | |
22 | //! Texture buffer of data records of high-level BVH nodes. |
23 | uniform isamplerBuffer uSceneNodeInfoTexture; |
24 | //! Texture buffer of minimum points of high-level BVH nodes. |
25 | uniform samplerBuffer uSceneMinPointTexture; |
26 | //! Texture buffer of maximum points of high-level BVH nodes. |
27 | uniform samplerBuffer uSceneMaxPointTexture; |
28 | |
29 | //! Texture buffer of data records of bottom-level BVH nodes. |
30 | uniform isamplerBuffer uObjectNodeInfoTexture; |
31 | //! Texture buffer of minimum points of bottom-level BVH nodes. |
32 | uniform samplerBuffer uObjectMinPointTexture; |
33 | //! Texture buffer of maximum points of bottom-level BVH nodes. |
34 | uniform samplerBuffer uObjectMaxPointTexture; |
35 | |
36 | //! Texture buffer of vertex coords. |
37 | uniform samplerBuffer uGeometryVertexTexture; |
38 | //! Texture buffer of vertex normals. |
39 | uniform samplerBuffer uGeometryNormalTexture; |
40 | //! Texture buffer of triangle indices. |
41 | uniform isamplerBuffer uGeometryTriangTexture; |
42 | |
43 | //! Texture buffer of material properties. |
44 | uniform samplerBuffer uRaytraceMaterialTexture; |
45 | //! Texture buffer of light source properties. |
46 | uniform samplerBuffer uRaytraceLightSrcTexture; |
47 | //! Environment map texture. |
48 | uniform sampler2D uEnvironmentMapTexture; |
49 | |
50 | //! Total number of light sources. |
51 | uniform int uLightCount; |
52 | //! Intensity of global ambient light. |
53 | uniform vec4 uGlobalAmbient; |
54 | |
55 | //! Enables/disables environment map. |
56 | uniform int uEnvironmentEnable; |
57 | //! Enables/disables computation of shadows. |
58 | uniform int uShadowsEnable; |
59 | //! Enables/disables computation of reflections. |
60 | uniform int uReflectionsEnable; |
61 | |
62 | //! Radius of bounding sphere of the scene. |
63 | uniform float uSceneRadius; |
64 | //! Scene epsilon to prevent self-intersections. |
65 | uniform float uSceneEpsilon; |
66 | |
67 | ///////////////////////////////////////////////////////////////////////////////////////// |
68 | // Specific data types |
69 | |
70 | //! Stores ray parameters. |
71 | struct SRay |
72 | { |
73 | vec3 Origin; |
74 | |
75 | vec3 Direct; |
76 | }; |
77 | |
78 | //! Stores intersection parameters. |
79 | struct 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 | // ======================================================================= |
109 | SRay 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 | // ======================================================================= |
125 | float 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 | // ======================================================================= |
147 | float 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. |
175 | int 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 | // ======================================================================= |
184 | ivec4 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 | // ======================================================================= |
292 | float 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 | // ======================================================================= |
394 | ivec4 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 | // ======================================================================= |
497 | float 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 | // ======================================================================= |
581 | vec2 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 | // ======================================================================= |
595 | vec3 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 | // ======================================================================= |
623 | vec4 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 | } |