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