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