[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.
This commit is contained in:
Bill Currie 2024-01-23 14:32:30 +09:00
parent 60cb5a922a
commit 8f20638cd9
9 changed files with 93 additions and 20 deletions

View file

@ -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];

View file

@ -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)

View file

@ -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 = {

View file

@ -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);
}

View file

@ -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);
}

View file

@ -35,6 +35,7 @@ layout (set = 1, binding = 4) buffer LightEntIds {
};
layout (push_constant) uniform PushConstants {
vec4 fog;
vec4 CascadeDepths;
uint queue;
};

View file

@ -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);

View file

@ -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[] = {

View file

@ -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);
}