3a9b5dc8 |
1 | #ifdef ADAPTIVE_SAMPLING |
2 | #extension GL_ARB_shader_image_load_store : require |
3 | #extension GL_NV_shader_atomic_float : require |
4 | #endif |
5 | |
25ef750e |
6 | #ifdef USE_TEXTURES |
7 | #extension GL_ARB_bindless_texture : require |
8 | #endif |
9 | |
fc73a202 |
10 | //! Normalized pixel coordinates. |
11 | in vec2 vPixel; |
12 | |
50d0e1ce |
13 | //! Sub-pixel offset in X direction for FSAA. |
14 | uniform float uOffsetX = 0.f; |
15 | //! Sub-pixel offset in Y direction for FSAA. |
16 | uniform float uOffsetY = 0.f; |
17 | |
fc73a202 |
18 | //! Origin of viewing ray in left-top corner. |
19 | uniform vec3 uOriginLT; |
20 | //! Origin of viewing ray in left-bottom corner. |
21 | uniform vec3 uOriginLB; |
22 | //! Origin of viewing ray in right-top corner. |
23 | uniform vec3 uOriginRT; |
24 | //! Origin of viewing ray in right-bottom corner. |
25 | uniform vec3 uOriginRB; |
26 | |
312a4043 |
27 | //! Width of the rendering window. |
28 | uniform int uWinSizeX; |
29 | //! Height of the rendering window. |
30 | uniform int uWinSizeY; |
31 | |
fc73a202 |
32 | //! Direction of viewing ray in left-top corner. |
33 | uniform vec3 uDirectLT; |
34 | //! Direction of viewing ray in left-bottom corner. |
35 | uniform vec3 uDirectLB; |
36 | //! Direction of viewing ray in right-top corner. |
37 | uniform vec3 uDirectRT; |
38 | //! Direction of viewing ray in right-bottom corner. |
39 | uniform vec3 uDirectRB; |
40 | |
a89742cf |
41 | //! Inverse model-view-projection matrix. |
25ef750e |
42 | uniform mat4 uUnviewMat; |
43 | |
1d865689 |
44 | //! Model-view-projection matrix. |
45 | uniform mat4 uViewMat; |
46 | |
e2da917a |
47 | //! Texture buffer of data records of bottom-level BVH nodes. |
fc73a202 |
48 | uniform isamplerBuffer uSceneNodeInfoTexture; |
e2da917a |
49 | //! Texture buffer of minimum points of bottom-level BVH nodes. |
fc73a202 |
50 | uniform samplerBuffer uSceneMinPointTexture; |
e2da917a |
51 | //! Texture buffer of maximum points of bottom-level BVH nodes. |
fc73a202 |
52 | uniform samplerBuffer uSceneMaxPointTexture; |
84c71f29 |
53 | //! Texture buffer of transformations of high-level BVH nodes. |
54 | uniform samplerBuffer uSceneTransformTexture; |
fc73a202 |
55 | |
fc73a202 |
56 | //! Texture buffer of vertex coords. |
57 | uniform samplerBuffer uGeometryVertexTexture; |
58 | //! Texture buffer of vertex normals. |
59 | uniform samplerBuffer uGeometryNormalTexture; |
25ef750e |
60 | #ifdef USE_TEXTURES |
61 | //! Texture buffer of per-vertex UV-coordinates. |
62 | uniform samplerBuffer uGeometryTexCrdTexture; |
63 | #endif |
fc73a202 |
64 | //! Texture buffer of triangle indices. |
65 | uniform isamplerBuffer uGeometryTriangTexture; |
66 | |
67 | //! Texture buffer of material properties. |
68 | uniform samplerBuffer uRaytraceMaterialTexture; |
69 | //! Texture buffer of light source properties. |
70 | uniform samplerBuffer uRaytraceLightSrcTexture; |
71 | //! Environment map texture. |
72 | uniform sampler2D uEnvironmentMapTexture; |
73 | |
74 | //! Total number of light sources. |
75 | uniform int uLightCount; |
76 | //! Intensity of global ambient light. |
77 | uniform vec4 uGlobalAmbient; |
78 | |
189f85a3 |
79 | //! Enables/disables hard shadows. |
80 | uniform int uShadowsEnabled; |
81 | //! Enables/disables specular reflections. |
82 | uniform int uReflectEnabled; |
83 | //! Enables/disables spherical environment map. |
84 | uniform int uSphereMapEnabled; |
85 | //! Enables/disables environment map background. |
86 | uniform int uSphereMapForBack; |
fc73a202 |
87 | |
88 | //! Radius of bounding sphere of the scene. |
89 | uniform float uSceneRadius; |
90 | //! Scene epsilon to prevent self-intersections. |
91 | uniform float uSceneEpsilon; |
92 | |
25ef750e |
93 | #ifdef USE_TEXTURES |
94 | //! Unique 64-bit handles of OpenGL textures. |
47e9c178 |
95 | uniform uvec2 uTextureSamplers[MAX_TEX_NUMBER]; |
25ef750e |
96 | #endif |
97 | |
3a9b5dc8 |
98 | #ifdef ADAPTIVE_SAMPLING |
99 | //! OpenGL image used for accumulating rendering result. |
100 | volatile restrict layout(size1x32) uniform image2D uRenderImage; |
101 | |
102 | //! OpenGL image storing offsets of sampled pixels blocks. |
103 | coherent restrict layout(size2x32) uniform iimage2D uOffsetImage; |
104 | #endif |
105 | |
189f85a3 |
106 | //! Top color of gradient background. |
107 | uniform vec4 uBackColorTop = vec4 (0.0); |
108 | //! Bottom color of gradient background. |
109 | uniform vec4 uBackColorBot = vec4 (0.0); |
110 | |
b27ab03d |
111 | //! Aperture radius of camera used for depth-of-field |
112 | uniform float uApertureRadius = 0.f; |
113 | |
114 | //! Focal distance of camera used for depth-of field |
115 | uniform float uFocalPlaneDist = 10.f; |
116 | |
117 | //! Camera position used for projective mode |
118 | uniform vec3 uEyeOrig; |
119 | |
120 | //! Camera view direction used for projective mode |
121 | uniform vec3 uEyeView; |
122 | |
123 | //! Camera's screen vertical direction used for projective mode |
124 | uniform vec3 uEyeVert; |
125 | |
126 | //! Camera's screen horizontal direction used for projective mode |
127 | uniform vec3 uEyeSide; |
128 | |
129 | //! Camera's screen size used for projective mode |
130 | uniform vec2 uEyeSize; |
131 | |
fc73a202 |
132 | ///////////////////////////////////////////////////////////////////////////////////////// |
133 | // Specific data types |
189f85a3 |
134 | |
fc73a202 |
135 | //! Stores ray parameters. |
136 | struct SRay |
137 | { |
138 | vec3 Origin; |
189f85a3 |
139 | |
fc73a202 |
140 | vec3 Direct; |
141 | }; |
142 | |
143 | //! Stores intersection parameters. |
144 | struct SIntersect |
145 | { |
146 | float Time; |
189f85a3 |
147 | |
fc73a202 |
148 | vec2 UV; |
189f85a3 |
149 | |
fc73a202 |
150 | vec3 Normal; |
151 | }; |
152 | |
153 | ///////////////////////////////////////////////////////////////////////////////////////// |
154 | // Some useful constants |
155 | |
156 | #define MAXFLOAT 1e15f |
157 | |
dc9ef964 |
158 | #define SMALL vec3 (exp2 (-80.0f)) |
fc73a202 |
159 | |
dc9ef964 |
160 | #define ZERO vec3 (0.0f, 0.0f, 0.0f) |
161 | #define UNIT vec3 (1.0f, 1.0f, 1.0f) |
fc73a202 |
162 | |
dc9ef964 |
163 | #define AXIS_X vec3 (1.0f, 0.0f, 0.0f) |
164 | #define AXIS_Y vec3 (0.0f, 1.0f, 0.0f) |
165 | #define AXIS_Z vec3 (0.0f, 0.0f, 1.0f) |
fc73a202 |
166 | |
6e728f3b |
167 | #define M_PI 3.141592653f |
168 | #define M_2_PI 6.283185307f |
169 | #define M_PI_2 1.570796327f |
189f85a3 |
170 | |
171 | #define LUMA vec3 (0.2126f, 0.7152f, 0.0722f) |
172 | |
173 | // ======================================================================= |
174 | // function : MatrixRowMultiplyDir |
175 | // purpose : Multiplies a vector by matrix |
176 | // ======================================================================= |
177 | vec3 MatrixRowMultiplyDir (in vec3 v, |
178 | in vec4 m0, |
179 | in vec4 m1, |
180 | in vec4 m2) |
181 | { |
182 | return vec3 (dot (m0.xyz, v), |
183 | dot (m1.xyz, v), |
184 | dot (m2.xyz, v)); |
185 | } |
186 | |
312a4043 |
187 | //! 32-bit state of random number generator. |
188 | uint RandState; |
189 | |
190 | // ======================================================================= |
191 | // function : SeedRand |
192 | // purpose : Applies hash function by Thomas Wang to randomize seeds |
193 | // (see http://www.burtleburtle.net/bob/hash/integer.html) |
194 | // ======================================================================= |
8c820969 |
195 | void SeedRand (in int theSeed, in int theSizeX, in int theRadius) |
312a4043 |
196 | { |
8c820969 |
197 | RandState = uint (int (gl_FragCoord.y) / theRadius * theSizeX + int (gl_FragCoord.x) / theRadius + theSeed); |
312a4043 |
198 | |
199 | RandState = (RandState + 0x479ab41du) + (RandState << 8); |
200 | RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >> 5); |
201 | RandState = (RandState + 0x9942f0a6u) - (RandState << 14); |
202 | RandState = (RandState ^ 0x5aedd67du) ^ (RandState >> 3); |
203 | RandState = (RandState + 0x17bea992u) + (RandState << 7); |
204 | } |
205 | |
206 | // ======================================================================= |
207 | // function : RandInt |
208 | // purpose : Generates integer using Xorshift algorithm by G. Marsaglia |
209 | // ======================================================================= |
210 | uint RandInt() |
211 | { |
212 | RandState ^= (RandState << 13); |
213 | RandState ^= (RandState >> 17); |
214 | RandState ^= (RandState << 5); |
215 | |
216 | return RandState; |
217 | } |
218 | |
219 | // ======================================================================= |
220 | // function : RandFloat |
ee5befae |
221 | // purpose : Generates a random float in 0 <= x < 1 range |
312a4043 |
222 | // ======================================================================= |
223 | float RandFloat() |
224 | { |
225 | return float (RandInt()) * (1.f / 4294967296.f); |
226 | } |
227 | |
bc8c79bb |
228 | // ======================================================================= |
229 | // function : MatrixColMultiplyPnt |
230 | // purpose : Multiplies a vector by matrix |
231 | // ======================================================================= |
232 | vec3 MatrixColMultiplyPnt (in vec3 v, |
233 | in vec4 m0, |
234 | in vec4 m1, |
235 | in vec4 m2, |
236 | in vec4 m3) |
237 | { |
47e9c178 |
238 | return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z + m3.x, |
239 | m0.y * v.x + m1.y * v.y + m2.y * v.z + m3.y, |
240 | m0.z * v.x + m1.z * v.y + m2.z * v.z + m3.z); |
bc8c79bb |
241 | } |
84c71f29 |
242 | |
243 | // ======================================================================= |
bc8c79bb |
244 | // function : MatrixColMultiplyDir |
84c71f29 |
245 | // purpose : Multiplies a vector by matrix |
246 | // ======================================================================= |
bc8c79bb |
247 | vec3 MatrixColMultiplyDir (in vec3 v, |
248 | in vec4 m0, |
249 | in vec4 m1, |
47e9c178 |
250 | in vec4 m2) |
84c71f29 |
251 | { |
47e9c178 |
252 | return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z, |
253 | m0.y * v.x + m1.y * v.y + m2.y * v.z, |
254 | m0.z * v.x + m1.z * v.y + m2.z * v.z); |
84c71f29 |
255 | } |
256 | |
189f85a3 |
257 | //======================================================================= |
258 | // function : InverseDirection |
259 | // purpose : Returns safely inverted direction of the given one |
260 | //======================================================================= |
261 | vec3 InverseDirection (in vec3 theInput) |
262 | { |
263 | vec3 anInverse = 1.f / max (abs (theInput), SMALL); |
264 | |
265 | return mix (-anInverse, anInverse, step (ZERO, theInput)); |
266 | } |
267 | |
268 | //======================================================================= |
269 | // function : BackgroundColor |
270 | // purpose : Returns color of gradient background |
271 | //======================================================================= |
272 | vec4 BackgroundColor() |
273 | { |
3a9b5dc8 |
274 | #ifdef ADAPTIVE_SAMPLING |
275 | |
276 | ivec2 aFragCoord = ivec2 (gl_FragCoord.xy); |
277 | |
278 | ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE, |
279 | aFragCoord.y / BLOCK_SIZE)).xy; |
280 | |
281 | aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, BLOCK_SIZE); |
282 | |
283 | return mix (uBackColorBot, uBackColorTop, float (aTileXY.y) / uWinSizeY); |
284 | |
285 | #else |
286 | |
189f85a3 |
287 | return mix (uBackColorBot, uBackColorTop, vPixel.y); |
3a9b5dc8 |
288 | |
289 | #endif |
189f85a3 |
290 | } |
291 | |
fc73a202 |
292 | ///////////////////////////////////////////////////////////////////////////////////////// |
293 | // Functions for compute ray-object intersection |
294 | |
b27ab03d |
295 | //======================================================================= |
296 | // function : sampleUniformDisk |
297 | // purpose : |
298 | //======================================================================= |
299 | vec2 sampleUniformDisk () |
300 | { |
301 | vec2 aPoint; |
302 | |
303 | float aKsi1 = 2.f * RandFloat () - 1.f; |
304 | float aKsi2 = 2.f * RandFloat () - 1.f; |
305 | |
306 | if (aKsi1 > -aKsi2) |
307 | { |
308 | if (aKsi1 > aKsi2) |
309 | aPoint = vec2 (aKsi1, (M_PI / 4.f) * (0.f + aKsi2 / aKsi1)); |
310 | else |
311 | aPoint = vec2 (aKsi2, (M_PI / 4.f) * (2.f - aKsi1 / aKsi2)); |
312 | } |
313 | else |
314 | { |
315 | if (aKsi1 < aKsi2) |
316 | aPoint = vec2 (-aKsi1, (M_PI / 4.f) * (4.f + aKsi2 / aKsi1)); |
317 | else |
318 | aPoint = vec2 (-aKsi2, (M_PI / 4.f) * (6.f - aKsi1 / aKsi2)); |
319 | } |
320 | |
321 | return vec2 (sin (aPoint.y), cos (aPoint.y)) * aPoint.x; |
322 | } |
323 | |
fc73a202 |
324 | // ======================================================================= |
325 | // function : GenerateRay |
326 | // purpose : |
327 | // ======================================================================= |
328 | SRay GenerateRay (in vec2 thePixel) |
329 | { |
b27ab03d |
330 | #ifndef DEPTH_OF_FIELD |
331 | |
fc73a202 |
332 | vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x); |
333 | vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x); |
334 | |
335 | vec3 aD0 = mix (uDirectLB, uDirectRB, thePixel.x); |
336 | vec3 aD1 = mix (uDirectLT, uDirectRT, thePixel.x); |
a89742cf |
337 | |
338 | vec3 aDirection = normalize (mix (aD0, aD1, thePixel.y)); |
339 | |
340 | return SRay (mix (aP0, aP1, thePixel.y), aDirection); |
b27ab03d |
341 | |
342 | #else |
343 | |
344 | vec2 aPixel = uEyeSize * (thePixel - vec2 (0.5f)) * 2.f; |
345 | |
346 | vec2 aAperturePnt = sampleUniformDisk () * uApertureRadius; |
347 | |
348 | vec3 aLocalDir = normalize (vec3 ( |
349 | aPixel * uFocalPlaneDist - aAperturePnt, uFocalPlaneDist)); |
350 | |
351 | vec3 aOrigin = uEyeOrig + |
352 | uEyeSide * aAperturePnt.x + |
353 | uEyeVert * aAperturePnt.y; |
354 | |
355 | vec3 aDirect = uEyeView * aLocalDir.z + |
356 | uEyeSide * aLocalDir.x + |
357 | uEyeVert * aLocalDir.y; |
358 | |
359 | return SRay (aOrigin, aDirect); |
360 | |
361 | #endif |
a89742cf |
362 | } |
363 | |
fc73a202 |
364 | // ======================================================================= |
365 | // function : IntersectSphere |
366 | // purpose : Computes ray-sphere intersection |
367 | // ======================================================================= |
368 | float IntersectSphere (in SRay theRay, in float theRadius) |
369 | { |
370 | float aDdotD = dot (theRay.Direct, theRay.Direct); |
371 | float aDdotO = dot (theRay.Direct, theRay.Origin); |
372 | float aOdotO = dot (theRay.Origin, theRay.Origin); |
e2da917a |
373 | |
fc73a202 |
374 | float aD = aDdotO * aDdotO - aDdotD * (aOdotO - theRadius * theRadius); |
e2da917a |
375 | |
dc9ef964 |
376 | if (aD > 0.0f) |
fc73a202 |
377 | { |
dc9ef964 |
378 | float aTime = (sqrt (aD) - aDdotO) * (1.0f / aDdotD); |
fc73a202 |
379 | |
dc9ef964 |
380 | return aTime > 0.0f ? aTime : MAXFLOAT; |
fc73a202 |
381 | } |
e2da917a |
382 | |
fc73a202 |
383 | return MAXFLOAT; |
384 | } |
385 | |
386 | // ======================================================================= |
387 | // function : IntersectTriangle |
388 | // purpose : Computes ray-triangle intersection (branchless version) |
389 | // ======================================================================= |
f2474958 |
390 | void IntersectTriangle (in SRay theRay, |
391 | in vec3 thePnt0, |
392 | in vec3 thePnt1, |
393 | in vec3 thePnt2, |
394 | out vec3 theUVT, |
395 | out vec3 theNorm) |
fc73a202 |
396 | { |
f2474958 |
397 | vec3 aToTrg = thePnt0 - theRay.Origin; |
398 | |
fc73a202 |
399 | vec3 aEdge0 = thePnt1 - thePnt0; |
400 | vec3 aEdge1 = thePnt0 - thePnt2; |
e2da917a |
401 | |
fc73a202 |
402 | theNorm = cross (aEdge1, aEdge0); |
403 | |
f2474958 |
404 | vec3 theVect = cross (theRay.Direct, aToTrg); |
e2da917a |
405 | |
f2474958 |
406 | theUVT = vec3 (dot (theNorm, aToTrg), |
407 | dot (theVect, aEdge1), |
408 | dot (theVect, aEdge0)) * (1.f / dot (theNorm, theRay.Direct)); |
fc73a202 |
409 | |
f2474958 |
410 | theUVT.x = any (lessThan (theUVT, ZERO)) || (theUVT.y + theUVT.z) > 1.f ? MAXFLOAT : theUVT.x; |
411 | } |
e2da917a |
412 | |
f2474958 |
413 | #define EMPTY_ROOT ivec4(0) |
e2da917a |
414 | |
f2474958 |
415 | //! Utility structure containing information about |
416 | //! currently traversing sub-tree of scene's BVH. |
417 | struct SSubTree |
418 | { |
419 | //! Transformed ray. |
420 | SRay TrsfRay; |
fc73a202 |
421 | |
f2474958 |
422 | //! Inversed ray direction. |
423 | vec3 Inverse; |
fc73a202 |
424 | |
f2474958 |
425 | //! Parameters of sub-root node. |
426 | ivec4 SubData; |
427 | }; |
84c71f29 |
428 | |
05aa616d |
429 | #define MATERIAL_AMBN(index) (19 * index + 0) |
430 | #define MATERIAL_DIFF(index) (19 * index + 1) |
431 | #define MATERIAL_SPEC(index) (19 * index + 2) |
432 | #define MATERIAL_EMIS(index) (19 * index + 3) |
433 | #define MATERIAL_REFL(index) (19 * index + 4) |
434 | #define MATERIAL_REFR(index) (19 * index + 5) |
435 | #define MATERIAL_TRAN(index) (19 * index + 6) |
436 | #define MATERIAL_TRS1(index) (19 * index + 7) |
437 | #define MATERIAL_TRS2(index) (19 * index + 8) |
438 | #define MATERIAL_TRS3(index) (19 * index + 9) |
47e9c178 |
439 | |
47e9c178 |
440 | #define TRS_OFFSET(treelet) treelet.SubData.x |
441 | #define BVH_OFFSET(treelet) treelet.SubData.y |
442 | #define VRT_OFFSET(treelet) treelet.SubData.z |
443 | #define TRG_OFFSET(treelet) treelet.SubData.w |
444 | |
f2474958 |
445 | //! Identifies the absence of intersection. |
446 | #define INALID_HIT ivec4 (-1) |
447 | |
448 | //! Global stack shared between traversal functions. |
449 | int Stack[STACK_SIZE]; |
450 | |
451 | // ======================================================================= |
452 | // function : pop |
453 | // purpose : |
454 | // ======================================================================= |
455 | int pop (inout int theHead) |
456 | { |
457 | int aData = Stack[theHead]; |
458 | |
459 | int aMask = aData >> 26; |
460 | int aNode = aMask & 0x3; |
461 | |
462 | aMask >>= 2; |
463 | |
464 | if ((aMask & 0x3) == aNode) |
465 | { |
466 | --theHead; |
467 | } |
468 | else |
469 | { |
470 | aMask |= (aMask << 2) & 0x30; |
471 | |
472 | Stack[theHead] = (aData & 0x03FFFFFF) | (aMask << 26); |
473 | } |
474 | |
475 | return (aData & 0x03FFFFFF) + aNode; |
476 | } |
47e9c178 |
477 | |
fc73a202 |
478 | // ======================================================================= |
47e9c178 |
479 | // function : SceneNearestHit |
480 | // purpose : Finds intersection with nearest scene triangle |
fc73a202 |
481 | // ======================================================================= |
47e9c178 |
482 | ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId) |
fc73a202 |
483 | { |
fc73a202 |
484 | ivec4 aTriIndex = INALID_HIT; |
485 | |
47e9c178 |
486 | int aNode = 0; // node to traverse |
487 | int aHead = -1; // pointer of stack |
488 | int aStop = -1; // BVH level switch |
489 | |
490 | SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT); |
491 | |
f2474958 |
492 | for (bool toContinue = true; toContinue; /* none */) |
fc73a202 |
493 | { |
47e9c178 |
494 | ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode); |
fc73a202 |
495 | |
496 | if (aData.x == 0) // if inner node |
497 | { |
47e9c178 |
498 | aData.y += BVH_OFFSET (aSubTree); |
e2da917a |
499 | |
f2474958 |
500 | vec4 aHitTimes = vec4 (MAXFLOAT, |
501 | MAXFLOAT, |
502 | MAXFLOAT, |
503 | MAXFLOAT); |
504 | |
505 | vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse; |
fc73a202 |
506 | |
f2474958 |
507 | vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse; |
508 | vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse; |
509 | vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse; |
510 | vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse; |
511 | vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse; |
512 | vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse; |
513 | vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse; |
514 | vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse; |
e2da917a |
515 | |
f2474958 |
516 | vec3 aTimeMax = max (aNodeMin0, aNodeMax0); |
517 | vec3 aTimeMin = min (aNodeMin0, aNodeMax0); |
fc73a202 |
518 | |
f2474958 |
519 | float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z)); |
520 | float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z)); |
e2da917a |
521 | |
06e06389 |
522 | aHitTimes.x = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT; |
fc73a202 |
523 | |
f2474958 |
524 | aTimeMax = max (aNodeMin1, aNodeMax1); |
525 | aTimeMin = min (aNodeMin1, aNodeMax1); |
fc73a202 |
526 | |
f2474958 |
527 | aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z)); |
528 | aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z)); |
fc73a202 |
529 | |
06e06389 |
530 | aHitTimes.y = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT; |
fc73a202 |
531 | |
f2474958 |
532 | aTimeMax = max (aNodeMin2, aNodeMax2); |
533 | aTimeMin = min (aNodeMin2, aNodeMax2); |
fc73a202 |
534 | |
f2474958 |
535 | aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z)); |
536 | aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z)); |
47e9c178 |
537 | |
06e06389 |
538 | aHitTimes.z = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 1) ? aTimeEnter : MAXFLOAT; |
f2474958 |
539 | |
540 | aTimeMax = max (aNodeMin3, aNodeMax3); |
541 | aTimeMin = min (aNodeMin3, aNodeMax3); |
542 | |
543 | aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z)); |
544 | aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z)); |
545 | |
06e06389 |
546 | aHitTimes.w = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 2) ? aTimeEnter : MAXFLOAT; |
f2474958 |
547 | |
548 | ivec4 aChildren = ivec4 (0, 1, 2, 3); |
549 | |
550 | aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy; |
551 | aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy; |
552 | aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw; |
553 | aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw; |
554 | aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz; |
555 | aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz; |
556 | aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw; |
557 | aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw; |
558 | aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz; |
559 | aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz; |
560 | |
561 | if (aHitTimes.x != MAXFLOAT) |
fc73a202 |
562 | { |
f2474958 |
563 | int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2 |
564 | | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y); |
565 | |
566 | if (aHitTimes.y != MAXFLOAT) |
567 | Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26; |
e2da917a |
568 | |
f2474958 |
569 | aNode = aData.y + aChildren.x; |
fc73a202 |
570 | } |
f2474958 |
571 | else |
fc73a202 |
572 | { |
47e9c178 |
573 | toContinue = (aHead >= 0); |
574 | |
575 | if (aHead == aStop) // go to top-level BVH |
fc73a202 |
576 | { |
47e9c178 |
577 | aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT); |
fc73a202 |
578 | } |
25ef750e |
579 | |
f2474958 |
580 | if (aHead >= 0) |
581 | aNode = pop (aHead); |
fc73a202 |
582 | } |
583 | } |
f2474958 |
584 | else if (aData.x < 0) // leaf node (contains triangles) |
fc73a202 |
585 | { |
586 | vec3 aNormal; |
f2474958 |
587 | vec3 aTimeUV; |
84c71f29 |
588 | |
fc73a202 |
589 | for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx) |
590 | { |
47e9c178 |
591 | ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree)); |
fc73a202 |
592 | |
47e9c178 |
593 | vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz; |
594 | vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz; |
595 | vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz; |
fc73a202 |
596 | |
f2474958 |
597 | IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal); |
e2da917a |
598 | |
f2474958 |
599 | if (aTimeUV.x < theHit.Time) |
fc73a202 |
600 | { |
601 | aTriIndex = aTriangle; |
a89742cf |
602 | |
47e9c178 |
603 | theTrsfId = TRS_OFFSET (aSubTree); |
604 | |
f2474958 |
605 | theHit = SIntersect (aTimeUV.x, aTimeUV.yz, aNormal); |
fc73a202 |
606 | } |
607 | } |
fc73a202 |
608 | |
47e9c178 |
609 | toContinue = (aHead >= 0); |
610 | |
611 | if (aHead == aStop) // go to top-level BVH |
612 | { |
613 | aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT); |
614 | } |
615 | |
f2474958 |
616 | if (aHead >= 0) |
617 | aNode = pop (aHead); |
47e9c178 |
618 | } |
619 | else if (aData.x > 0) // switch node |
620 | { |
621 | aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root |
622 | |
623 | vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0); |
624 | vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1); |
625 | vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2); |
626 | vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3); |
627 | |
628 | aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct, |
629 | aInvTransf0, |
630 | aInvTransf1, |
631 | aInvTransf2); |
632 | |
633 | aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) / |
634 | max (abs (aSubTree.TrsfRay.Direct), SMALL); |
e2da917a |
635 | |
47e9c178 |
636 | aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin, |
637 | aInvTransf0, |
638 | aInvTransf1, |
639 | aInvTransf2, |
640 | aInvTransf3); |
641 | |
642 | aNode = BVH_OFFSET (aSubTree); // go to sub-root node |
643 | |
644 | aStop = aHead; // store current stack pointer |
fc73a202 |
645 | } |
646 | } |
647 | |
648 | return aTriIndex; |
649 | } |
650 | |
651 | // ======================================================================= |
47e9c178 |
652 | // function : SceneAnyHit |
653 | // purpose : Finds intersection with any scene triangle |
fc73a202 |
654 | // ======================================================================= |
47e9c178 |
655 | float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance) |
fc73a202 |
656 | { |
8c820969 |
657 | float aFactor = 1.f; |
fc73a202 |
658 | |
47e9c178 |
659 | int aNode = 0; // node to traverse |
660 | int aHead = -1; // pointer of stack |
661 | int aStop = -1; // BVH level switch |
662 | |
663 | SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT); |
664 | |
f2474958 |
665 | for (bool toContinue = true; toContinue; /* none */) |
fc73a202 |
666 | { |
e2da917a |
667 | ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode); |
fc73a202 |
668 | |
669 | if (aData.x == 0) // if inner node |
670 | { |
47e9c178 |
671 | aData.y += BVH_OFFSET (aSubTree); |
e2da917a |
672 | |
f2474958 |
673 | vec4 aHitTimes = vec4 (MAXFLOAT, |
674 | MAXFLOAT, |
675 | MAXFLOAT, |
676 | MAXFLOAT); |
677 | |
678 | vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse; |
fc73a202 |
679 | |
f2474958 |
680 | vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse; |
681 | vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse; |
682 | vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse; |
683 | vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse; |
684 | vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse; |
685 | vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse; |
686 | vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse; |
687 | vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse; |
fc73a202 |
688 | |
f2474958 |
689 | vec3 aTimeMax = max (aNodeMin0, aNodeMax0); |
690 | vec3 aTimeMin = min (aNodeMin0, aNodeMax0); |
fc73a202 |
691 | |
f2474958 |
692 | float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z)); |
693 | float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z)); |
e2da917a |
694 | |
06e06389 |
695 | aHitTimes.x = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT; |
fc73a202 |
696 | |
f2474958 |
697 | aTimeMax = max (aNodeMin1, aNodeMax1); |
698 | aTimeMin = min (aNodeMin1, aNodeMax1); |
fc73a202 |
699 | |
f2474958 |
700 | aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z)); |
701 | aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z)); |
fc73a202 |
702 | |
06e06389 |
703 | aHitTimes.y = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT; |
fc73a202 |
704 | |
f2474958 |
705 | aTimeMax = max (aNodeMin2, aNodeMax2); |
706 | aTimeMin = min (aNodeMin2, aNodeMax2); |
fc73a202 |
707 | |
f2474958 |
708 | aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z)); |
709 | aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z)); |
47e9c178 |
710 | |
06e06389 |
711 | aHitTimes.z = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 1) ? aTimeEnter : MAXFLOAT; |
f2474958 |
712 | |
713 | aTimeMax = max (aNodeMin3, aNodeMax3); |
714 | aTimeMin = min (aNodeMin3, aNodeMax3); |
715 | |
716 | aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z)); |
717 | aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z)); |
718 | |
06e06389 |
719 | aHitTimes.w = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 2) ? aTimeEnter : MAXFLOAT; |
f2474958 |
720 | |
721 | ivec4 aChildren = ivec4 (0, 1, 2, 3); |
722 | |
723 | aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy; |
724 | aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy; |
725 | aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw; |
726 | aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw; |
727 | aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz; |
728 | aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz; |
729 | aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw; |
730 | aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw; |
731 | aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz; |
732 | aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz; |
733 | |
734 | if (aHitTimes.x != MAXFLOAT) |
fc73a202 |
735 | { |
f2474958 |
736 | int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2 |
737 | | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y); |
fc73a202 |
738 | |
f2474958 |
739 | if (aHitTimes.y != MAXFLOAT) |
740 | Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26; |
741 | |
742 | aNode = aData.y + aChildren.x; |
fc73a202 |
743 | } |
f2474958 |
744 | else |
fc73a202 |
745 | { |
47e9c178 |
746 | toContinue = (aHead >= 0); |
747 | |
748 | if (aHead == aStop) // go to top-level BVH |
fc73a202 |
749 | { |
47e9c178 |
750 | aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT); |
fc73a202 |
751 | } |
fc73a202 |
752 | |
f2474958 |
753 | if (aHead >= 0) |
754 | aNode = pop (aHead); |
fc73a202 |
755 | } |
756 | } |
47e9c178 |
757 | else if (aData.x < 0) // leaf node |
fc73a202 |
758 | { |
759 | vec3 aNormal; |
f2474958 |
760 | vec3 aTimeUV; |
25ef750e |
761 | |
fc73a202 |
762 | for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx) |
763 | { |
47e9c178 |
764 | ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree)); |
fc73a202 |
765 | |
47e9c178 |
766 | vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz; |
767 | vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz; |
768 | vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz; |
fc73a202 |
769 | |
f2474958 |
770 | IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal); |
bc8c79bb |
771 | |
772 | #ifdef TRANSPARENT_SHADOWS |
f2474958 |
773 | if (aTimeUV.x < theDistance) |
bc8c79bb |
774 | { |
8c820969 |
775 | aFactor *= 1.f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x; |
bc8c79bb |
776 | } |
777 | #else |
f2474958 |
778 | if (aTimeUV.x < theDistance) |
8c820969 |
779 | { |
780 | aFactor = 0.f; |
781 | } |
bc8c79bb |
782 | #endif |
fc73a202 |
783 | } |
25ef750e |
784 | |
3a9b5dc8 |
785 | toContinue = (aHead >= 0) && (aFactor > 0.1f); |
25ef750e |
786 | |
47e9c178 |
787 | if (aHead == aStop) // go to top-level BVH |
fc73a202 |
788 | { |
47e9c178 |
789 | aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT); |
fc73a202 |
790 | } |
e2da917a |
791 | |
f2474958 |
792 | if (aHead >= 0) |
793 | aNode = pop (aHead); |
fc73a202 |
794 | } |
47e9c178 |
795 | else if (aData.x > 0) // switch node |
fc73a202 |
796 | { |
47e9c178 |
797 | aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root |
bc8c79bb |
798 | |
47e9c178 |
799 | vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0); |
800 | vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1); |
801 | vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2); |
802 | vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3); |
fc73a202 |
803 | |
47e9c178 |
804 | aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct, |
805 | aInvTransf0, |
806 | aInvTransf1, |
807 | aInvTransf2); |
bc8c79bb |
808 | |
47e9c178 |
809 | aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin, |
810 | aInvTransf0, |
811 | aInvTransf1, |
812 | aInvTransf2, |
813 | aInvTransf3); |
fc73a202 |
814 | |
47e9c178 |
815 | aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) / max (abs (aSubTree.TrsfRay.Direct), SMALL); |
bc8c79bb |
816 | |
47e9c178 |
817 | aNode = BVH_OFFSET (aSubTree); // go to sub-root node |
84c71f29 |
818 | |
47e9c178 |
819 | aStop = aHead; // store current stack pointer |
fc73a202 |
820 | } |
821 | } |
25ef750e |
822 | |
bc8c79bb |
823 | return aFactor; |
fc73a202 |
824 | } |
825 | |
826 | #define PI 3.1415926f |
827 | |
828 | // ======================================================================= |
829 | // function : Latlong |
830 | // purpose : Converts world direction to environment texture coordinates |
831 | // ======================================================================= |
832 | vec2 Latlong (in vec3 thePoint, in float theRadius) |
833 | { |
834 | float aPsi = acos (-thePoint.z / theRadius); |
25ef750e |
835 | |
fc73a202 |
836 | float aPhi = atan (thePoint.y, thePoint.x) + PI; |
25ef750e |
837 | |
fc73a202 |
838 | return vec2 (aPhi * 0.1591549f, |
839 | aPsi * 0.3183098f); |
840 | } |
841 | |
842 | // ======================================================================= |
843 | // function : SmoothNormal |
844 | // purpose : Interpolates normal across the triangle |
845 | // ======================================================================= |
846 | vec3 SmoothNormal (in vec2 theUV, in ivec4 theTriangle) |
847 | { |
848 | vec3 aNormal0 = texelFetch (uGeometryNormalTexture, theTriangle.x).xyz; |
849 | vec3 aNormal1 = texelFetch (uGeometryNormalTexture, theTriangle.y).xyz; |
850 | vec3 aNormal2 = texelFetch (uGeometryNormalTexture, theTriangle.z).xyz; |
25ef750e |
851 | |
fc73a202 |
852 | return normalize (aNormal1 * theUV.x + |
853 | aNormal2 * theUV.y + |
dc9ef964 |
854 | aNormal0 * (1.0f - theUV.x - theUV.y)); |
855 | } |
856 | |
be86ba90 |
857 | #define POLYGON_OFFSET_UNIT 0.f |
858 | #define POLYGON_OFFSET_FACTOR 1.f |
859 | #define POLYGON_OFFSET_SCALE 0.006f |
860 | |
861 | // ======================================================================= |
862 | // function : PolygonOffset |
863 | // purpose : Computes OpenGL polygon offset |
864 | // ======================================================================= |
865 | float PolygonOffset (in vec3 theNormal, in vec3 thePoint) |
866 | { |
867 | vec4 aProjectedNorm = vec4 (theNormal, -dot (theNormal, thePoint)) * uUnviewMat; |
868 | |
869 | float aPolygonOffset = POLYGON_OFFSET_UNIT; |
870 | |
871 | if (aProjectedNorm.z * aProjectedNorm.z > 1e-20f) |
872 | { |
873 | aProjectedNorm.xy *= 1.f / aProjectedNorm.z; |
874 | |
875 | aPolygonOffset += POLYGON_OFFSET_FACTOR * max (abs (aProjectedNorm.x), |
876 | abs (aProjectedNorm.y)); |
877 | } |
878 | |
879 | return aPolygonOffset; |
880 | } |
881 | |
25ef750e |
882 | // ======================================================================= |
883 | // function : SmoothUV |
884 | // purpose : Interpolates UV coordinates across the triangle |
885 | // ======================================================================= |
886 | #ifdef USE_TEXTURES |
887 | vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle) |
888 | { |
889 | vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st; |
890 | vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st; |
891 | vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st; |
892 | |
893 | return aTexCrd1 * theUV.x + |
894 | aTexCrd2 * theUV.y + |
895 | aTexCrd0 * (1.0f - theUV.x - theUV.y); |
896 | } |
897 | #endif |
898 | |
189f85a3 |
899 | // ======================================================================= |
900 | // function : FetchEnvironment |
901 | // purpose : |
902 | // ======================================================================= |
903 | vec4 FetchEnvironment (in vec2 theTexCoord) |
904 | { |
6e728f3b |
905 | return uSphereMapEnabled == 0 ? |
906 | vec4 (0.f, 0.f, 0.f, 1.f) : textureLod (uEnvironmentMapTexture, theTexCoord, 0.f); |
189f85a3 |
907 | } |
908 | |
dc9ef964 |
909 | // ======================================================================= |
910 | // function : Refract |
bc8c79bb |
911 | // purpose : Computes refraction ray (also handles TIR) |
dc9ef964 |
912 | // ======================================================================= |
189f85a3 |
913 | #ifndef PATH_TRACING |
dc9ef964 |
914 | vec3 Refract (in vec3 theInput, |
915 | in vec3 theNormal, |
916 | in float theRefractIndex, |
917 | in float theInvRefractIndex) |
918 | { |
25ef750e |
919 | float aNdotI = dot (theInput, theNormal); |
920 | |
dc9ef964 |
921 | float anIndex = aNdotI < 0.0f |
922 | ? theInvRefractIndex |
923 | : theRefractIndex; |
25ef750e |
924 | |
dc9ef964 |
925 | float aSquare = anIndex * anIndex * (1.0f - aNdotI * aNdotI); |
25ef750e |
926 | |
dc9ef964 |
927 | if (aSquare > 1.0f) |
928 | { |
929 | return reflect (theInput, theNormal); |
930 | } |
25ef750e |
931 | |
dc9ef964 |
932 | float aNdotT = sqrt (1.0f - aSquare); |
25ef750e |
933 | |
dc9ef964 |
934 | return normalize (anIndex * theInput - |
bc8c79bb |
935 | (anIndex * aNdotI + (aNdotI < 0.0f ? aNdotT : -aNdotT)) * theNormal); |
fc73a202 |
936 | } |
189f85a3 |
937 | #endif |
fc73a202 |
938 | |
a89742cf |
939 | #define MIN_SLOPE 0.0001f |
940 | #define EPS_SCALE 8.0000f |
941 | |
bc8c79bb |
942 | #define THRESHOLD vec3 (0.1f) |
fc73a202 |
943 | |
1804bb99 |
944 | #define INVALID_BOUNCES 1000 |
945 | |
fc73a202 |
946 | #define LIGHT_POS(index) (2 * index + 1) |
947 | #define LIGHT_PWR(index) (2 * index + 0) |
948 | |
949 | // ======================================================================= |
950 | // function : Radiance |
25ef750e |
951 | // purpose : Computes color along the given ray |
fc73a202 |
952 | // ======================================================================= |
189f85a3 |
953 | #ifndef PATH_TRACING |
fc73a202 |
954 | vec4 Radiance (in SRay theRay, in vec3 theInverse) |
955 | { |
dc9ef964 |
956 | vec3 aResult = vec3 (0.0f); |
957 | vec4 aWeight = vec4 (1.0f); |
84c71f29 |
958 | |
8c820969 |
959 | int aTrsfId; |
a89742cf |
960 | |
1d865689 |
961 | float aRaytraceDepth = MAXFLOAT; |
a89742cf |
962 | |
25ef750e |
963 | for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth) |
fc73a202 |
964 | { |
965 | SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO); |
a89742cf |
966 | |
8c820969 |
967 | ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId); |
fc73a202 |
968 | |
969 | if (aTriIndex.x == -1) |
970 | { |
189f85a3 |
971 | vec4 aColor = vec4 (0.0); |
25ef750e |
972 | |
189f85a3 |
973 | if (bool(uSphereMapForBack) || aWeight.w == 0.0f /* reflection */) |
fc73a202 |
974 | { |
975 | float aTime = IntersectSphere (theRay, uSceneRadius); |
25ef750e |
976 | |
189f85a3 |
977 | aColor = FetchEnvironment (Latlong ( |
978 | theRay.Direct * aTime + theRay.Origin, uSceneRadius)); |
979 | } |
980 | else |
981 | { |
3a9b5dc8 |
982 | aColor = BackgroundColor(); |
fc73a202 |
983 | } |
25ef750e |
984 | |
8c820969 |
985 | aResult += aWeight.xyz * aColor.xyz; aWeight.w *= aColor.w; |
986 | |
987 | break; // terminate path |
fc73a202 |
988 | } |
a89742cf |
989 | |
8c820969 |
990 | vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz; |
991 | vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz; |
992 | vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz; |
cf537aac |
993 | |
994 | aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal), |
995 | dot (aInvTransf1, aHit.Normal), |
996 | dot (aInvTransf2, aHit.Normal))); |
1804bb99 |
997 | |
1804bb99 |
998 | theRay.Origin += theRay.Direct * aHit.Time; // intersection point |
999 | |
3a9b5dc8 |
1000 | // Evaluate depth on first hit |
1d865689 |
1001 | if (aDepth == 0) |
1002 | { |
be86ba90 |
1003 | vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f); |
1d865689 |
1004 | |
be86ba90 |
1005 | float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin); |
1006 | aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f; |
1d865689 |
1007 | } |
1008 | |
1804bb99 |
1009 | vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex); |
1010 | |
1011 | aNormal = normalize (vec3 (dot (aInvTransf0, aNormal), |
1012 | dot (aInvTransf1, aNormal), |
1013 | dot (aInvTransf2, aNormal))); |
25ef750e |
1014 | |
dc9ef964 |
1015 | vec3 aAmbient = texelFetch ( |
1016 | uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb; |
25ef750e |
1017 | vec4 aDiffuse = texelFetch ( |
1018 | uRaytraceMaterialTexture, MATERIAL_DIFF (aTriIndex.w)); |
dc9ef964 |
1019 | vec4 aSpecular = texelFetch ( |
1020 | uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w)); |
1021 | vec4 aOpacity = texelFetch ( |
1022 | uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w)); |
25ef750e |
1023 | |
1024 | #ifdef USE_TEXTURES |
1025 | if (aDiffuse.w >= 0.f) |
1026 | { |
1027 | vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f); |
1028 | |
1029 | vec4 aTrsfRow1 = texelFetch ( |
1030 | uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w)); |
1031 | vec4 aTrsfRow2 = texelFetch ( |
1032 | uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w)); |
1033 | |
1034 | aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord), |
1035 | dot (aTrsfRow2, aTexCoord)); |
1036 | |
f411f94f |
1037 | vec4 aTexColor = textureLod ( |
1038 | sampler2D (uTextureSamplers[int(aDiffuse.w)]), aTexCoord.st, 0.f); |
25ef750e |
1039 | |
f411f94f |
1040 | aDiffuse.rgb *= aTexColor.rgb; |
1041 | aAmbient.rgb *= aTexColor.rgb; |
1042 | |
1043 | // keep refractive index untouched (Z component) |
1044 | aOpacity.xy = vec2 (aTexColor.w * aOpacity.x, 1.0f - aTexColor.w * aOpacity.x); |
25ef750e |
1045 | } |
1046 | #endif |
84c71f29 |
1047 | |
1804bb99 |
1048 | vec3 aEmission = texelFetch ( |
1049 | uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb; |
84c71f29 |
1050 | |
1804bb99 |
1051 | float aGeomFactor = dot (aNormal, theRay.Direct); |
1052 | |
1053 | aResult.xyz += aWeight.xyz * aOpacity.x * ( |
1054 | uGlobalAmbient.xyz * aAmbient * max (abs (aGeomFactor), 0.5f) + aEmission); |
25ef750e |
1055 | |
1804bb99 |
1056 | vec3 aSidedNormal = mix (aNormal, -aNormal, step (0.0f, aGeomFactor)); |
a89742cf |
1057 | |
fc73a202 |
1058 | for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx) |
1059 | { |
1060 | vec4 aLight = texelFetch ( |
1061 | uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx)); |
e2da917a |
1062 | |
fc73a202 |
1063 | float aDistance = MAXFLOAT; |
e2da917a |
1064 | |
dc9ef964 |
1065 | if (aLight.w != 0.0f) // point light source |
fc73a202 |
1066 | { |
1804bb99 |
1067 | aDistance = length (aLight.xyz -= theRay.Origin); |
e2da917a |
1068 | |
dc9ef964 |
1069 | aLight.xyz *= 1.0f / aDistance; |
fc73a202 |
1070 | } |
1071 | |
1804bb99 |
1072 | float aLdotN = dot (aLight.xyz, aSidedNormal); |
e2da917a |
1073 | |
1804bb99 |
1074 | if (aLdotN > 0.0f) // first check if light source is important |
fc73a202 |
1075 | { |
1804bb99 |
1076 | float aVisibility = 1.0f; |
25ef750e |
1077 | |
189f85a3 |
1078 | if (bool(uShadowsEnabled)) |
1804bb99 |
1079 | { |
1080 | SRay aShadow = SRay (theRay.Origin, aLight.xyz); |
e2da917a |
1081 | |
1804bb99 |
1082 | aShadow.Origin += uSceneEpsilon * (aLight.xyz + |
1083 | mix (-aHit.Normal, aHit.Normal, step (0.0f, dot (aHit.Normal, aLight.xyz)))); |
25ef750e |
1084 | |
1804bb99 |
1085 | vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL); |
25ef750e |
1086 | |
1804bb99 |
1087 | aVisibility = SceneAnyHit ( |
1088 | aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance); |
1089 | } |
25ef750e |
1090 | |
1804bb99 |
1091 | if (aVisibility > 0.0f) |
fc73a202 |
1092 | { |
6e728f3b |
1093 | vec3 aIntensity = min (UNIT, vec3 (texelFetch ( |
1094 | uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)))); |
1804bb99 |
1095 | |
1096 | float aRdotV = dot (reflect (aLight.xyz, aSidedNormal), theRay.Direct); |
25ef750e |
1097 | |
bc8c79bb |
1098 | aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity * |
1804bb99 |
1099 | (aDiffuse.xyz * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w)); |
fc73a202 |
1100 | } |
1101 | } |
1102 | } |
0e330c8c |
1103 | |
dc9ef964 |
1104 | if (aOpacity.x != 1.0f) |
fc73a202 |
1105 | { |
1106 | aWeight *= aOpacity.y; |
a89742cf |
1107 | |
bc8c79bb |
1108 | if (aOpacity.z != 1.0f) |
1109 | { |
1110 | theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w); |
a89742cf |
1111 | } |
fc73a202 |
1112 | } |
1113 | else |
1114 | { |
189f85a3 |
1115 | aWeight *= bool(uReflectEnabled) ? |
dc9ef964 |
1116 | texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f); |
25ef750e |
1117 | |
1804bb99 |
1118 | vec3 aReflect = reflect (theRay.Direct, aNormal); |
25ef750e |
1119 | |
1804bb99 |
1120 | if (dot (aReflect, aHit.Normal) * dot (theRay.Direct, aHit.Normal) > 0.0f) |
fc73a202 |
1121 | { |
1804bb99 |
1122 | aReflect = reflect (theRay.Direct, aHit.Normal); |
fc73a202 |
1123 | } |
1124 | |
1804bb99 |
1125 | theRay.Direct = aReflect; |
fc73a202 |
1126 | } |
25ef750e |
1127 | |
fc73a202 |
1128 | if (all (lessThanEqual (aWeight.xyz, THRESHOLD))) |
1129 | { |
1804bb99 |
1130 | aDepth = INVALID_BOUNCES; |
1131 | } |
1132 | else if (aOpacity.x == 1.0f || aOpacity.z != 1.0f) // if no simple transparency |
1133 | { |
1134 | theRay.Origin += aHit.Normal * mix ( |
1135 | -uSceneEpsilon, uSceneEpsilon, step (0.0f, dot (aHit.Normal, theRay.Direct))); |
1136 | |
1137 | theInverse = 1.0f / max (abs (theRay.Direct), SMALL); |
1138 | |
1139 | theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct)); |
fc73a202 |
1140 | } |
25ef750e |
1141 | |
1804bb99 |
1142 | theRay.Origin += theRay.Direct * uSceneEpsilon; |
fc73a202 |
1143 | } |
1144 | |
1d865689 |
1145 | gl_FragDepth = aRaytraceDepth; |
1146 | |
fc73a202 |
1147 | return vec4 (aResult.x, |
1148 | aResult.y, |
1149 | aResult.z, |
1150 | aWeight.w); |
1151 | } |
189f85a3 |
1152 | #endif |