From f5706d444b02ccc1fcd854968087172d50cfcca2 Mon Sep 17 00:00:00 2001 From: x2048 Date: Sun, 11 Jul 2021 17:15:19 +0200 Subject: Improve shadow rendering with non-default camera FOV (#11385) * 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 --- src/client/shader.cpp | 2 +- src/client/shadows/dynamicshadows.cpp | 31 ++++++++++++++++++------------- src/util/numeric.cpp | 11 ++++++++--- 3 files changed, 27 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 355366bd3..0b35c37af 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -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"; diff --git a/src/client/shadows/dynamicshadows.cpp b/src/client/shadows/dynamicshadows.cpp index 775cdebce..17b711a61 100644 --- a/src/client/shadows/dynamicshadows.cpp +++ b/src/client/shadows/dynamicshadows.cpp @@ -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; diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp index 99e4cfb5c..702ddce95 100644 --- a/src/util/numeric.cpp +++ b/src/util/numeric.cpp @@ -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) -- cgit v1.2.3