From 8f20638cd9157314dec8da330f6958d95cf5d653 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 23 Jan 2024 14:32:30 +0900 Subject: [PATCH] [vulkan] Implement deferred fog It's not perfect (double fog on translucent surfaces, the scatter/absorption isn't right, and no local lighting on the fog itself), but it at least seems to look ok. --- include/QF/Vulkan/qf_compose.h | 2 +- libs/video/renderer/Makemodule.am | 8 +++---- libs/video/renderer/vulkan/rp_main_def.plist | 16 ++++++++++++- .../video/renderer/vulkan/shader/compose.frag | 23 +++++++++++------- libs/video/renderer/vulkan/shader/fog.finc | 18 ++++++++++++++ libs/video/renderer/vulkan/shader/lighting.h | 1 + .../renderer/vulkan/shader/lighting_main.finc | 5 ++++ libs/video/renderer/vulkan/vulkan_compose.c | 16 ++++++++++--- libs/video/renderer/vulkan/vulkan_lighting.c | 24 ++++++++++++++++--- 9 files changed, 93 insertions(+), 20 deletions(-) diff --git a/include/QF/Vulkan/qf_compose.h b/include/QF/Vulkan/qf_compose.h index 699a28cfa..4c1a42adb 100644 --- a/include/QF/Vulkan/qf_compose.h +++ b/include/QF/Vulkan/qf_compose.h @@ -36,7 +36,7 @@ #include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/command.h" -#define COMPOSE_IMAGE_INFOS 3 +#define COMPOSE_IMAGE_INFOS 4 typedef struct composeframe_s { VkDescriptorImageInfo imageInfo[COMPOSE_IMAGE_INFOS]; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 09334bf81..a697663c9 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -469,13 +469,13 @@ $(light_debug_c): $(light_debug_src) $(lighting_h) $(light_oit_c): $(light_oit_src) $(lighting_h) -$(lighting_nonef_c): $(lighting_nonef_src) $(lighting_h) $(lighting_main) +$(lighting_nonef_c): $(lighting_nonef_src) $(lighting_h) $(lighting_main) $(fog_h) -$(lighting_cascadef_c): $(lighting_cascadef_src) $(lighting_h) $(lighting_main) +$(lighting_cascadef_c): $(lighting_cascadef_src) $(lighting_h) $(lighting_main) $(fog_h) -$(lighting_cubef_c): $(lighting_cubef_src) $(lighting_h) $(lighting_main) +$(lighting_cubef_c): $(lighting_cubef_src) $(lighting_h) $(lighting_main) $(fog_h) -$(lighting_planef_c): $(lighting_planef_src) $(lighting_h) $(lighting_main) +$(lighting_planef_c): $(lighting_planef_src) $(lighting_h) $(lighting_main) $(fog_h) $(composef_c): $(composef_src) $(oit_blend) $(oit_h) diff --git a/libs/video/renderer/vulkan/rp_main_def.plist b/libs/video/renderer/vulkan/rp_main_def.plist index 2b362dc18..1575c8d1c 100644 --- a/libs/video/renderer/vulkan/rp_main_def.plist +++ b/libs/video/renderer/vulkan/rp_main_def.plist @@ -708,6 +708,7 @@ properties = { lighting_attach, lighting_shadow); pushConstants = { fragment = { + fog = vec4; CascadeDepths = vec4; queue = uint; }; @@ -724,6 +725,12 @@ properties = { }; layout = { descriptorSets = (compose_attach, oit_set); + pushConstants = { + fragment = { + fog = vec4; + camera = vec4; + }; + }; }; }; output = { @@ -1053,6 +1060,12 @@ descriptorSetLayouts = { descriptorCount = 1; stageFlags = fragment; }, + { + binding = 3; + descriptorType = input_attachment; + descriptorCount = 1; + stageFlags = fragment; + }, ); }; particle_set = { @@ -1884,6 +1897,7 @@ renderpasses = { color = shader_read_only_optimal; light = shader_read_only_optimal; emission = shader_read_only_optimal; + position = shader_read_only_optimal; }; color = { output = { @@ -1891,7 +1905,7 @@ renderpasses = { blend = $additive_blend; }; }; - preserve = (depth, normal, position); + preserve = (depth, normal); }; pipelines = { compose = { diff --git a/libs/video/renderer/vulkan/shader/compose.frag b/libs/video/renderer/vulkan/shader/compose.frag index 441b9c9d9..4f7a20d7d 100644 --- a/libs/video/renderer/vulkan/shader/compose.frag +++ b/libs/video/renderer/vulkan/shader/compose.frag @@ -5,24 +5,31 @@ #define OIT_SET 1 #include "oit_blend.finc" +#include "fog.finc" + +layout (push_constant) uniform PushConstants { + vec4 fog; + vec4 camera; +}; + layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput color; layout (input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput light; layout (input_attachment_index = 2, set = 0, binding = 2) uniform subpassInput emission; +layout (input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput position; layout (location = 0) out vec4 frag_color; void main (void) { - vec3 c; - vec3 l; - vec3 e; - vec3 o; + vec3 c = subpassLoad (color).rgb; + vec3 l = subpassLoad (light).rgb; + vec3 e = subpassLoad (emission).rgb; + vec3 p = subpassLoad (position).xyz; + vec3 o = max(BlendFrags (vec4 (c * l + e, 1)).xyz, vec3(0)); - c = subpassLoad (color).rgb; - l = subpassLoad (light).rgb; - e = subpassLoad (emission).rgb; - o = max(BlendFrags (vec4 (c * l + e, 1)).xyz, vec3(0)); + float d = length (p - camera.xyz); + o = FogBlend (vec4(o,1), fog, d).xyz; o = pow (o, vec3(0.83));//FIXME make gamma correction configurable frag_color = vec4 (o, 1); } diff --git a/libs/video/renderer/vulkan/shader/fog.finc b/libs/video/renderer/vulkan/shader/fog.finc index e9f1d37c8..f9aa723d4 100644 --- a/libs/video/renderer/vulkan/shader/fog.finc +++ b/libs/video/renderer/vulkan/shader/fog.finc @@ -7,3 +7,21 @@ FogBlend (vec4 color, vec4 fog) float fog_factor = exp (-az); return mix (fog_color, color, fog_factor); } + +vec4 +FogBlend (vec4 color, vec4 fog, float dist) +{ + float az = fog.a * dist; + vec4 fog_color = vec4 (fog.rgb, 1.0); + + float fog_factor = exp (-az); + return mix (fog_color, color, fog_factor); +} + +vec4 +FogTransmit (vec4 color, vec4 fog, float dist) +{ + float az = fog.a * dist; + vec3 fog_color = exp (-az * fog.rgb); + return vec4 (color.rgb * fog_color, color.a); +} diff --git a/libs/video/renderer/vulkan/shader/lighting.h b/libs/video/renderer/vulkan/shader/lighting.h index 2c244bd9b..4919c3975 100644 --- a/libs/video/renderer/vulkan/shader/lighting.h +++ b/libs/video/renderer/vulkan/shader/lighting.h @@ -35,6 +35,7 @@ layout (set = 1, binding = 4) buffer LightEntIds { }; layout (push_constant) uniform PushConstants { + vec4 fog; vec4 CascadeDepths; uint queue; }; diff --git a/libs/video/renderer/vulkan/shader/lighting_main.finc b/libs/video/renderer/vulkan/shader/lighting_main.finc index df31b46f6..4a32c9b85 100644 --- a/libs/video/renderer/vulkan/shader/lighting_main.finc +++ b/libs/video/renderer/vulkan/shader/lighting_main.finc @@ -21,6 +21,8 @@ diffuse (vec3 incoming, vec3 normal) return clamp (lightdot, 0, 1); } +#include "fog.finc" + void main (void) { @@ -61,6 +63,9 @@ main (void) if (bitfieldExtract(id_data, 31, 1) == 0) { col *= style[renderer[id].style]; } + if (fog.w > 0) { + col = FogTransmit (col, fog, r[1]); + } light += I * col.w * col.xyz; } //light = max (light, minLight); diff --git a/libs/video/renderer/vulkan/vulkan_compose.c b/libs/video/renderer/vulkan/vulkan_compose.c index 4be2d3955..2b13e1eda 100644 --- a/libs/video/renderer/vulkan/vulkan_compose.c +++ b/libs/video/renderer/vulkan/vulkan_compose.c @@ -87,11 +87,21 @@ compose_draw (const exprval_t **params, exprval_t *result, exprctx_t *ectx) cframe->imageInfo[0].imageView = fb->views[QFV_attachColor]; cframe->imageInfo[1].imageView = fb->views[QFV_attachLight]; cframe->imageInfo[2].imageView = fb->views[QFV_attachEmission]; - dfunc->vkUpdateDescriptorSets (device->dev, 1, - cframe->descriptors, 0, 0); - if (!color_only) { + cframe->imageInfo[3].imageView = fb->views[QFV_attachPosition]; + if (color_only) { + dfunc->vkUpdateDescriptorSets (device->dev, 1, + cframe->descriptors, 0, 0); + } else { dfunc->vkUpdateDescriptorSets (device->dev, COMPOSE_IMAGE_INFOS, cframe->descriptors, 0, 0); + + vec4f_t fog = Fog_Get (); + vec4f_t cam = r_refdef.camera[3]; + qfv_push_constants_t push_constants[] = { + { VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof (fog), &fog }, + { VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(fog), sizeof (cam), &cam }, + }; + QFV_PushConstants (device, cmd, layout, 2, push_constants); } VkDescriptorSet sets[] = { diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index 4b7558aa6..8419d8194 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -1296,6 +1296,12 @@ lighting_draw_hulls (const exprval_t **params, exprval_t *result, } } +typedef struct { + vec4f_t fog; + vec4f_t CascadeDepths; + uint32_t queue; +} light_push_constants_t; + static void lighting_draw_lights (const exprval_t **params, exprval_t *result, exprctx_t *ectx) @@ -1317,15 +1323,27 @@ lighting_draw_lights (const exprval_t **params, exprval_t *result, return; } + vec4f_t fog = Fog_Get (); + // convert scatter to transmission (FIXME ignoring absorbtion) + fog = (vec4f_t) { 1, 1, 1, 0 } - fog; + fog[3] = -fog[3]; + //FIXME dup of z_range (sort of) vec4f_t depths = { r_nearclip / 32, r_nearclip / 256, r_nearclip / 1024, 0, }; qfv_push_constants_t push_constants[] = { - { VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof (depths), &depths }, - { VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(depths), sizeof(queue), &queue }, + { VK_SHADER_STAGE_FRAGMENT_BIT, + field_offset (light_push_constants_t, fog), + sizeof (fog), &fog }, + { VK_SHADER_STAGE_FRAGMENT_BIT, + field_offset (light_push_constants_t, CascadeDepths), + sizeof (depths), &depths }, + { VK_SHADER_STAGE_FRAGMENT_BIT, + field_offset (light_push_constants_t, queue), + sizeof (queue), &queue }, }; - QFV_PushConstants (device, cmd, layout, 2, push_constants); + QFV_PushConstants (device, cmd, layout, 3, push_constants); dfunc->vkCmdDraw (cmd, 3, 1, 0, 0); }