mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Merge pull request #107254 from passivestar/shadow-unleak
Fix LightmapGI shadow leaks
This commit is contained in:
commit
09ed9d4a93
3 changed files with 39 additions and 12 deletions
|
@ -979,7 +979,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID
|
|||
return BAKE_OK;
|
||||
}
|
||||
|
||||
LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata) {
|
||||
LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, RID p_unocclude_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata) {
|
||||
RID denoise_params_buffer = p_rd->uniform_buffer_create(sizeof(DenoiseParams));
|
||||
DenoiseParams denoise_params;
|
||||
denoise_params.spatial_bandwidth = 5.0f;
|
||||
|
@ -1000,8 +1000,15 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh
|
|||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
|
||||
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
|
||||
u.binding = 3;
|
||||
u.append_id(p_unocclude_tex);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
{
|
||||
RD::Uniform u;
|
||||
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
|
||||
u.binding = 4;
|
||||
u.append_id(denoise_params_buffer);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
|
@ -1622,6 +1629,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||
}
|
||||
|
||||
PushConstant push_constant;
|
||||
push_constant.denoiser_range = p_use_denoiser ? p_denoiser_range : 1.0;
|
||||
|
||||
/* UNOCCLUDE */
|
||||
{
|
||||
|
@ -1638,7 +1646,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||
RD::Uniform u;
|
||||
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
|
||||
u.binding = 1;
|
||||
u.append_id(unocclude_tex); //will be unused
|
||||
u.append_id(unocclude_tex);
|
||||
uniforms.push_back(u);
|
||||
}
|
||||
}
|
||||
|
@ -1659,6 +1667,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||
rd->compute_list_end(); //done
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TEXTURES
|
||||
for (int i = 0; i < atlas_slices; i++) {
|
||||
Vector<uint8_t> s = rd->texture_get_data(unocclude_tex, i);
|
||||
Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s);
|
||||
img->save_exr("res://1_unocclude_" + itos(i) + ".exr", false);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_step_function) {
|
||||
if (p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true)) {
|
||||
FREE_TEXTURES
|
||||
|
@ -2083,7 +2099,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||
} else {
|
||||
// JNLM (built-in).
|
||||
SWAP(light_accum_tex, light_accum_tex2);
|
||||
error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, p_denoiser_strength, p_denoiser_range, atlas_size, atlas_slices, p_bake_sh, p_step_function, p_bake_userdata);
|
||||
error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, unocclude_tex, p_denoiser_strength, p_denoiser_range, atlas_size, atlas_slices, p_bake_sh, p_step_function, p_bake_userdata);
|
||||
}
|
||||
if (unlikely(error != BAKE_OK)) {
|
||||
return error;
|
||||
|
@ -2098,7 +2114,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
|
|||
} else {
|
||||
// JNLM (built-in).
|
||||
SWAP(shadowmask_tex, shadowmask_tex2);
|
||||
error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, shadowmask_tex2, normal_tex, shadowmask_tex, p_denoiser_strength, p_denoiser_range, atlas_size, atlas_slices, false, p_step_function, p_bake_userdata);
|
||||
error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, shadowmask_tex2, normal_tex, shadowmask_tex, unocclude_tex, p_denoiser_strength, p_denoiser_range, atlas_size, atlas_slices, false, p_step_function, p_bake_userdata);
|
||||
}
|
||||
if (unlikely(error != BAKE_OK)) {
|
||||
return error;
|
||||
|
|
|
@ -261,7 +261,7 @@ class LightmapperRD : public Lightmapper {
|
|||
uint32_t ray_to = 0;
|
||||
uint32_t region_ofs[2] = {};
|
||||
uint32_t probe_count = 0;
|
||||
uint32_t pad = 0;
|
||||
uint32_t denoiser_range = 0;
|
||||
};
|
||||
|
||||
Vector<Ref<Image>> lightmap_textures;
|
||||
|
@ -289,7 +289,7 @@ class LightmapperRD : public Lightmapper {
|
|||
void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
|
||||
|
||||
BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
|
||||
BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata);
|
||||
BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, RID p_unocclude_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata);
|
||||
BakeError _pack_l1(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
|
||||
|
||||
Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name, bool p_shadowmask);
|
||||
|
|
|
@ -46,7 +46,7 @@ layout(set = 1, binding = 2) uniform texture2D environment;
|
|||
#ifdef MODE_UNOCCLUDE
|
||||
|
||||
layout(rgba32f, set = 1, binding = 0) uniform restrict image2DArray position;
|
||||
layout(rgba32f, set = 1, binding = 1) uniform restrict readonly image2DArray unocclude;
|
||||
layout(rgba32f, set = 1, binding = 1) uniform restrict image2DArray unocclude;
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -73,7 +73,8 @@ layout(set = 1, binding = 1) uniform texture2DArray source_light;
|
|||
|
||||
#ifdef MODE_DENOISE
|
||||
layout(set = 1, binding = 2) uniform texture2DArray source_normal;
|
||||
layout(set = 1, binding = 3) uniform DenoiseParams {
|
||||
layout(set = 1, binding = 3) uniform texture2DArray unocclude_mask;
|
||||
layout(set = 1, binding = 4) uniform DenoiseParams {
|
||||
float spatial_bandwidth;
|
||||
float light_bandwidth;
|
||||
float albedo_bandwidth;
|
||||
|
@ -93,6 +94,7 @@ layout(push_constant, std430) uniform Params {
|
|||
|
||||
ivec2 region_ofs;
|
||||
uint probe_count;
|
||||
uint denoiser_range;
|
||||
}
|
||||
params;
|
||||
|
||||
|
@ -1011,13 +1013,16 @@ void main() {
|
|||
|
||||
vec3 rays[4] = vec3[](tangent, bitangent, -tangent, -bitangent);
|
||||
float min_d = 1e20;
|
||||
float unocclude_mask = 0.0;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vec3 ray_to = base_pos + rays[i] * texel_size;
|
||||
vec3 ray_to = base_pos + rays[i] * texel_size * params.denoiser_range;
|
||||
float d;
|
||||
vec3 norm;
|
||||
|
||||
if (trace_ray_closest_hit_distance(base_pos, ray_to, d, norm) == RAY_BACK) {
|
||||
if (d < min_d) {
|
||||
unocclude_mask = 1.0;
|
||||
if (d <= texel_size && d < min_d) {
|
||||
// This bias needs to be greater than the regular bias, because otherwise later, rays will go the other side when pointing back.
|
||||
vertex_pos = base_pos + rays[i] * d + norm * bake_params.bias * 10.0;
|
||||
min_d = d;
|
||||
|
@ -1028,6 +1033,7 @@ void main() {
|
|||
position_alpha.xyz = vertex_pos;
|
||||
|
||||
imageStore(position, ivec3(atlas_pos, params.atlas_slice), position_alpha);
|
||||
imageStore(unocclude, ivec3(atlas_pos, params.atlas_slice), vec4(unocclude_mask, 0, 0, 0));
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1211,6 +1217,7 @@ void main() {
|
|||
vec3 search_rgb = texelFetch(sampler2DArray(source_light, linear_sampler), ivec3(search_pos, lightmap_slice), 0).rgb;
|
||||
vec3 search_albedo = texelFetch(sampler2DArray(albedo_tex, linear_sampler), ivec3(search_pos, params.atlas_slice), 0).rgb;
|
||||
vec3 search_normal = texelFetch(sampler2DArray(source_normal, linear_sampler), ivec3(search_pos, params.atlas_slice), 0).xyz;
|
||||
float search_occlusion = texelFetch(sampler2DArray(unocclude_mask, linear_sampler), ivec3(search_pos, params.atlas_slice), 0).r;
|
||||
float patch_square_dist = 0.0f;
|
||||
for (int offset_y = -HALF_PATCH_WINDOW; offset_y <= HALF_PATCH_WINDOW; offset_y++) {
|
||||
for (int offset_x = -HALF_PATCH_WINDOW; offset_x <= HALF_PATCH_WINDOW; offset_x++) {
|
||||
|
@ -1252,12 +1259,16 @@ void main() {
|
|||
float normal_square_dist = dot(normal_delta, normal_delta);
|
||||
weight *= exp(-normal_square_dist / TWO_SIGMA_NORMAL_SQUARE);
|
||||
|
||||
// Weight with occlusion.
|
||||
weight *= 1.0 - search_occlusion;
|
||||
|
||||
denoised_rgb += weight * search_rgb;
|
||||
sum_weights += weight;
|
||||
}
|
||||
}
|
||||
|
||||
denoised_rgb /= sum_weights;
|
||||
// Avoid division by zero if no weights were accumulated.
|
||||
denoised_rgb = sum_weights > EPSILON ? denoised_rgb / sum_weights : input_rgb;
|
||||
} else {
|
||||
// Ignore pixels where the normal is empty, just copy the light color.
|
||||
denoised_rgb = input_light.rgb;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue