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