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