| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- /*
- * Copyright (C) 2020, Inria
- * GRAPHDECO research group, https://team.inria.fr/graphdeco
- * All rights reserved.
- *
- * This software is free for non-commercial, research and evaluation use
- * under the terms of the LICENSE.md file.
- *
- * For inquiries contact sibr@inria.fr and/or George.Drettakis@inria.fr
- */
- #version 420
- #define SHADOWPOWER_METHOD_ESTIM 1
- #define SHADOWPOWER_METHOD_3D 2
- #define SHADOWPOWER_METHOD_ESTIM_NONLINEAR 3
- #define SHADOWPOWER_METHOD SHADOWPOWER_METHOD_ESTIM
- layout(binding = 0) uniform sampler2D tex;
- layout(binding = 1) uniform sampler2D firstPassRT; /// \todo TODO: use ping pong buffering to update it with the last add
- uniform mat4 in_inv_proj;
- uniform vec2 in_image_size;
- layout(location= 0) out vec4 out_color;
- in vec2 tex_coord;
- //const float blurSize = 1.0 / 1000.0;
- const float constFgAdditionalOffset = -0.02; // note it should not be linear because of near/far+proj
- const float constSmoothShadowDistAtten = 8.0;
- vec3 unproject(vec3 xyd, mat4 inv_proj) {
- vec4 pxl = vec4(xyd,1.0)*vec4(2.0)-vec4(1.0); // [0,1] -> [-1,1]
- vec4 obj = inv_proj * pxl; // unproject
- return (obj.xyz/obj.w);
- }
- float smoothShadowDist( float dist01 )
- {
- float v = 1.0 - max(0.0, min(1.0, dist01) );
- return exp(log(v)*constSmoothShadowDistAtten);
- }
- void main(void) {
- //===========================================================================//
- // //
- // Adding Shadow //
- // //
- //===========================================================================//
- {
- const float scanSizeX = (1.0 / in_image_size.x)*4.0; /// \todo TODO: should be split into H and W and use image size
- const float scanSizeY = (1.0 / in_image_size.y)*4.0; /// \todo TODO: should be split into H and W and use image size
-
- vec4 bg = texture(firstPassRT,tex_coord); // background color
- vec4 fg = texture(tex,tex_coord); // foreground color (object to add)
- float bgDepth = bg.a;
- float outDepth = bgDepth;
- float fgDepth = fg.a+constFgAdditionalOffset;
- // By default set output values using bg
- out_color = vec4(bg.rgb, 1.0);
- //out_color = vec4(bg.a, 0.0, 0.0, 1.0);
- //gl_FragDepth = bgDepth;
-
- bool fgIsEmpty = (fg.r == 0 && fg.g == 0 && fg.b == 0);
- /// gl_FragDepth = 0;
-
- if (fgIsEmpty == false)
- {
- out_color = vec4(fg.rgb, (bgDepth <= fgDepth)? 0.0 : 1.0);
- //fgDepth = bgDepth;
- outDepth = (bgDepth <= fgDepth)? bgDepth : fgDepth;
- //gl_FragDepth = fgDepth;
- /// out_color = vec4(fg.a, 0.0, 0.0, 1.0);
- }
- else
- {
- // Scan for non-empty pixels for determining the power
- // of the shadow.
- // 'non-empty' pixels are FULL black pixels
-
- const int scanItCount = 8;
- const int maxScanablePixels = (scanItCount*2 + 1)*(scanItCount*2 + 1);
- const float maxAxisX = (scanItCount*2 + 1)*scanSizeX;
- const float maxAxisY = (scanItCount*2 + 1)*scanSizeY;
- const float maxScanDist = maxAxisX*maxAxisX + maxAxisY*maxAxisY;
-
- float nearestDist = maxScanDist*2.0;//maxScanDist + 1.0;
- float nearestXs = 1.0;
- float nearestYs = 1.0;
- float nearestDepth = 0.0;
- float averageBgDepth = 0.0;
- float nonEmptyPixelFound = 0;
- for (int x = -scanItCount; x <= scanItCount; x++)
- {
- for (int y = -scanItCount; y <= scanItCount; y++)
- {
- float xs = x*scanSizeX;
- float ys = y*scanSizeY;
- float dist = (xs*xs + ys*ys);
- vec4 color = texture(tex, vec2(tex_coord.x+xs, tex_coord.y+ys));
- float sampleDepth = color.a+constFgAdditionalOffset;
-
- averageBgDepth += sampleDepth;
-
- if ( (color.r == 0 && color.g == 0 && color.b == 0) == false
- //// [A] this one will cause you trouble with object in front of your shadow caster
- // )
- //// [B] this one will prevent you from casting shadow in front of your object
- //// but visually, you can make it fly a bit and it look like the under is in front
- && sampleDepth <= bgDepth )
- //// [C] this one is the best in fidelity but requires a call to texture(...)
- // && sampleDepth <= texture(firstPassRT, vec2(tex_coord.x+xs, tex_coord.y+ys)).a)
- {
- if (dist < nearestDist)
- {
- nearestXs = xs;
- nearestYs = ys;
- // nearestDist = dist;
- // nearestDepth = sampleDepth;
- }
-
- //nearestXs = min(xs, nearestXs);
- //nearestYs = min(ys, nearestYs); // note that stored nearestXs/Ys might stores an unexisting coordinate pair
- nearestDist = min(nearestDist, dist);
- nearestDepth += sampleDepth;//max(nearestDepth, sampleDepth);
- ++nonEmptyPixelFound;
-
- averageBgDepth -= sampleDepth; // cancel this in this case
- }
- }
- }
- nearestDepth = nearestDepth/float(nonEmptyPixelFound);
- averageBgDepth = averageBgDepth/float(maxScanablePixels-nonEmptyPixelFound);
-
- //if (nearestDist > 0)
- {
-
- // Compute the shadow power
- float shadowPower = 1.0;
-
- float ratioNonEmptyPixelFound = float(nonEmptyPixelFound) / float(maxScanablePixels);
- // influence of the caster size
- shadowPower *= smoothstep(0.0, 0.5, ratioNonEmptyPixelFound);
-
- //if (nonEmptyPixelFound < 100)
- // shadowPower = 0.0;
-
- //shadowPower *= max(0.0, min(1.0, nonEmptyPixelFound/minPixelCaster ));
-
- // Dev Note for improving things
- // There are two way to implement the influence of the shadow caster/receiver distance.
- // [3d solution]
- // - one is to unproject both points and measure their distance in 3d world unit
- // [estim solution]
- // - another one is roughly estimate the effect
- #if SHADOWPOWER_METHOD == SHADOWPOWER_METHOD_ESTIM_NONLINEAR
- // [estim solution]
- // influence of the distance to the object that cast this shadow (slightly improve but not enough)
- //shadowPower *= smoothShadowDist(nearestDist/maxScanDist);
- // influence of the depth distance
- const float maxDiffDepth = 0.04;//0.15; // because it's nonlinear, it will react differently depending on Z (and your dataset clipping planes's near/far)
- float diffDepth = bgDepth-nearestDepth;
- diffDepth = diffDepth / maxDiffDepth;
- float depthFactor = clamp(diffDepth, 0.0, 1.0);
- shadowPower *= (1.0 - depthFactor);
- #endif
-
- #if SHADOWPOWER_METHOD == SHADOWPOWER_METHOD_ESTIM
- // [estim solution]
- // influence of the distance to the object that cast this shadow (slightly improve but not enough)
- //shadowPower *= smoothShadowDist(nearestDist/maxScanDist);
- // influence of the depth distance
- const float maxDist = 0.4; // in world unit
- vec3 bg2dPos = vec3(tex_coord.xy, bgDepth);
- vec3 bg3dPos = unproject(bg2dPos, in_inv_proj);
- vec3 caster2dPos = vec3(vec2(tex_coord.x+nearestXs, tex_coord.y+nearestYs), nearestDepth);
- vec3 caster3dPos = unproject(caster2dPos, in_inv_proj);
- float line = abs(caster3dPos.z-bg3dPos.z);
- float factorDist = 1.0 - max(0.0, min(1.0, line/maxDist) );
- shadowPower *= factorDist;
- #endif
-
- #if SHADOWPOWER_METHOD == SHADOWPOWER_METHOD_3D
- // [3d solution]
- // influence of the shadow receiver distance
- const float maxDist = 0.25; // in world unit
- const float maxDistSqr = maxDist*maxDist;
- vec3 bg2dPos = vec3(tex_coord.xy, bgDepth);
- vec3 bg3dPos = unproject(bg2dPos, in_inv_proj);
- vec3 caster2dPos = vec3(vec2(tex_coord.x+nearestXs, tex_coord.y+nearestYs), nearestDepth);
- vec3 caster3dPos = unproject(caster2dPos, in_inv_proj);
- vec3 line = caster3dPos-bg3dPos;
- float distSqr = line.x*line.x + line.y*line.y + line.z*line.z;
- float factorDist = 1.0 - max(0.0, min(1.0, distSqr/maxDistSqr) );
- shadowPower *= factorDist;
- #endif
-
-
-
- out_color = vec4(0, 0, 0, shadowPower / 1.5);
-
- // //out_color = vec4(fgZ/10.0, 0, 0, 1.0);
- // float nearPlane = 3.23569;
- // float farPlane = 17.1543;
- // //bgZ = (bg2dPos.z * bg2dPos.w - nearPlane) / (farPlane - nearPlane);
- // out_color = vec4(bg2dPos.z/farPlane, 0, 0, 1.0);
- //out_color = vec4(bgDepth, 0, 0, 1.0);
- //gl_FragDepth = nearestDepth;
-
-
- //gl_FragDepth = bgDepth + constFgAdditionalOffset - 1;
- float newDepth = bgDepth;// + constFgAdditionalOffset;
- outDepth = (newDepth <= bgDepth)? newDepth : bgDepth;
- }
-
- // if (nearestDist < 1.0)
- // {
- // out_color = vec4(nearestDepth, 0.0, 0.0, 1.0);
- // gl_FragDepth = 0;
- // }
- }
-
- // Simulate BLEND function (GL_ONE_MINUS_SRC_ALPHA)
- //out_color = vec4(bg.xyz + out_color.xyz/out_color.a, gl_FragDepth);
- out_color = vec4(bg.xyz*(1.0 - out_color.a) + out_color.xyz*out_color.a, outDepth);
- //gl_FragDepth = outDepth;
- //out_color = bg;
- }
- }
|