godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.4k stars 21.26k forks source link

Volumetric Fog does not affect background when using Background Mode Canvas #78423

Open cridenour opened 1 year ago

cridenour commented 1 year ago

Godot version

v4.0.3.stable.official [5222a99f5]

System information

macOS 12.2.0 - Vulkan (Forward+) - integrated Apple M1 Max - Apple M1 Max (10 Threads)

Issue description

Noticed this in both 4.0.3 stable and master branch (tested on 116f783db).

When switching background mode to canvas, volumetric fog is not visible on the skybox. It will color the grid lines in the editor and objects behind it in game, but will never affect the sky.

Screen Shot 2023-06-18 at 9 42 05 PM Screen Shot 2023-06-18 at 9 42 17 PM

Steps to reproduce

  1. Create a world environment with Volumetric Fog enabled and Background Mode Canvas.
  2. Use world fog or create fog volume.

Minimal reproduction project

canvas-bg-fog.zip

Calinou commented 1 year ago

See discussion on Godot Contributors Chat: https://chat.godotengine.org/channel/rendering?msg=rssmQSemNovKWMxTD

cridenour commented 1 year ago
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 788ec1cee4..c15af5ce97 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -1428,7 +1428,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p

    RS::EnvironmentBG background = RendererSceneRenderRD::get_singleton()->environment_get_background(p_env);

-   if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+   if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR || background == RS::ENV_BG_CANVAS) || sky) {
        ERR_FAIL_COND(!sky);
        sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));

@@ -1445,7 +1445,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p
        }
    }

-   if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+   if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR || background == RS::ENV_BG_CANVAS) {
        sky_material = sky_scene_state.fog_material;
        material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
    }
@@ -1536,7 +1536,7 @@ void SkyRD::draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_ren

    RS::EnvironmentBG background = RendererSceneRenderRD::get_singleton()->environment_get_background(p_env);

-   if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) {
+   if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR || background == RS::ENV_BG_CANVAS) || sky) {
        ERR_FAIL_COND(!sky);
        sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));

@@ -1553,7 +1553,7 @@ void SkyRD::draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_ren
        }
    }

-   if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+   if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR || background == RS::ENV_BG_CANVAS) {
        sky_material = sky_scene_state.fog_material;
        material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
    }
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index c7d85a3bbf..38feb848e5 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1773,6 +1773,12 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
                    copy_effects->copy_to_fb_rect(texture, color_only_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true);
                }
                keep_color = true;
+
+                if ((rb->has_custom_data(RB_SCOPE_FOG)) || environment_get_fog_enabled(p_render_data->environment)) {
+                    draw_sky_fog_only = true;
+                    clear_color.a = 0.0;
+                    RendererRD::MaterialStorage::get_singleton()->material_set_param(sky.sky_scene_state.fog_material, "clear_color", Variant(clear_color.srgb_to_linear()));
+                }
            } break;
            case RS::ENV_BG_KEEP: {
                keep_color = true;

After a few attempts, this is as far as I got. It works in the editor and renders the fog correctly, but it seems to be clearing over the canvas, despite keep_color.

I've also tried changing RD::INITIAL_ACTION_CLEAR to RD::INITIAL_ACTION_KEEP in sky.cpp with no luck.

clayjohn commented 1 year ago

@cridenour looks like the fog_material ignores alpha.

shader_type sky;

uniform vec4 clear_color;

void sky() {
    COLOR = clear_color.rgb;
}

Maybe the fix is as simple as adding ALPHA = clear_color.a?

cridenour commented 1 year ago

Maybe the fix is as simple as adding ALPHA = clear_color.a?

Unfortunately, no effect.

cridenour commented 1 year ago

Looking into it further, ALPHA is only available in a subpass (half or quarter mode) - so the sky shader will always draw the clear color in the main pass. I assume this is for a reason, does anyone know why?

Zireael07 commented 1 year ago

My first instinct is to say "performance"

cridenour commented 1 year ago

For those who may find this later, there is a workaround, though I can't say I understand the downsides yet.

Render your background to a SubViewport with Own World 3D enabled and change your WorldEnvironment to Sky and use a ShaderMaterial with the following shader:

shader_type sky;

uniform sampler2D viewport_texture : source_color;

void sky() {
    COLOR = texture(viewport_texture, SCREEN_UV).rgb;
}

Make sure your ShaderMaterial, Sky and WorldEnvironment are set to Local to scene and sync up your SubViewport size to your main scene's viewport size.