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