]> git.lizzy.rs Git - minetest.git/commitdiff
Improve shadow rendering with non-default camera FOV (#11385)
authorx2048 <codeforsmile@gmail.com>
Sun, 11 Jul 2021 15:15:19 +0000 (17:15 +0200)
committerGitHub <noreply@github.com>
Sun, 11 Jul 2021 15:15:19 +0000 (08:15 -0700)
* Adjust minimum filter radius for perspective

* Expand shadow frustum when camera FOV changes, reuse FOV distance adjustment from numeric.cpp

* Read shadow_soft_radius setting as float

* Use adaptive filter radius to accomodate for PSM distortion

* Adjust filter radius for texture resolution

client/shaders/nodes_shader/opengl_fragment.glsl
src/client/shader.cpp
src/client/shadows/dynamicshadows.cpp
src/util/numeric.cpp

index 43a8b1f25a48c485ee0b429f1fc6d71e650cba5d..9f8a21d09127802f2808141d69c6dd04ddcefd13 100644 (file)
@@ -181,9 +181,14 @@ float getDeltaPerspectiveFactor(float l)
 
 float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
 {
+       float baseLength = getBaseLength(smTexCoord);
+       float perspectiveFactor;
+
        // Return fast if sharp shadows are requested
-       if (SOFTSHADOWRADIUS <= 1.0)
-               return SOFTSHADOWRADIUS;
+       if (SOFTSHADOWRADIUS <= 1.0) {
+               perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
+               return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
+       }
 
        vec2 clampedpos;
        float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5);
@@ -192,8 +197,6 @@ float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDist
        float pointDepth;
        float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
 
-       float baseLength = getBaseLength(smTexCoord);
-       float perspectiveFactor;
        float bound = clamp(PCFBOUND * (1 - baseLength), 0.5, PCFBOUND);
        int n = 0;
 
@@ -211,9 +214,10 @@ float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDist
        }
 
        depth = depth / n;
-
        depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001;
-       return max(0.5, depth * maxRadius);
+
+       perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
+       return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius);
 }
 
 #ifdef POISSON_FILTER
index 355366bd388e0528f9e108881d1f92f541724d3e..0b35c37afb134af6ac0c2506e845cab3dc097d7e 100644 (file)
@@ -740,7 +740,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
                s32 shadow_filter = g_settings->getS32("shadow_filters");
                shaders_header << "#define SHADOW_FILTER " << shadow_filter << "\n";
 
-               float shadow_soft_radius = g_settings->getS32("shadow_soft_radius");
+               float shadow_soft_radius = g_settings->getFloat("shadow_soft_radius");
                if (shadow_soft_radius < 1.0f)
                        shadow_soft_radius = 1.0f;
                shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n";
index 775cdebcec17cc94473214113c94d0f15df08e1c..17b711a61a9be881e006fac143512d9ccae43770 100644 (file)
@@ -33,29 +33,34 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
        v3f newCenter;
        v3f look = cam->getDirection();
 
+       // camera view tangents
+       float tanFovY = tanf(cam->getFovY() * 0.5f);
+       float tanFovX = tanf(cam->getFovX() * 0.5f);
+
+       // adjusted frustum boundaries
+       float sfNear = shadow_frustum.zNear;
+       float sfFar = adjustDist(shadow_frustum.zFar, cam->getFovY());
+
+       // adjusted camera positions
        v3f camPos2 = cam->getPosition();
        v3f camPos = v3f(camPos2.X - cam->getOffset().X * BS,
                        camPos2.Y - cam->getOffset().Y * BS,
                        camPos2.Z - cam->getOffset().Z * BS);
-       camPos += look * shadow_frustum.zNear;
-       camPos2 += look * shadow_frustum.zNear;
-       float end = shadow_frustum.zNear + shadow_frustum.zFar;
-       newCenter = camPos + look * (shadow_frustum.zNear + 0.05f * end);
-       v3f world_center = camPos2 + look * (shadow_frustum.zNear + 0.05f * end);
-       // Create a vector to the frustum far corner
-       // @Liso: move all vars we can outside the loop.
-       float tanFovY = tanf(cam->getFovY() * 0.5f);
-       float tanFovX = tanf(cam->getFovX() * 0.5f);
+       camPos += look * sfNear;
+       camPos2 += look * sfNear;
 
-       const v3f &viewUp = cam->getCameraNode()->getUpVector();
-       // viewUp.normalize();
+       // center point of light frustum
+       float end = sfNear + sfFar;
+       newCenter = camPos + look * (sfNear + 0.05f * end);
+       v3f world_center = camPos2 + look * (sfNear + 0.05f * end);
 
+       // Create a vector to the frustum far corner
+       const v3f &viewUp = cam->getCameraNode()->getUpVector();
        v3f viewRight = look.crossProduct(viewUp);
-       // viewRight.normalize();
 
        v3f farCorner = look + viewRight * tanFovX + viewUp * tanFovY;
        // Compute the frustumBoundingSphere radius
-       v3f boundVec = (camPos + farCorner * shadow_frustum.zFar) - newCenter;
+       v3f boundVec = (camPos + farCorner * sfFar) - newCenter;
        radius = boundVec.getLength() * 2.0f;
        // boundVec.getLength();
        float vvolume = radius * 2.0f;
index 99e4cfb5ce24d5804b4342058aa6bd8fecca272a..702ddce951b2a1f32679f1de323f6643db4db342 100644 (file)
@@ -159,7 +159,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
        return true;
 }
 
-s16 adjustDist(s16 dist, float zoom_fov)
+inline float adjustDist(float dist, float zoom_fov)
 {
        // 1.775 ~= 72 * PI / 180 * 1.4, the default FOV on the client.
        // The heuristic threshold for zooming is half of that.
@@ -167,8 +167,13 @@ s16 adjustDist(s16 dist, float zoom_fov)
        if (zoom_fov < 0.001f || zoom_fov > threshold_fov)
                return dist;
 
-       return std::round(dist * std::cbrt((1.0f - std::cos(threshold_fov)) /
-               (1.0f - std::cos(zoom_fov / 2.0f))));
+       return dist * std::cbrt((1.0f - std::cos(threshold_fov)) /
+               (1.0f - std::cos(zoom_fov / 2.0f)));
+}
+
+s16 adjustDist(s16 dist, float zoom_fov)
+{
+       return std::round(adjustDist((float)dist, zoom_fov));
 }
 
 void setPitchYawRollRad(core::matrix4 &m, const v3f &rot)