mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 10:03:45 +01:00
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
This commit is contained in:
parent
1d25d1f7ad
commit
f5706d444b
@ -181,9 +181,14 @@ float getDeltaPerspectiveFactor(float l)
|
|||||||
|
|
||||||
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
|
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
|
||||||
{
|
{
|
||||||
|
float baseLength = getBaseLength(smTexCoord);
|
||||||
|
float perspectiveFactor;
|
||||||
|
|
||||||
// Return fast if sharp shadows are requested
|
// Return fast if sharp shadows are requested
|
||||||
if (SOFTSHADOWRADIUS <= 1.0)
|
if (SOFTSHADOWRADIUS <= 1.0) {
|
||||||
return SOFTSHADOWRADIUS;
|
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
||||||
|
return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
vec2 clampedpos;
|
vec2 clampedpos;
|
||||||
float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5);
|
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 pointDepth;
|
||||||
float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
|
float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
|
||||||
float perspectiveFactor;
|
|
||||||
float bound = clamp(PCFBOUND * (1 - baseLength), 0.5, PCFBOUND);
|
float bound = clamp(PCFBOUND * (1 - baseLength), 0.5, PCFBOUND);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
@ -211,9 +214,10 @@ float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDist
|
|||||||
}
|
}
|
||||||
|
|
||||||
depth = depth / n;
|
depth = depth / n;
|
||||||
|
|
||||||
depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001;
|
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
|
#ifdef POISSON_FILTER
|
||||||
|
@ -740,7 +740,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||||||
s32 shadow_filter = g_settings->getS32("shadow_filters");
|
s32 shadow_filter = g_settings->getS32("shadow_filters");
|
||||||
shaders_header << "#define SHADOW_FILTER " << shadow_filter << "\n";
|
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)
|
if (shadow_soft_radius < 1.0f)
|
||||||
shadow_soft_radius = 1.0f;
|
shadow_soft_radius = 1.0f;
|
||||||
shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n";
|
shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n";
|
||||||
|
@ -33,29 +33,34 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
|
|||||||
v3f newCenter;
|
v3f newCenter;
|
||||||
v3f look = cam->getDirection();
|
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 camPos2 = cam->getPosition();
|
||||||
v3f camPos = v3f(camPos2.X - cam->getOffset().X * BS,
|
v3f camPos = v3f(camPos2.X - cam->getOffset().X * BS,
|
||||||
camPos2.Y - cam->getOffset().Y * BS,
|
camPos2.Y - cam->getOffset().Y * BS,
|
||||||
camPos2.Z - cam->getOffset().Z * BS);
|
camPos2.Z - cam->getOffset().Z * BS);
|
||||||
camPos += look * shadow_frustum.zNear;
|
camPos += look * sfNear;
|
||||||
camPos2 += look * shadow_frustum.zNear;
|
camPos2 += look * sfNear;
|
||||||
float end = shadow_frustum.zNear + shadow_frustum.zFar;
|
|
||||||
newCenter = camPos + look * (shadow_frustum.zNear + 0.05f * end);
|
// center point of light frustum
|
||||||
v3f world_center = camPos2 + look * (shadow_frustum.zNear + 0.05f * end);
|
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
|
// 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);
|
|
||||||
|
|
||||||
const v3f &viewUp = cam->getCameraNode()->getUpVector();
|
const v3f &viewUp = cam->getCameraNode()->getUpVector();
|
||||||
// viewUp.normalize();
|
|
||||||
|
|
||||||
v3f viewRight = look.crossProduct(viewUp);
|
v3f viewRight = look.crossProduct(viewUp);
|
||||||
// viewRight.normalize();
|
|
||||||
|
|
||||||
v3f farCorner = look + viewRight * tanFovX + viewUp * tanFovY;
|
v3f farCorner = look + viewRight * tanFovX + viewUp * tanFovY;
|
||||||
// Compute the frustumBoundingSphere radius
|
// Compute the frustumBoundingSphere radius
|
||||||
v3f boundVec = (camPos + farCorner * shadow_frustum.zFar) - newCenter;
|
v3f boundVec = (camPos + farCorner * sfFar) - newCenter;
|
||||||
radius = boundVec.getLength() * 2.0f;
|
radius = boundVec.getLength() * 2.0f;
|
||||||
// boundVec.getLength();
|
// boundVec.getLength();
|
||||||
float vvolume = radius * 2.0f;
|
float vvolume = radius * 2.0f;
|
||||||
|
@ -159,7 +159,7 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir,
|
|||||||
return true;
|
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.
|
// 1.775 ~= 72 * PI / 180 * 1.4, the default FOV on the client.
|
||||||
// The heuristic threshold for zooming is half of that.
|
// 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)
|
if (zoom_fov < 0.001f || zoom_fov > threshold_fov)
|
||||||
return dist;
|
return dist;
|
||||||
|
|
||||||
return std::round(dist * std::cbrt((1.0f - std::cos(threshold_fov)) /
|
return dist * std::cbrt((1.0f - std::cos(threshold_fov)) /
|
||||||
(1.0f - std::cos(zoom_fov / 2.0f))));
|
(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)
|
void setPitchYawRollRad(core::matrix4 &m, const v3f &rot)
|
||||||
|
Loading…
Reference in New Issue
Block a user