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