Skip to content

Commit

Permalink
Adjust shadowmap distortion to use entire SM texture (minetest#12166)
Browse files Browse the repository at this point in the history
  • Loading branch information
x2048 committed Apr 7, 2022
1 parent 0b5b2b2 commit 48f7c56
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 112 deletions.
25 changes: 14 additions & 11 deletions client/shaders/nodes_shader/opengl_fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ uniform float animationTimer;
uniform mat4 m_ShadowViewProj;
uniform float f_shadowfar;
uniform float f_shadow_strength;
uniform vec4 CameraPos;
varying float normalOffsetScale;
varying float adj_shadow_strength;
varying float cosLight;
Expand Down Expand Up @@ -53,12 +54,13 @@ uniform float zPerspectiveBias;

vec4 getPerspectiveFactor(in vec4 shadowPosition)
{

float pDistance = length(shadowPosition.xy);
vec2 s = vec2(shadowPosition.x > CameraPos.x ? 1.0 : -1.0, shadowPosition.y > CameraPos.y ? 1.0 : -1.0);
vec2 l = s * (shadowPosition.xy - CameraPos.xy) / (1.0 - s * CameraPos.xy);
float pDistance = length(l);
float pFactor = pDistance * xyPerspectiveBias0 + xyPerspectiveBias1;

shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPerspectiveBias);

l /= pFactor;
shadowPosition.xy = CameraPos.xy * (1.0 - l) + s * l;
shadowPosition.z *= zPerspectiveBias;
return shadowPosition;
}

Expand Down Expand Up @@ -171,21 +173,20 @@ float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDis

float getBaseLength(vec2 smTexCoord)
{
float l = length(2.0 * smTexCoord.xy - 1.0); // length in texture coords
float l = length(2.0 * smTexCoord.xy - 1.0 - CameraPos.xy); // length in texture coords
return xyPerspectiveBias1 / (1.0 / l - xyPerspectiveBias0); // return to undistorted coords
}

float getDeltaPerspectiveFactor(float l)
{
return 0.1 / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10
return 0.04 * pow(512.0 / f_textureresolution, 0.4) / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10
}

float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
{
float baseLength = getBaseLength(smTexCoord);
float perspectiveFactor;

if (PCFBOUND == 0.0) return 0.0;
// Return fast if sharp shadows are requested
if (PCFBOUND == 0.0)
return 0.0;
Expand Down Expand Up @@ -489,11 +490,13 @@ void main(void)
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
vec3 posLightSpace = getLightSpacePosition();

float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 50.0));
float distance_rate = (1.0 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 10.0));
if (max(abs(posLightSpace.x - 0.5), abs(posLightSpace.y - 0.5)) > 0.5)
distance_rate = 0.0;
float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z),0.0);

if (distance_rate > 1e-7) {

#ifdef COLORED_SHADOWS
vec4 visibility;
if (cosLight > 0.0)
Expand Down Expand Up @@ -527,7 +530,7 @@ void main(void)
}

shadow_int *= f_adj_shadow_strength;

// calculate fragment color from components:
col.rgb =
adjusted_night_ratio * col.rgb + // artificial light
Expand Down
89 changes: 55 additions & 34 deletions client/shaders/object_shader/opengl_fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,49 @@ uniform vec4 skyBgColor;
uniform float fogDistance;
uniform vec3 eyePosition;

// The cameraOffset is the current center of the visible world.
uniform vec3 cameraOffset;
uniform float animationTimer;
#ifdef ENABLE_DYNAMIC_SHADOWS
// shadow texture
uniform sampler2D ShadowMapSampler;
// shadow uniforms
uniform vec3 v_LightDirection;
uniform float f_textureresolution;
uniform mat4 m_ShadowViewProj;
uniform float f_shadowfar;
uniform float f_shadow_strength;
uniform vec4 CameraPos;
varying float normalOffsetScale;
varying float adj_shadow_strength;
varying float cosLight;
varying float f_normal_length;
#endif


varying vec3 vNormal;
varying vec3 vPosition;
// World position in the visible world (i.e. relative to the cameraOffset.)
// This can be used for many shader effects without loss of precision.
// If the absolute position is required it can be calculated with
// cameraOffset + worldPosition (for large coordinates the limits of float
// precision must be considered).
varying vec3 worldPosition;
varying lowp vec4 varColor;
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif

varying vec3 eyeVec;
varying float nightRatio;

varying float vIDiff;

const float e = 2.718281828459;
const float BS = 10.0;
const float fogStart = FOG_START;
const float fogShadingParameter = 1.0 / (1.0 - fogStart);

#ifdef ENABLE_DYNAMIC_SHADOWS
// shadow texture
uniform sampler2D ShadowMapSampler;
// shadow uniforms
uniform vec3 v_LightDirection;
uniform float f_textureresolution;
uniform mat4 m_ShadowViewProj;
uniform float f_shadowfar;
uniform float f_timeofday;
uniform float f_shadow_strength;
varying float normalOffsetScale;
varying float adj_shadow_strength;
varying float cosLight;
varying float f_normal_length;
#endif


#ifdef ENABLE_DYNAMIC_SHADOWS
uniform float xyPerspectiveBias0;
Expand All @@ -49,15 +57,22 @@ uniform float zPerspectiveBias;

vec4 getPerspectiveFactor(in vec4 shadowPosition)
{

float pDistance = length(shadowPosition.xy);
vec2 s = vec2(shadowPosition.x > CameraPos.x ? 1.0 : -1.0, shadowPosition.y > CameraPos.y ? 1.0 : -1.0);
vec2 l = s * (shadowPosition.xy - CameraPos.xy) / (1.0 - s * CameraPos.xy);
float pDistance = length(l);
float pFactor = pDistance * xyPerspectiveBias0 + xyPerspectiveBias1;

shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPerspectiveBias);

l /= pFactor;
shadowPosition.xy = CameraPos.xy * (1.0 - l) + s * l;
shadowPosition.z *= zPerspectiveBias;
return shadowPosition;
}

// assuming near is always 1.0
float getLinearDepth()
{
return 2.0 * f_shadowfar / (f_shadowfar + 1.0 - (2.0 * gl_FragCoord.z - 1.0) * (f_shadowfar - 1.0));
}

vec3 getLightSpacePosition()
{
vec4 pLightSpace;
Expand Down Expand Up @@ -161,13 +176,13 @@ float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDis

float getBaseLength(vec2 smTexCoord)
{
float l = length(2.0 * smTexCoord.xy - 1.0); // length in texture coords
float l = length(2.0 * smTexCoord.xy - 1.0 - CameraPos.xy); // length in texture coords
return xyPerspectiveBias1 / (1.0 / l - xyPerspectiveBias0); // return to undistorted coords
}

float getDeltaPerspectiveFactor(float l)
{
return 0.1 / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10
return 0.04 * pow(512.0 / f_textureresolution, 0.4) / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10
}

float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
Expand All @@ -178,7 +193,7 @@ float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDist
// Return fast if sharp shadows are requested
if (PCFBOUND == 0.0)
return 0.0;

if (SOFTSHADOWRADIUS <= 1.0) {
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
Expand Down Expand Up @@ -418,6 +433,7 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
#endif

#if ENABLE_TONE_MAPPING

/* Hable's UC2 Tone mapping parameters
A = 0.22;
B = 0.30;
Expand Down Expand Up @@ -448,12 +464,14 @@ vec4 applyToneMapping(vec4 color)
}
#endif



void main(void)
{
vec3 color;
vec2 uv = varTexCoord.st;
vec4 base = texture2D(baseTexture, uv).rgba;

vec4 base = texture2D(baseTexture, uv).rgba;
// If alpha is zero, we can just discard the pixel. This fixes transparency
// on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
// and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
Expand All @@ -467,8 +485,7 @@ void main(void)
#endif

color = base.rgb;
vec4 col = vec4(color.rgb, base.a);
col.rgb *= varColor.rgb;
vec4 col = vec4(color.rgb * varColor.rgb, 1.0);
col.rgb *= vIDiff;

#ifdef ENABLE_DYNAMIC_SHADOWS
Expand All @@ -477,11 +494,13 @@ void main(void)
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
vec3 posLightSpace = getLightSpacePosition();

float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 50.0));
float distance_rate = (1.0 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 10.0));
if (max(abs(posLightSpace.x - 0.5), abs(posLightSpace.y - 0.5)) > 0.5)
distance_rate = 0.0;
float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z),0.0);

if (distance_rate > 1e-7) {

#ifdef COLORED_SHADOWS
vec4 visibility;
if (cosLight > 0.0)
Expand All @@ -506,8 +525,8 @@ void main(void)
// Power ratio was measured on torches in MTG (brightness = 14).
float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6);

// cosine of the normal-to-light angle when
// we start to apply self-shadowing
// Apply self-shadowing when light falls at a narrow angle to the surface
// Cosine of the cut-off angle.
const float self_shadow_cutoff_cosine = 0.14;
if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) {
shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
Expand Down Expand Up @@ -541,5 +560,7 @@ void main(void)
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col = mix(skyBgColor, col, clarity);
gl_FragColor = vec4(col.rgb, base.a);
col = vec4(col.rgb, base.a);

gl_FragColor = col;
}
10 changes: 7 additions & 3 deletions client/shaders/shadow_shaders/pass1_trans_vertex.glsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
uniform mat4 LightMVP; // world matrix
uniform vec4 CameraPos;
varying vec4 tPos;
#ifdef COLORED_SHADOWS
varying vec3 varColor;
Expand All @@ -10,10 +11,13 @@ uniform float zPerspectiveBias;

vec4 getPerspectiveFactor(in vec4 shadowPosition)
{
float pDistance = length(shadowPosition.xy);
vec2 s = vec2(shadowPosition.x > CameraPos.x ? 1.0 : -1.0, shadowPosition.y > CameraPos.y ? 1.0 : -1.0);
vec2 l = s * (shadowPosition.xy - CameraPos.xy) / (1.0 - s * CameraPos.xy);
float pDistance = length(l);
float pFactor = pDistance * xyPerspectiveBias0 + xyPerspectiveBias1;
shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPerspectiveBias);

l /= pFactor;
shadowPosition.xy = CameraPos.xy * (1.0 - l) + s * l;
shadowPosition.z *= zPerspectiveBias;
return shadowPosition;
}

Expand Down
10 changes: 7 additions & 3 deletions client/shaders/shadow_shaders/pass1_vertex.glsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
uniform mat4 LightMVP; // world matrix
uniform vec4 CameraPos; // camera position
varying vec4 tPos;

uniform float xyPerspectiveBias0;
Expand All @@ -7,10 +8,13 @@ uniform float zPerspectiveBias;

vec4 getPerspectiveFactor(in vec4 shadowPosition)
{
float pDistance = length(shadowPosition.xy);
vec2 s = vec2(shadowPosition.x > CameraPos.x ? 1.0 : -1.0, shadowPosition.y > CameraPos.y ? 1.0 : -1.0);
vec2 l = s * (shadowPosition.xy - CameraPos.xy) / (1.0 - s * CameraPos.xy);
float pDistance = length(l);
float pFactor = pDistance * xyPerspectiveBias0 + xyPerspectiveBias1;
shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPerspectiveBias);

l /= pFactor;
shadowPosition.xy = CameraPos.xy * (1.0 - l) + s * l;
shadowPosition.z *= zPerspectiveBias;
return shadowPosition;
}

Expand Down
36 changes: 10 additions & 26 deletions src/client/clientmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -862,20 +862,14 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
/*
Custom update draw list for the pov of shadow light.
*/
void ClientMap::updateDrawListShadow(const v3f &shadow_light_pos, const v3f &shadow_light_dir, float shadow_range)
void ClientMap::updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir, float radius, float length)
{
ScopeProfiler sp(g_profiler, "CM::updateDrawListShadow()", SPT_AVG);

const v3f camera_position = shadow_light_pos;
const v3f camera_direction = shadow_light_dir;
// I "fake" fov just to avoid creating a new function to handle orthographic
// projection.
const f32 camera_fov = m_camera_fov * 1.9f;

v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
v3s16 cam_pos_nodes = floatToInt(shadow_light_pos, BS);
v3s16 p_blocks_min;
v3s16 p_blocks_max;
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max, shadow_range);
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max, radius + length);

std::vector<v2s16> blocks_in_range;

Expand All @@ -889,10 +883,10 @@ void ClientMap::updateDrawListShadow(const v3f &shadow_light_pos, const v3f &sha
// they are not inside the light frustum and it creates glitches.
// FIXME: This could be removed if we figure out why they are missing
// from the light frustum.
for (auto &i : m_drawlist) {
i.second->refGrab();
m_drawlist_shadow[i.first] = i.second;
}
// for (auto &i : m_drawlist) {
// i.second->refGrab();
// m_drawlist_shadow[i.first] = i.second;
// }

// Number of blocks currently loaded by the client
u32 blocks_loaded = 0;
Expand All @@ -919,23 +913,13 @@ void ClientMap::updateDrawListShadow(const v3f &shadow_light_pos, const v3f &sha
continue;
}

float range = shadow_range;

float d = 0.0;
if (!isBlockInSight(block->getPos(), camera_position,
camera_direction, camera_fov, range, &d))
v3f block_pos = intToFloat(block->getPos() * MAP_BLOCKSIZE, BS);
v3f projection = shadow_light_pos + shadow_light_dir * shadow_light_dir.dotProduct(block_pos - shadow_light_pos);
if (projection.getDistanceFrom(block_pos) > radius)
continue;

blocks_in_range_with_mesh++;

/*
Occlusion culling
*/
if (isBlockOccluded(block, cam_pos_nodes)) {
blocks_occlusion_culled++;
continue;
}

// This block is in range. Reset usage timer.
block->resetUsageTimer();

Expand Down
2 changes: 1 addition & 1 deletion src/client/clientmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class ClientMap : public Map, public scene::ISceneNode
void getBlocksInViewRange(v3s16 cam_pos_nodes,
v3s16 *p_blocks_min, v3s16 *p_blocks_max, float range=-1.0f);
void updateDrawList();
void updateDrawListShadow(const v3f &shadow_light_pos, const v3f &shadow_light_dir, float shadow_range);
void updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir, float radius, float length);
// Returns true if draw list needs updating before drawing the next frame.
bool needsUpdateDrawList() { return m_needs_update_drawlist; }
void renderMap(video::IVideoDriver* driver, s32 pass);
Expand Down
Loading

0 comments on commit 48f7c56

Please sign in to comment.