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