Merge pull request #51025 from reduz/fix-directional-shadow-bias
Fix directional shadow bias
This commit is contained in:
commit
e499758a77
6 changed files with 20 additions and 103 deletions
|
|
@ -2777,7 +2777,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
|
|||
CameraMatrix shadow_mtx = rectm * bias * matrix * modelview;
|
||||
light_data.shadow_split_offsets[j] = split;
|
||||
float bias_scale = li->shadow_transform[j].bias_scale;
|
||||
light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * bias_scale;
|
||||
light_data.shadow_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0 * bias_scale;
|
||||
light_data.shadow_normal_bias[j] = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * li->shadow_transform[j].shadow_texel_size;
|
||||
light_data.shadow_transmittance_bias[j] = storage->light_get_transmittance_bias(base) * bias_scale;
|
||||
light_data.shadow_z_range[j] = li->shadow_transform[j].farplane;
|
||||
|
|
@ -2948,14 +2948,10 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
|
|||
light_data.shadow_enabled = true;
|
||||
|
||||
if (type == RS::LIGHT_SPOT) {
|
||||
light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0);
|
||||
float shadow_texel_size = Math::tan(Math::deg2rad(spot_angle)) * radius * 2.0;
|
||||
shadow_texel_size *= light_instance_get_shadow_texel_size(li->self, p_shadow_atlas);
|
||||
|
||||
light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size;
|
||||
light_data.shadow_bias = (storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0);
|
||||
|
||||
} else { //omni
|
||||
light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) * radius / 10.0;
|
||||
light_data.shadow_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0;
|
||||
float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas);
|
||||
light_data.shadow_normal_bias = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 2.0; // applied in -1 .. 1 space
|
||||
}
|
||||
|
|
|
|||
|
|
@ -410,14 +410,8 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
|
|||
vec4 v = vec4(vertex, 1.0);
|
||||
|
||||
vec4 splane = (omni_lights.data[idx].shadow_matrix * v);
|
||||
float shadow_len = length(splane.xyz); //need to remember shadow len from here
|
||||
|
||||
{
|
||||
vec3 nofs = normal_interp * omni_lights.data[idx].shadow_normal_bias / omni_lights.data[idx].inv_radius;
|
||||
nofs *= (1.0 - max(0.0, dot(normalize(light_rel_vec), normalize(normal_interp))));
|
||||
v.xyz += nofs;
|
||||
splane = (omni_lights.data[idx].shadow_matrix * v);
|
||||
}
|
||||
float shadow_len = length(splane.xyz); //need to remember shadow len from here
|
||||
|
||||
float shadow;
|
||||
|
||||
|
|
@ -526,7 +520,8 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
|
|||
splane.xy /= splane.z;
|
||||
|
||||
splane.xy = splane.xy * 0.5 + 0.5;
|
||||
splane.z = (shadow_len - omni_lights.data[idx].shadow_bias) * omni_lights.data[idx].inv_radius;
|
||||
splane.z = shadow_len * omni_lights.data[idx].inv_radius;
|
||||
splane.z -= omni_lights.data[idx].shadow_bias;
|
||||
splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
|
||||
splane.w = 1.0; //needed? i think it should be 1 already
|
||||
shadow = sample_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale * scene_data.shadow_atlas_pixel_size, splane);
|
||||
|
|
@ -702,27 +697,17 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
|
|||
//there is a shadowmap
|
||||
vec4 v = vec4(vertex, 1.0);
|
||||
|
||||
v.xyz -= spot_dir * spot_lights.data[idx].shadow_bias;
|
||||
|
||||
float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
|
||||
|
||||
float depth_bias_scale = 1.0 / (max(0.0001, z_norm)); //the closer to the light origin, the more you have to offset to reach 1px in the map
|
||||
vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(spot_dir, -normalize(normal_interp)))) * spot_lights.data[idx].shadow_normal_bias * depth_bias_scale;
|
||||
normal_bias -= spot_dir * dot(spot_dir, normal_bias); //only XY, no Z
|
||||
v.xyz += normal_bias;
|
||||
|
||||
//adjust with bias
|
||||
z_norm = dot(spot_dir, v.xyz - spot_lights.data[idx].position) * spot_lights.data[idx].inv_radius;
|
||||
|
||||
float shadow;
|
||||
|
||||
vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
|
||||
splane /= splane.w;
|
||||
splane.z -= spot_lights.data[idx].shadow_bias;
|
||||
|
||||
if (sc_use_light_soft_shadows && spot_lights.data[idx].soft_shadow_size > 0.0) {
|
||||
//soft shadow
|
||||
|
||||
//find blocker
|
||||
float z_norm = dot(spot_dir, -light_rel_vec) * spot_lights.data[idx].inv_radius;
|
||||
|
||||
vec2 shadow_uv = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy;
|
||||
|
||||
|
|
|
|||
|
|
@ -1955,10 +1955,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
|
|||
|
||||
bool overlap = RSG::storage->light_directional_get_blend_splits(p_instance->base);
|
||||
|
||||
real_t first_radius = 0.0;
|
||||
|
||||
real_t min_distance_bias_scale = distances[1];
|
||||
|
||||
cull.shadow_count = p_shadow_index + 1;
|
||||
cull.shadows[p_shadow_index].cascade_count = splits;
|
||||
cull.shadows[p_shadow_index].light_instance = light->instance;
|
||||
|
|
@ -2006,8 +2002,8 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
|
|||
real_t z_min_cam = 0.f;
|
||||
//real_t z_max_cam = 0.f;
|
||||
|
||||
real_t bias_scale = 1.0;
|
||||
real_t aspect_bias_scale = 1.0;
|
||||
//real_t bias_scale = 1.0;
|
||||
//real_t aspect_bias_scale = 1.0;
|
||||
|
||||
//used for culling
|
||||
|
||||
|
|
@ -2061,12 +2057,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
|
|||
|
||||
radius *= texture_size / (texture_size - 2.0); //add a texel by each side
|
||||
|
||||
if (i == 0) {
|
||||
first_radius = radius;
|
||||
} else {
|
||||
bias_scale = radius / first_radius;
|
||||
}
|
||||
|
||||
z_min_cam = z_vec.dot(center) - radius;
|
||||
|
||||
{
|
||||
|
|
@ -2110,64 +2100,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
|
|||
|
||||
// a pre pass will need to be needed to determine the actual z-near to be used
|
||||
|
||||
if (pancake_size > 0) {
|
||||
z_max = z_vec.dot(center) + radius + pancake_size;
|
||||
}
|
||||
|
||||
if (aspect != 1.0) {
|
||||
// if the aspect is different, then the radius will become larger.
|
||||
// if this happens, then bias needs to be adjusted too, as depth will increase
|
||||
// to do this, compare the depth of one that would have resulted from a square frustum
|
||||
|
||||
CameraMatrix camera_matrix_square;
|
||||
if (p_cam_orthogonal) {
|
||||
Vector2 vp_he = camera_matrix.get_viewport_half_extents();
|
||||
if (p_cam_vaspect) {
|
||||
camera_matrix_square.set_orthogonal(vp_he.x * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
|
||||
} else {
|
||||
camera_matrix_square.set_orthogonal(vp_he.y * 2.0, 1.0, distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
|
||||
}
|
||||
} else {
|
||||
Vector2 vp_he = camera_matrix.get_viewport_half_extents();
|
||||
if (p_cam_vaspect) {
|
||||
camera_matrix_square.set_frustum(vp_he.x * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], true);
|
||||
} else {
|
||||
camera_matrix_square.set_frustum(vp_he.y * 2.0, 1.0, Vector2(), distances[(i == 0 || !overlap) ? i : i - 1], distances[i + 1], false);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 endpoints_square[8]; // frustum plane endpoints
|
||||
res = camera_matrix_square.get_endpoints(p_cam_transform, endpoints_square);
|
||||
ERR_CONTINUE(!res);
|
||||
Vector3 center_square;
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
center_square += endpoints_square[j];
|
||||
}
|
||||
|
||||
center_square /= 8.0;
|
||||
|
||||
real_t radius_square = 0;
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
real_t d = center_square.distance_to(endpoints_square[j]);
|
||||
if (d > radius_square) {
|
||||
radius_square = d;
|
||||
}
|
||||
}
|
||||
|
||||
radius_square *= texture_size / (texture_size - 2.0); //add a texel by each side
|
||||
|
||||
float z_max_square = z_vec.dot(center_square) + radius_square + pancake_size;
|
||||
|
||||
real_t z_min_cam_square = z_vec.dot(center_square) - radius_square;
|
||||
|
||||
aspect_bias_scale = (z_max - z_min_cam) / (z_max_square - z_min_cam_square);
|
||||
|
||||
// this is not entirely perfect, because the cull-adjusted z-max may be different
|
||||
// but at least it's warranted that it results in a greater bias, so no acne should be present either way.
|
||||
// pancaking also helps with this.
|
||||
}
|
||||
z_max = z_vec.dot(center) + radius + pancake_size;
|
||||
|
||||
{
|
||||
CameraMatrix ortho_camera;
|
||||
|
|
@ -2188,7 +2121,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
|
|||
cull.shadows[p_shadow_index].cascades[i].zfar = z_max - z_min_cam;
|
||||
cull.shadows[p_shadow_index].cascades[i].split = distances[i + 1];
|
||||
cull.shadows[p_shadow_index].cascades[i].shadow_texel_size = radius * 2.0 / texture_size;
|
||||
cull.shadows[p_shadow_index].cascades[i].bias_scale = bias_scale * aspect_bias_scale * min_distance_bias_scale;
|
||||
cull.shadows[p_shadow_index].cascades[i].bias_scale = (z_max - z_min_cam);
|
||||
cull.shadows[p_shadow_index].cascades[i].range_begin = z_max;
|
||||
cull.shadows[p_shadow_index].cascades[i].uv_scale = uv_scale;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue