From 24c2c452de8f65115958583e34c765b21f851d04 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Mon, 12 Jan 2026 18:56:10 -0800 Subject: [PATCH] Fix downsampled radiance map generation. Reduce the mipmap levels so that the border is pixel perfect Always use the high quality downsample to reduce jaggies Fix the jacobian approximation so that it actually helps account for the octahedral distortion --- .../renderer_rd/effects/copy_effects.cpp | 36 +++++-------------- .../renderer_rd/effects/copy_effects.h | 13 ++++--- .../rendering/renderer_rd/environment/sky.cpp | 22 ++++++------ .../shaders/effects/octmap_downsampler.glsl | 7 +--- 4 files changed, 26 insertions(+), 52 deletions(-) diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index edb16e28bb4..c5c98681e5f 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -166,27 +166,15 @@ CopyEffects::CopyEffects(BitField p_raster_effects) { { // Initialize octmap downsampler. - Vector downsampler_modes; - if (raster_effects.has_flag(RASTER_EFFECT_OCTMAP)) { - for (int i = 0; i < DOWNSAMPLER_MODE_RASTER_MAX; i++) { - String mode; - if (i & DOWNSAMPLER_MODE_FLAG_HIGH_QUALITY) { - mode += "\n#define USE_HIGH_QUALITY\n"; - } - downsampler_modes.push_back(mode); - } - octmap_downsampler.raster_shader.initialize(downsampler_modes); + if (raster_effects.has_flag(RASTER_EFFECT_OCTMAP)) { + octmap_downsampler.raster_shader.initialize({ "" }); octmap_downsampler.shader_version = octmap_downsampler.raster_shader.version_create(); - for (int i = 0; i < DOWNSAMPLER_MODE_RASTER_MAX; i++) { - octmap_downsampler.raster_pipelines[i].setup(octmap_downsampler.raster_shader.version_get_shader(octmap_downsampler.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); - } + octmap_downsampler.raster_pipeline.setup(octmap_downsampler.raster_shader.version_get_shader(octmap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); } else { + Vector downsampler_modes; for (int i = 0; i < DOWNSAMPLER_MODE_COMPUTE_MAX; i++) { String mode; - if (i & DOWNSAMPLER_MODE_FLAG_HIGH_QUALITY) { - mode += "\n#define USE_HIGH_QUALITY\n"; - } if (i & DOWNSAMPLER_MODE_FLAG_RGB10_A2) { mode += "\n#define OCTMAP_FORMAT rgb10_a2\n"; } else { @@ -1152,7 +1140,7 @@ void CopyEffects::copy_cubemap_to_octmap(RID p_source_rd_texture, RID p_dst_fram RD::get_singleton()->draw_list_end(); } -void CopyEffects::octmap_downsample(RID p_source_octmap, RID p_dest_octmap, const Size2i &p_size, bool p_use_filter_quality, float p_border_size) { +void CopyEffects::octmap_downsample(RID p_source_octmap, RID p_dest_octmap, const Size2i &p_size, float p_border_size) { ERR_FAIL_COND_MSG(raster_effects.has_flag(RASTER_EFFECT_OCTMAP), "Can't use compute based octmap downsample."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); @@ -1170,9 +1158,6 @@ void CopyEffects::octmap_downsample(RID p_source_octmap, RID p_dest_octmap, cons RD::Uniform u_dest_octmap(RD::UNIFORM_TYPE_IMAGE, 0, Vector({ p_dest_octmap })); int mode = 0; - if (!p_use_filter_quality || filter.use_high_quality) { - mode |= DOWNSAMPLER_MODE_FLAG_HIGH_QUALITY; - } RD::TextureFormat texture_format = RD::get_singleton()->texture_get_format(p_dest_octmap); switch (texture_format.format) { @@ -1205,7 +1190,7 @@ void CopyEffects::octmap_downsample(RID p_source_octmap, RID p_dest_octmap, cons RD::get_singleton()->compute_list_end(); } -void CopyEffects::octmap_downsample_raster(RID p_source_octmap, RID p_dest_framebuffer, const Size2i &p_size, bool p_use_filter_quality, float p_border_size) { +void CopyEffects::octmap_downsample_raster(RID p_source_octmap, RID p_dest_framebuffer, const Size2i &p_size, float p_border_size) { ERR_FAIL_COND_MSG(!raster_effects.has_flag(RASTER_EFFECT_OCTMAP), "Can't use raster based octmap downsample."); UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); @@ -1221,16 +1206,11 @@ void CopyEffects::octmap_downsample_raster(RID p_source_octmap, RID p_dest_frame RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector({ default_sampler, p_source_octmap })); - int mode = 0; - if (!p_use_filter_quality || filter.use_high_quality) { - mode |= DOWNSAMPLER_MODE_FLAG_HIGH_QUALITY; - } - - RID shader = octmap_downsampler.raster_shader.version_get_shader(octmap_downsampler.shader_version, mode); + RID shader = octmap_downsampler.raster_shader.version_get_shader(octmap_downsampler.shader_version, 0); ERR_FAIL_COND(shader.is_null()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::DRAW_IGNORE_COLOR_ALL); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, octmap_downsampler.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, octmap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); RD::get_singleton()->draw_list_set_push_constant(draw_list, &octmap_downsampler.push_constant, sizeof(OctmapDownsamplerPushConstant)); diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h index 62c546f9fbd..e15fd4a51ea 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.h +++ b/servers/rendering/renderer_rd/effects/copy_effects.h @@ -256,11 +256,10 @@ private: }; enum OctmapDownsamplerMode { - DOWNSAMPLER_MODE_FLAG_HIGH_QUALITY = (1 << 0), - DOWNSAMPLER_MODE_FLAG_RGB10_A2 = (1 << 1), + DOWNSAMPLER_MODE_FLAG_RGB10_A2 = (1 << 0), - DOWNSAMPLER_MODE_COMPUTE_MAX = ((DOWNSAMPLER_MODE_FLAG_HIGH_QUALITY | DOWNSAMPLER_MODE_FLAG_RGB10_A2) + 1), - DOWNSAMPLER_MODE_RASTER_MAX = (DOWNSAMPLER_MODE_FLAG_HIGH_QUALITY + 1), + DOWNSAMPLER_MODE_COMPUTE_MAX = (DOWNSAMPLER_MODE_FLAG_RGB10_A2 + 1), + DOWNSAMPLER_MODE_RASTER_MAX = 1, }; struct OctmapDownsampler { @@ -269,7 +268,7 @@ private: OctmapDownsamplerRasterShaderRD raster_shader; RID shader_version; PipelineDeferredRD compute_pipelines[DOWNSAMPLER_MODE_COMPUTE_MAX]; - PipelineCacheRD raster_pipelines[DOWNSAMPLER_MODE_RASTER_MAX]; + PipelineCacheRD raster_pipeline; } octmap_downsampler; enum OctmapFilterMode { @@ -393,8 +392,8 @@ public: void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip); void copy_cubemap_to_octmap(RID p_source_rd_texture, RID p_dst_framebuffer, float p_border_size); - void octmap_downsample(RID p_source_octmap, RID p_dest_octmap, const Size2i &p_size, bool p_use_filter_quality, float p_border_size); - void octmap_downsample_raster(RID p_source_octmap, RID p_dest_framebuffer, const Size2i &p_size, bool p_use_filter_quality, float p_border_size); + void octmap_downsample(RID p_source_octmap, RID p_dest_octmap, const Size2i &p_size, float p_border_size); + void octmap_downsample_raster(RID p_source_octmap, RID p_dest_framebuffer, const Size2i &p_size, float p_border_size); void octmap_filter(RID p_source_octmap, const Vector &p_dest_octmap, bool p_use_array, float p_border_size); void octmap_filter_raster(RID p_source_octmap, RID p_dest_framebuffer, uint32_t p_mip_level, float p_border_size); void octmap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_sample_count, float p_roughness, uint32_t p_source_size, uint32_t p_dest_size, float p_border_size); diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index dc6b9e9f787..62aa8124524 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -340,7 +340,7 @@ void SkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bo tf.format = p_texture_format; tf.width = p_low_quality ? 160 : p_size >> 1; // Always 160x160 when using REALTIME. tf.height = p_low_quality ? 160 : p_size >> 1; - tf.mipmaps = p_low_quality ? 7 : mipmaps - 1; + tf.mipmaps = p_low_quality ? 5 : mipmaps - 1; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; if (!use_raster_effect) { tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; @@ -378,10 +378,10 @@ void SkyRD::ReflectionData::create_reflection_fast_filter(bool p_use_arrays) { if (use_raster_effect) { RD::get_singleton()->draw_command_begin_label("Downsample Radiance Map"); - copy_effects->octmap_downsample_raster(radiance_base_octmap, downsampled_layer.mipmaps[0].framebuffer, downsampled_layer.mipmaps[0].size, true, uv_border_size); + copy_effects->octmap_downsample_raster(radiance_base_octmap, downsampled_layer.mipmaps[0].framebuffer, downsampled_layer.mipmaps[0].size, uv_border_size); for (uint32_t i = 1; i < downsampled_layer.mipmaps.size(); i++) { - copy_effects->octmap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffer, downsampled_layer.mipmaps[i].size, true, uv_border_size); + copy_effects->octmap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffer, downsampled_layer.mipmaps[i].size, uv_border_size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance @@ -399,10 +399,10 @@ void SkyRD::ReflectionData::create_reflection_fast_filter(bool p_use_arrays) { RD::get_singleton()->draw_command_end_label(); // Filter radiance } else { RD::get_singleton()->draw_command_begin_label("Downsample Radiance Map"); - copy_effects->octmap_downsample(radiance_base_octmap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size, true, uv_border_size); + copy_effects->octmap_downsample(radiance_base_octmap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size, uv_border_size); for (uint32_t i = 1; i < downsampled_layer.mipmaps.size(); i++) { - copy_effects->octmap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size, true, uv_border_size); + copy_effects->octmap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size, uv_border_size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance Vector views; @@ -429,10 +429,10 @@ void SkyRD::ReflectionData::create_reflection_importance_sample(bool p_use_array if (use_raster_effect) { if (p_base_layer == 1) { RD::get_singleton()->draw_command_begin_label("Downsample Radiance Map"); - copy_effects->octmap_downsample_raster(radiance_base_octmap, downsampled_layer.mipmaps[0].framebuffer, downsampled_layer.mipmaps[0].size, false, uv_border_size); + copy_effects->octmap_downsample_raster(radiance_base_octmap, downsampled_layer.mipmaps[0].framebuffer, downsampled_layer.mipmaps[0].size, uv_border_size); for (uint32_t i = 1; i < downsampled_layer.mipmaps.size(); i++) { - copy_effects->octmap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffer, downsampled_layer.mipmaps[i].size, false, uv_border_size); + copy_effects->octmap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffer, downsampled_layer.mipmaps[i].size, uv_border_size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance } @@ -460,10 +460,10 @@ void SkyRD::ReflectionData::create_reflection_importance_sample(bool p_use_array } else { if (p_base_layer == 1) { RD::get_singleton()->draw_command_begin_label("Downsample Radiance Map"); - copy_effects->octmap_downsample(radiance_base_octmap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size, false, uv_border_size); + copy_effects->octmap_downsample(radiance_base_octmap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size, uv_border_size); for (uint32_t i = 1; i < downsampled_layer.mipmaps.size(); i++) { - copy_effects->octmap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size, false, uv_border_size); + copy_effects->octmap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size, uv_border_size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance } @@ -490,10 +490,10 @@ void SkyRD::ReflectionData::update_reflection_mipmaps(int p_start, int p_end) { Size2i size = layers[i].mipmaps[j + 1].size; if (use_raster_effect) { RID framebuffer = layers[i].mipmaps[j + 1].framebuffer; - copy_effects->octmap_downsample_raster(view, framebuffer, size, false, uv_border_size); + copy_effects->octmap_downsample_raster(view, framebuffer, size, uv_border_size); } else { RID texture = layers[i].mipmaps[j + 1].view; - copy_effects->octmap_downsample(view, texture, size, false, uv_border_size); + copy_effects->octmap_downsample(view, texture, size, uv_border_size); } } } diff --git a/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler.glsl index 2ce1b727b52..1ae91212b43 100644 --- a/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/octmap_downsampler.glsl @@ -44,7 +44,7 @@ params; // Use an approximation of the Jacobian. float calcWeight(float u, float v) { - vec3 d = oct_to_vec3_with_border(vec2(u, v), params.border_size); + vec3 d = oct_to_vec3_with_border(vec2(u, v) * 0.5 + 0.5, params.border_size); return 1.0 / pow(abs(d.z) + 1.0, 3.0); } @@ -54,7 +54,6 @@ void main() { float inv_size = 1.0 / float(params.size); uvec2 sample_id = id; -#ifdef USE_HIGH_QUALITY float u0 = (float(sample_id.x) * 2.0f + 1.0f - 0.75f) * inv_size - 1.0f; float u1 = (float(sample_id.x) * 2.0f + 1.0f + 0.75f) * inv_size - 1.0f; float v0 = (float(sample_id.y) * 2.0f + 1.0f - 0.75f) * inv_size - 1.0f; @@ -75,9 +74,5 @@ void main() { color += textureLod(source_octmap, vec2(u0, v1) * 0.5f + 0.5f, 0.0) * weights[2]; color += textureLod(source_octmap, vec2(u1, v1) * 0.5f + 0.5f, 0.0) * weights[3]; imageStore(dest_octmap, ivec2(id), color); -#else - vec2 uv = (vec2(sample_id.xy) + 0.5) * inv_size; - imageStore(dest_octmap, ivec2(id), textureLod(source_octmap, uv, 0.0)); -#endif } }