2021-11-05 20:08:15 +01:00
|
|
|
|
#version 460
|
2024-01-08 18:03:56 +01:00
|
|
|
|
#include "debug.glsl"
|
2022-01-12 03:13:59 +01:00
|
|
|
|
#include "utils.glsl"
|
2022-03-23 00:40:35 +01:00
|
|
|
|
#include "color_spaces.glsl"
|
2021-11-07 21:46:27 +01:00
|
|
|
|
|
2023-01-30 05:53:18 +01:00
|
|
|
|
#define GLSL
|
|
|
|
|
#include "ray_interop.h"
|
|
|
|
|
#undef GLSL
|
|
|
|
|
|
2022-01-23 03:54:11 +01:00
|
|
|
|
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
2021-11-05 20:08:15 +01:00
|
|
|
|
|
2022-11-05 20:33:07 +01:00
|
|
|
|
layout(set = 0, binding = 0, rgba16f) uniform image2D out_dest;
|
2021-11-09 19:59:36 +01:00
|
|
|
|
|
2022-11-05 20:33:07 +01:00
|
|
|
|
layout(set = 0, binding = 1, rgba8) uniform readonly image2D base_color_a;
|
2022-01-28 04:14:56 +01:00
|
|
|
|
|
2022-11-05 20:33:07 +01:00
|
|
|
|
layout(set = 0, binding = 2, rgba16f) uniform readonly image2D light_poly_diffuse;
|
|
|
|
|
layout(set = 0, binding = 3, rgba16f) uniform readonly image2D light_poly_specular;
|
2022-01-28 04:14:56 +01:00
|
|
|
|
|
2022-11-05 20:33:07 +01:00
|
|
|
|
layout(set = 0, binding = 4, rgba16f) uniform readonly image2D light_point_diffuse;
|
|
|
|
|
layout(set = 0, binding = 5, rgba16f) uniform readonly image2D light_point_specular;
|
|
|
|
|
layout(set = 0, binding = 6, rgba16f) uniform readonly image2D emissive;
|
2022-01-28 04:14:56 +01:00
|
|
|
|
|
2023-01-30 20:31:46 +01:00
|
|
|
|
layout(set = 0, binding = 7, rgba32f) uniform readonly image2D position_t;
|
|
|
|
|
layout(set = 0, binding = 8, rgba16f) uniform readonly image2D normals_gs;
|
2023-12-11 17:48:44 +01:00
|
|
|
|
layout(set = 0, binding = 9, rgba8) uniform readonly image2D material_rmxx;
|
2023-02-01 21:01:34 +01:00
|
|
|
|
layout(set = 0, binding = 10, rgba32f) uniform readonly image2D geometry_prev_position;
|
2023-01-30 05:53:18 +01:00
|
|
|
|
|
2023-02-01 21:01:34 +01:00
|
|
|
|
layout(set = 0, binding = 11) uniform UBO { UniformBuffer ubo; } ubo;
|
2023-01-22 00:45:29 +01:00
|
|
|
|
|
2023-02-07 19:46:57 +01:00
|
|
|
|
layout(set = 0, binding = 12, rgba16f) uniform readonly image2D indirect_diffuse;
|
2024-02-01 16:36:34 +01:00
|
|
|
|
layout(set = 0, binding = 13, rgba16f) uniform readonly image2D indirect_diffuse_atrous1;
|
|
|
|
|
layout(set = 0, binding = 14, rgba16f) uniform readonly image2D indirect_specular;
|
2023-02-07 19:46:57 +01:00
|
|
|
|
|
2024-02-01 16:36:34 +01:00
|
|
|
|
layout(set = 0, binding = 15, rgba16f) uniform image2D out_temporal_diffuse;
|
|
|
|
|
layout(set = 0, binding = 16, rgba16f) uniform image2D prev_temporal_diffuse;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2024-02-01 16:36:34 +01:00
|
|
|
|
layout(set = 0, binding = 17, rgba16f) uniform image2D out_temporal_specular;
|
|
|
|
|
layout(set = 0, binding = 18, rgba16f) uniform image2D prev_temporal_specular;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2023-10-30 18:51:23 +01:00
|
|
|
|
//#define DEBUG_NOISE
|
2023-09-11 18:31:03 +02:00
|
|
|
|
#ifdef DEBUG_NOISE
|
2024-02-01 16:36:34 +01:00
|
|
|
|
layout(set = 0, binding = 19) uniform sampler3D blue_noise_texture;
|
2023-10-30 18:51:23 +01:00
|
|
|
|
#include "bluenoise.glsl"
|
2023-09-11 18:31:03 +02:00
|
|
|
|
#endif
|
2023-09-05 19:06:00 +02:00
|
|
|
|
|
2024-02-01 16:36:34 +01:00
|
|
|
|
layout(set = 0, binding = 20, rgba16f) uniform readonly image2D legacy_blend;
|
2023-12-29 18:04:38 +01:00
|
|
|
|
|
2024-02-01 16:36:34 +01:00
|
|
|
|
//layout(set = 0, binding = 21) uniform sampler2D textures[MAX_TEXTURES];
|
2023-09-05 19:06:00 +02:00
|
|
|
|
|
2024-02-01 16:36:34 +01:00
|
|
|
|
#include "atrous.glsl"
|
2023-10-10 19:32:04 +02:00
|
|
|
|
|
2023-02-11 21:12:57 +01:00
|
|
|
|
const int INDIRECT_SCALE = 2;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2021-11-07 19:07:01 +01:00
|
|
|
|
// Blatantly copypasted from https://www.shadertoy.com/view/XsGfWV
|
|
|
|
|
vec3 aces_tonemap(vec3 color){
|
|
|
|
|
mat3 m1 = mat3(
|
|
|
|
|
0.59719, 0.07600, 0.02840,
|
|
|
|
|
0.35458, 0.90834, 0.13383,
|
|
|
|
|
0.04823, 0.01566, 0.83777
|
|
|
|
|
);
|
|
|
|
|
mat3 m2 = mat3(
|
|
|
|
|
1.60475, -0.10208, -0.00327,
|
|
|
|
|
-0.53108, 1.10813, -0.07276,
|
|
|
|
|
-0.07367, -0.00605, 1.07602
|
|
|
|
|
);
|
|
|
|
|
vec3 v = m1 * color;
|
|
|
|
|
vec3 a = v * (v + 0.0245786) - 0.000090537;
|
|
|
|
|
vec3 b = v * (0.983729 * v + 0.4329510) + 0.238081;
|
2021-12-20 21:26:29 +01:00
|
|
|
|
//return pow(clamp(m2 * (a / b), 0.0, 1.0), vec3(1.0 / 2.2));
|
|
|
|
|
return clamp(m2 * (a / b), 0.0, 1.0);
|
2021-11-07 19:07:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-20 22:40:33 +01:00
|
|
|
|
vec3 reinhard(vec3 color){
|
|
|
|
|
return color / (color + 1.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec3 reinhard02(vec3 c, vec3 Cwhite2) {
|
|
|
|
|
return c * (1. + c / Cwhite2) / (1. + c);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-12 18:40:08 +01:00
|
|
|
|
float normpdf2(in float x2, in float sigma) { return 0.39894*exp(-0.5*x2/(sigma*sigma))/sigma; }
|
|
|
|
|
float normpdf(in float x, in float sigma) { return normpdf2(x*x, sigma); }
|
|
|
|
|
|
2022-02-05 03:38:36 +01:00
|
|
|
|
void readNormals(ivec2 uv, out vec3 geometry_normal, out vec3 shading_normal) {
|
2022-11-05 20:33:07 +01:00
|
|
|
|
const vec4 n = imageLoad(normals_gs, uv);
|
2022-02-05 03:38:36 +01:00
|
|
|
|
geometry_normal = normalDecode(n.xy);
|
|
|
|
|
shading_normal = normalDecode(n.zw);
|
|
|
|
|
}
|
2021-11-12 19:42:56 +01:00
|
|
|
|
|
2023-02-11 20:06:33 +01:00
|
|
|
|
struct Components {
|
|
|
|
|
vec3 direct_diffuse, direct_specular, indirect_diffuse, indirect_specular;
|
|
|
|
|
};
|
|
|
|
|
|
2024-01-26 17:24:49 +01:00
|
|
|
|
Components dontBlurSamples(const ivec2 res, const ivec2 pix) {
|
|
|
|
|
Components c;
|
|
|
|
|
c.direct_diffuse = c.direct_specular = c.indirect_diffuse = c.indirect_specular = vec3(0.);
|
|
|
|
|
const ivec2 p = pix;
|
|
|
|
|
const ivec2 p_indirect = pix / INDIRECT_SCALE;
|
|
|
|
|
c.direct_diffuse += imageLoad(light_point_diffuse, p).rgb;
|
|
|
|
|
c.direct_diffuse += imageLoad(light_poly_diffuse, p).rgb;
|
|
|
|
|
c.indirect_diffuse += imageLoad(indirect_diffuse, p_indirect).rgb;
|
|
|
|
|
c.direct_specular += imageLoad(light_poly_specular, p).rgb;
|
|
|
|
|
c.direct_specular += imageLoad(light_point_specular, p).rgb;
|
|
|
|
|
c.indirect_specular += imageLoad(indirect_specular, p_indirect).rgb;
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-26 18:50:08 +01:00
|
|
|
|
#define BOX_BLUR(out, tex, res, center, kernel_range) \
|
|
|
|
|
{ \
|
|
|
|
|
const float scale = 1. / pow(float(kernel_range * 2 + 1), 2.); \
|
|
|
|
|
for (int x = -kernel_range; x <= kernel_range; ++x) { \
|
|
|
|
|
for (int y = -kernel_range; y <= kernel_range; ++y) { \
|
|
|
|
|
const ivec2 p = center + ivec2(x, y); \
|
|
|
|
|
if (any(greaterThanEqual(p, res)) || any(lessThan(p, ivec2(0)))) \
|
|
|
|
|
continue; \
|
|
|
|
|
out += imageLoad(tex, p).rgb * scale; \
|
|
|
|
|
} /* for y */ \
|
|
|
|
|
} /* for x */ \
|
|
|
|
|
}
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2024-01-23 16:46:10 +01:00
|
|
|
|
#if 1
|
2023-02-11 20:36:45 +01:00
|
|
|
|
const int DIRECT_DIFFUSE_KERNEL = 3;
|
2023-12-05 17:14:25 +01:00
|
|
|
|
const int DIRECT_SPECULAR_KERNEL = 2;
|
2024-01-26 19:59:15 +01:00
|
|
|
|
const int INDIRECT_DIFFUSE_KERNEL = 5;
|
2023-12-05 17:14:25 +01:00
|
|
|
|
const int INDIRECT_SPECULAR_KERNEL = 2;
|
2024-01-23 16:46:10 +01:00
|
|
|
|
#else
|
|
|
|
|
const int DIRECT_DIFFUSE_KERNEL = 1;
|
|
|
|
|
const int DIRECT_SPECULAR_KERNEL = 1;
|
2024-01-26 19:59:15 +01:00
|
|
|
|
const int INDIRECT_DIFFUSE_KERNEL = 1;
|
2024-01-23 16:46:10 +01:00
|
|
|
|
const int INDIRECT_SPECULAR_KERNEL = 1;
|
|
|
|
|
#endif
|
2024-01-26 18:50:08 +01:00
|
|
|
|
|
|
|
|
|
Components boxBlurSamples(ivec2 res, ivec2 pix) {
|
|
|
|
|
Components c;
|
|
|
|
|
c.direct_diffuse = c.direct_specular = c.indirect_diffuse = c.indirect_specular = vec3(0.);
|
|
|
|
|
|
|
|
|
|
BOX_BLUR(c.direct_diffuse, light_poly_diffuse, res, pix, DIRECT_DIFFUSE_KERNEL);
|
|
|
|
|
BOX_BLUR(c.direct_diffuse, light_point_diffuse, res, pix, DIRECT_DIFFUSE_KERNEL);
|
|
|
|
|
|
|
|
|
|
BOX_BLUR(c.direct_specular, light_poly_specular, res, pix, DIRECT_SPECULAR_KERNEL);
|
|
|
|
|
BOX_BLUR(c.direct_specular, light_point_specular, res, pix, DIRECT_SPECULAR_KERNEL);
|
|
|
|
|
|
|
|
|
|
res /= 2;
|
|
|
|
|
pix /= 2;
|
|
|
|
|
BOX_BLUR(c.indirect_diffuse, indirect_diffuse, res, pix, INDIRECT_DIFFUSE_KERNEL);
|
|
|
|
|
BOX_BLUR(c.indirect_specular, indirect_specular, res, pix, INDIRECT_SPECULAR_KERNEL);
|
|
|
|
|
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-26 19:59:15 +01:00
|
|
|
|
Components blurATrous(const ivec2 res, const ivec2 pix, vec3 pos, vec3 shading_normal, vec3 geometry_normal) {
|
|
|
|
|
Components c;
|
|
|
|
|
c.direct_diffuse = c.direct_specular = c.indirect_diffuse = c.indirect_specular = vec3(0.);
|
|
|
|
|
|
2024-01-29 18:49:32 +01:00
|
|
|
|
float weight_total_diffuse = 0.;
|
|
|
|
|
float weight_total_specular = 0.;
|
|
|
|
|
float weight_total_indirect_diffuse = 0.;
|
|
|
|
|
float weight_total_indirect_specular = 0.;
|
2024-02-01 16:36:34 +01:00
|
|
|
|
vec3 indirect_diffuse_c2 = vec3(0.);
|
2024-01-26 19:59:15 +01:00
|
|
|
|
const ivec2 res_scaled = res / INDIRECT_SCALE;
|
2024-01-29 18:49:32 +01:00
|
|
|
|
for (int x = 0; x <= ATROUS_KERNEL_WIDTH; ++x) {
|
|
|
|
|
for (int y = 0; y <= ATROUS_KERNEL_WIDTH; ++y) {
|
|
|
|
|
const ivec2 offset = ivec2(x, y);
|
|
|
|
|
// 1. Direct diffuse
|
|
|
|
|
{
|
|
|
|
|
const float sn_phi = .5;
|
|
|
|
|
const float p_phi = 2.;
|
|
|
|
|
const int step_width = 3;
|
|
|
|
|
ivec2 p;
|
|
|
|
|
const float weight = aTrousSampleWeigth(
|
2024-02-01 16:36:34 +01:00
|
|
|
|
res, pix, pos, shading_normal, offset, step_width, 1, sn_phi, p_phi, p);
|
2024-01-29 18:49:32 +01:00
|
|
|
|
|
|
|
|
|
if (weight > 0.) {
|
|
|
|
|
weight_total_diffuse += weight;
|
|
|
|
|
c.direct_diffuse +=
|
|
|
|
|
(imageLoad(light_poly_diffuse, p).rgb
|
|
|
|
|
+imageLoad(light_point_diffuse, p).rgb) * weight;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-26 19:59:15 +01:00
|
|
|
|
|
2024-01-29 18:49:32 +01:00
|
|
|
|
// 2. Direct specular
|
|
|
|
|
{
|
|
|
|
|
const float sn_phi = .5;
|
|
|
|
|
const float p_phi = 1.;
|
|
|
|
|
const int step_width = 1;
|
|
|
|
|
ivec2 p;
|
|
|
|
|
const float weight = aTrousSampleWeigth(
|
2024-02-01 16:36:34 +01:00
|
|
|
|
res, pix, pos, shading_normal, offset, step_width, 1, sn_phi, p_phi, p);
|
2024-01-29 18:49:32 +01:00
|
|
|
|
|
|
|
|
|
if (weight > 0.) {
|
|
|
|
|
weight_total_specular += weight;
|
|
|
|
|
c.direct_specular +=
|
|
|
|
|
(imageLoad(light_poly_specular, p).rgb
|
|
|
|
|
+imageLoad(light_point_specular, p).rgb) * weight;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-26 19:59:15 +01:00
|
|
|
|
|
2024-01-29 18:49:32 +01:00
|
|
|
|
// 3. Indirect diffuse
|
|
|
|
|
{
|
|
|
|
|
const float sn_phi = .5;
|
|
|
|
|
const float p_phi = 3.;
|
2024-02-01 16:36:34 +01:00
|
|
|
|
const int step_width = 2;
|
2024-01-29 18:49:32 +01:00
|
|
|
|
ivec2 p;
|
|
|
|
|
const float weight = aTrousSampleWeigth(
|
2024-02-01 16:36:34 +01:00
|
|
|
|
res, pix, pos, shading_normal, offset, step_width, 1, sn_phi, p_phi, p);
|
2024-01-29 18:49:32 +01:00
|
|
|
|
|
|
|
|
|
if (weight > 0.) {
|
2024-02-01 16:36:34 +01:00
|
|
|
|
const ivec2 p_scaled = p / INDIRECT_SCALE;
|
|
|
|
|
const bool do_indirect = all(lessThan(p_scaled, res_scaled));
|
2024-01-29 18:49:32 +01:00
|
|
|
|
if (do_indirect) {
|
|
|
|
|
weight_total_indirect_diffuse += weight;
|
2024-02-01 16:36:34 +01:00
|
|
|
|
indirect_diffuse_c2 += imageLoad(indirect_diffuse_atrous1, p_scaled).rgb * weight;
|
2024-01-29 18:49:32 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-26 19:59:15 +01:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-29 18:49:32 +01:00
|
|
|
|
// 4. Indirect specular
|
|
|
|
|
{
|
|
|
|
|
const float sn_phi = .5;
|
|
|
|
|
const float p_phi = 1.;
|
|
|
|
|
const int step_width = 1;
|
|
|
|
|
ivec2 p;
|
|
|
|
|
const float weight = aTrousSampleWeigth(
|
2024-02-01 16:36:34 +01:00
|
|
|
|
res, pix, pos, shading_normal, offset, step_width, 1, sn_phi, p_phi, p);
|
2024-01-29 18:49:32 +01:00
|
|
|
|
|
|
|
|
|
if (weight > 0.) {
|
2024-02-01 16:36:34 +01:00
|
|
|
|
const ivec2 p_scaled = p / INDIRECT_SCALE;
|
|
|
|
|
const bool do_indirect = all(lessThan(p_scaled, res_scaled));
|
2024-01-29 18:49:32 +01:00
|
|
|
|
if (do_indirect) {
|
|
|
|
|
weight_total_indirect_specular += weight;
|
2024-02-01 16:36:34 +01:00
|
|
|
|
c.indirect_specular += imageLoad(indirect_specular, p_scaled).rgb * weight;
|
2024-01-29 18:49:32 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-26 19:59:15 +01:00
|
|
|
|
}
|
|
|
|
|
} // for y
|
|
|
|
|
} // for x
|
|
|
|
|
|
2024-01-29 18:49:32 +01:00
|
|
|
|
const float one_over_weight_diffuse = 1. / weight_total_diffuse;
|
|
|
|
|
const float one_over_weight_specular = 1. / weight_total_specular;
|
|
|
|
|
const float one_over_weight_indirect_diffuse = 1. / weight_total_indirect_diffuse;
|
|
|
|
|
const float one_over_weight_indirect_specular = 1. / weight_total_indirect_specular;
|
|
|
|
|
c.direct_diffuse *= one_over_weight_diffuse;
|
|
|
|
|
c.direct_specular *= one_over_weight_specular;
|
|
|
|
|
|
2024-02-01 16:36:34 +01:00
|
|
|
|
indirect_diffuse_c2 *= one_over_weight_indirect_diffuse;
|
2024-01-29 18:49:32 +01:00
|
|
|
|
c.indirect_specular *= one_over_weight_indirect_specular;
|
2024-02-01 16:36:34 +01:00
|
|
|
|
|
|
|
|
|
const vec3 indirect_diffuse_c0 = imageLoad(indirect_diffuse, pix / INDIRECT_SCALE).rgb;
|
|
|
|
|
const vec3 indirect_diffuse_c1 = imageLoad(indirect_diffuse_atrous1, pix / INDIRECT_SCALE).rgb;
|
|
|
|
|
const vec3 d0 = indirect_diffuse_c1 - indirect_diffuse_c0;
|
|
|
|
|
const vec3 d1 = indirect_diffuse_c2 - indirect_diffuse_c1;
|
|
|
|
|
|
|
|
|
|
// TODO(or not todo): The Á-Trous paper mentions that it should be c2 + d1 + d0, but
|
|
|
|
|
// it gives horrible artifacts. Either I'm misreading the paper, or something else is broken here,
|
|
|
|
|
// Using just c2 seems fine enough (although still not up to original paper image quality)
|
|
|
|
|
c.indirect_diffuse = indirect_diffuse_c2;// + d1 + d0;
|
2024-01-26 19:59:15 +01:00
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-26 18:50:08 +01:00
|
|
|
|
Components blurSamples(const ivec2 res, const ivec2 pix) {
|
|
|
|
|
Components c;
|
|
|
|
|
c.direct_diffuse = c.direct_specular = c.indirect_diffuse = c.indirect_specular = vec3(0.);
|
|
|
|
|
|
|
|
|
|
const vec4 center_pos = imageLoad(position_t, pix);
|
|
|
|
|
|
2023-12-05 17:14:25 +01:00
|
|
|
|
const int KERNEL_SIZE = max(max(max(DIRECT_DIFFUSE_KERNEL, INDIRECT_DIFFUSE_KERNEL), DIRECT_SPECULAR_KERNEL), INDIRECT_SPECULAR_KERNEL);
|
2023-02-11 20:36:45 +01:00
|
|
|
|
|
|
|
|
|
const float direct_diffuse_sigma = DIRECT_DIFFUSE_KERNEL / 2.;
|
|
|
|
|
const float indirect_diffuse_sigma = INDIRECT_DIFFUSE_KERNEL / 2.;
|
2023-12-05 17:14:25 +01:00
|
|
|
|
const float direct_specular_sigma = DIRECT_SPECULAR_KERNEL / 2.;
|
|
|
|
|
const float indirect_specular_sigma = INDIRECT_SPECULAR_KERNEL / 2.;
|
2023-02-11 20:36:45 +01:00
|
|
|
|
|
|
|
|
|
float direct_diffuse_total = 0.;
|
|
|
|
|
float indirect_diffuse_total = 0.;
|
2023-12-05 17:14:25 +01:00
|
|
|
|
float direct_specular_total = 0.;
|
|
|
|
|
float indirect_specular_total = 0.;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2023-02-11 21:12:57 +01:00
|
|
|
|
const ivec2 res_scaled = res / INDIRECT_SCALE;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
for (int x = -KERNEL_SIZE; x <= KERNEL_SIZE; ++x)
|
|
|
|
|
for (int y = -KERNEL_SIZE; y <= KERNEL_SIZE; ++y) {
|
|
|
|
|
const ivec2 p = pix + ivec2(x, y);
|
|
|
|
|
if (any(greaterThanEqual(p, res)) || any(lessThan(p, ivec2(0)))) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec3 sample_geometry_normal, sample_shading_normal;
|
|
|
|
|
readNormals(p, sample_geometry_normal, sample_shading_normal);
|
|
|
|
|
|
2023-02-11 20:36:45 +01:00
|
|
|
|
float scale = 1.f;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
// FIXME also filter by depth, (kusok index?), etc
|
|
|
|
|
//scale *= smoothstep(.9, 1., dot(sample_geometry_normal, geometry_normal));
|
|
|
|
|
|
|
|
|
|
const vec4 sample_pos = imageLoad(position_t, p);
|
|
|
|
|
// FIXME what are these magic numbers?
|
2023-02-11 21:12:57 +01:00
|
|
|
|
scale *= smoothstep(center_pos.w * 4. / 100., 0., distance(center_pos.xyz, sample_pos.xyz));
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
|
|
|
|
if ( scale <= 0. )
|
|
|
|
|
continue;
|
|
|
|
|
|
2023-12-04 18:14:44 +01:00
|
|
|
|
const ivec2 p_indirect = pix / INDIRECT_SCALE + ivec2(x, y);
|
|
|
|
|
const bool do_indirect = all(lessThan(p_indirect, res_scaled)) && all(greaterThanEqual(p_indirect, ivec2(0)));
|
|
|
|
|
|
2023-02-11 20:36:45 +01:00
|
|
|
|
if (all(lessThan(abs(ivec2(x, y)), ivec2(DIRECT_DIFFUSE_KERNEL))))
|
|
|
|
|
{
|
|
|
|
|
const float direct_diffuse_scale = scale * normpdf(x, direct_diffuse_sigma) * normpdf(y, direct_diffuse_sigma);
|
|
|
|
|
direct_diffuse_total += direct_diffuse_scale;
|
|
|
|
|
|
|
|
|
|
c.direct_diffuse += imageLoad(light_point_diffuse, p).rgb * direct_diffuse_scale;
|
|
|
|
|
c.direct_diffuse += imageLoad(light_poly_diffuse, p).rgb * direct_diffuse_scale;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-05 17:14:25 +01:00
|
|
|
|
if (all(lessThan(abs(ivec2(x, y)), ivec2(INDIRECT_DIFFUSE_KERNEL))) && do_indirect)
|
2023-02-11 20:36:45 +01:00
|
|
|
|
{
|
2023-12-04 18:14:44 +01:00
|
|
|
|
// TODO indirect operates at different scale, do a separate pass
|
2023-12-05 17:14:25 +01:00
|
|
|
|
const float indirect_diffuse_scale = scale
|
|
|
|
|
* normpdf(x, indirect_diffuse_sigma)
|
|
|
|
|
* normpdf(y, indirect_diffuse_sigma);
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2023-12-05 17:14:25 +01:00
|
|
|
|
indirect_diffuse_total += indirect_diffuse_scale;
|
|
|
|
|
c.indirect_diffuse += imageLoad(indirect_diffuse, p_indirect).rgb * indirect_diffuse_scale;
|
2023-02-11 20:36:45 +01:00
|
|
|
|
}
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2023-12-05 17:14:25 +01:00
|
|
|
|
if (all(lessThan(abs(ivec2(x, y)), ivec2(DIRECT_SPECULAR_KERNEL))))
|
2023-02-11 20:36:45 +01:00
|
|
|
|
{
|
2023-12-05 17:14:25 +01:00
|
|
|
|
const float specular_scale = scale * normpdf(x, direct_specular_sigma) * normpdf(y, direct_specular_sigma);
|
|
|
|
|
direct_specular_total += specular_scale;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2023-02-11 20:36:45 +01:00
|
|
|
|
c.direct_specular += imageLoad(light_poly_specular, p).rgb * specular_scale;
|
2024-01-09 18:05:31 +01:00
|
|
|
|
DEBUG_VALIDATE_VEC3(c.direct_specular, "%d c.direct_specular=(%f,%f,%f) poly");
|
2024-01-08 18:03:56 +01:00
|
|
|
|
|
2023-02-11 20:36:45 +01:00
|
|
|
|
c.direct_specular += imageLoad(light_point_specular, p).rgb * specular_scale;
|
2024-01-09 18:05:31 +01:00
|
|
|
|
DEBUG_VALIDATE_VEC3(c.direct_specular, "%d c.direct_specular=(%f,%f,%f) point");
|
2023-12-05 17:14:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (all(lessThan(abs(ivec2(x, y)), ivec2(INDIRECT_SPECULAR_KERNEL)))) {
|
|
|
|
|
const ivec2 p_indirect = (pix + ivec2(x, y)) / INDIRECT_SCALE;// + ivec2(x, y);
|
|
|
|
|
const bool do_indirect = all(lessThan(p_indirect, res_scaled)) && all(greaterThanEqual(p_indirect, ivec2(0)));
|
2023-02-11 21:12:57 +01:00
|
|
|
|
|
2023-12-04 18:14:44 +01:00
|
|
|
|
if (do_indirect) {
|
2023-12-05 17:14:25 +01:00
|
|
|
|
// TODO indirect operates at different scale, do a separate pass
|
|
|
|
|
const float specular_scale = scale * normpdf(x, indirect_specular_sigma) * normpdf(y, indirect_specular_sigma);
|
|
|
|
|
indirect_specular_total += specular_scale;
|
2023-12-04 18:14:44 +01:00
|
|
|
|
c.indirect_specular += imageLoad(indirect_specular, p_indirect).rgb * specular_scale;
|
|
|
|
|
}
|
2023-02-11 20:36:45 +01:00
|
|
|
|
}
|
2023-02-11 20:06:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-11 20:36:45 +01:00
|
|
|
|
if (direct_diffuse_total > 0.)
|
|
|
|
|
c.direct_diffuse /= direct_diffuse_total;
|
|
|
|
|
|
|
|
|
|
if (indirect_diffuse_total > 0.)
|
|
|
|
|
c.indirect_diffuse *= indirect_diffuse_total;
|
|
|
|
|
|
2024-01-09 18:05:31 +01:00
|
|
|
|
#ifdef DEBUG_VALIDATE_EXTRA
|
2024-01-16 18:29:15 +01:00
|
|
|
|
if (IS_INVALIDV(c.direct_specular)) {
|
2024-01-08 18:03:56 +01:00
|
|
|
|
debugPrintfEXT("c.direct_specular=(%f,%f,%f)", PRIVEC3(c.direct_specular));
|
|
|
|
|
c.direct_specular = vec3(0.);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IS_INVALID(direct_specular_total)) {
|
|
|
|
|
debugPrintfEXT("direct_specular_total=%f", direct_specular_total);
|
|
|
|
|
direct_specular_total = 0.;
|
|
|
|
|
}
|
2024-01-09 18:05:31 +01:00
|
|
|
|
#endif
|
2024-01-08 18:03:56 +01:00
|
|
|
|
|
2023-12-05 17:14:25 +01:00
|
|
|
|
if (direct_specular_total > 0.)
|
|
|
|
|
c.direct_specular *= direct_specular_total;
|
|
|
|
|
|
|
|
|
|
if (indirect_specular_total > 0.)
|
|
|
|
|
c.indirect_specular *= indirect_specular_total;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
|
2024-01-09 18:05:31 +01:00
|
|
|
|
#ifdef DEBUG_VALIDATE_EXTRA
|
2024-01-16 18:29:15 +01:00
|
|
|
|
if (IS_INVALIDV(c.indirect_specular)) {
|
2024-01-08 18:03:56 +01:00
|
|
|
|
debugPrintfEXT("c.indirect_specular=(%f,%f,%f)", PRIVEC3(c.indirect_specular));
|
|
|
|
|
c.indirect_specular = vec3(0.);
|
|
|
|
|
}
|
2024-01-09 18:05:31 +01:00
|
|
|
|
#endif
|
2024-01-08 18:03:56 +01:00
|
|
|
|
|
2023-02-11 20:06:33 +01:00
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-05 20:08:15 +01:00
|
|
|
|
void main() {
|
2023-11-30 19:01:40 +01:00
|
|
|
|
const ivec2 res = ubo.ubo.res;
|
|
|
|
|
const ivec2 pix = ivec2(gl_GlobalInvocationID);
|
2021-11-05 20:08:15 +01:00
|
|
|
|
|
2021-11-07 21:46:27 +01:00
|
|
|
|
if (any(greaterThanEqual(pix, res))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-26 19:59:15 +01:00
|
|
|
|
const vec3 position = imageLoad(position_t, pix).xyz;
|
|
|
|
|
vec3 geometry_normal, shading_normal;
|
|
|
|
|
readNormals(pix, geometry_normal, shading_normal);
|
|
|
|
|
|
2023-11-03 15:58:13 +01:00
|
|
|
|
if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_DISABLED) {
|
|
|
|
|
// no-op, just continue
|
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_BASECOLOR) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(imageLoad(base_color_a, pix).rgb), 0.)); return;
|
|
|
|
|
return;
|
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_BASEALPHA) {
|
|
|
|
|
imageStore(out_dest, pix, imageLoad(base_color_a, pix).aaaa); return;
|
|
|
|
|
return;
|
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_EMISSIVE) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(imageLoad(emissive, pix).rgb), 0.)); return;
|
|
|
|
|
return;
|
2024-01-11 17:56:23 +01:00
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_MATERIAL) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(imageLoad(material_rmxx, pix).rg, 0., 0.)); return;
|
|
|
|
|
return;
|
2023-11-03 15:58:13 +01:00
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_NSHADE) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(.5 + shading_normal * .5, 0.));
|
|
|
|
|
return;
|
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_NGEOM) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(.5 + geometry_normal * .5, 0.));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-11 18:31:03 +02:00
|
|
|
|
#ifdef DEBUG_NOISE
|
|
|
|
|
imageStore(out_dest, pix, blueNoise(ivec3(pix.xy, ubo.ubo.frame_counter))); return;
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-01-26 18:50:08 +01:00
|
|
|
|
//const Components c = blurSamples(res, pix);
|
2024-01-26 19:59:15 +01:00
|
|
|
|
//const Components c = boxBlurSamples(res, pix);
|
2024-01-26 17:24:49 +01:00
|
|
|
|
//const Components c = dontBlurSamples(res, pix);
|
2024-01-26 19:59:15 +01:00
|
|
|
|
const Components c = blurATrous(res, pix, position, shading_normal, geometry_normal);
|
2021-11-07 21:46:27 +01:00
|
|
|
|
|
2023-11-06 18:47:21 +01:00
|
|
|
|
if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_DISABLED) {
|
2024-01-26 16:34:46 +01:00
|
|
|
|
// Skip
|
2023-11-06 18:47:21 +01:00
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_DIRECT) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(c.direct_diffuse + c.direct_specular), 0.)); return;
|
|
|
|
|
return;
|
2024-01-02 19:32:49 +01:00
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_DIRECT_DIFF) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(c.direct_diffuse), 0.)); return;
|
|
|
|
|
return;
|
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_DIRECT_SPEC) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(c.direct_specular), 0.)); return;
|
|
|
|
|
return;
|
2023-11-06 18:47:21 +01:00
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_INDIRECT) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(c.indirect_diffuse + c.indirect_specular), 0.)); return;
|
|
|
|
|
return;
|
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_INDIRECT_SPEC) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(c.indirect_specular), 0.)); return;
|
|
|
|
|
return;
|
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_INDIRECT_DIFF) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(c.indirect_diffuse), 0.)); return;
|
|
|
|
|
return;
|
2024-01-26 20:02:19 +01:00
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_DIFFUSE) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(c.indirect_diffuse + c.direct_diffuse), 0.)); return;
|
|
|
|
|
return;
|
|
|
|
|
} else if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_SPECULAR) {
|
|
|
|
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(c.indirect_specular + c.direct_specular), 0.)); return;
|
|
|
|
|
return;
|
2023-11-06 18:47:21 +01:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-11 17:48:44 +01:00
|
|
|
|
vec3 diffuse = c.direct_diffuse + c.indirect_diffuse;
|
|
|
|
|
vec3 specular = c.direct_specular + c.indirect_specular;
|
2023-02-11 20:06:33 +01:00
|
|
|
|
{
|
2023-11-21 18:10:14 +01:00
|
|
|
|
//#define DISABLE_TEMPORAL_DENOISER
|
|
|
|
|
#ifndef DISABLE_TEMPORAL_DENOISER
|
2023-02-11 20:06:33 +01:00
|
|
|
|
// TODO: need to extract reprojecting from this shader because reprojected stuff need svgf denoising pass after it
|
|
|
|
|
const vec3 origin = (ubo.ubo.inv_view * vec4(0., 0., 0., 1.)).xyz;
|
2023-11-02 17:23:33 +01:00
|
|
|
|
const float depth = length(origin - position);
|
2023-02-11 20:06:33 +01:00
|
|
|
|
const vec3 prev_position = imageLoad(geometry_prev_position, pix).rgb;
|
|
|
|
|
const vec4 clip_space = inverse(ubo.ubo.prev_inv_proj) * vec4((inverse(ubo.ubo.prev_inv_view) * vec4(prev_position, 1.)).xyz, 1.);
|
|
|
|
|
const vec2 reproj_uv = clip_space.xy / clip_space.w;
|
|
|
|
|
const ivec2 reproj_pix = ivec2((reproj_uv * 0.5 + vec2(0.5)) * vec2(res));
|
|
|
|
|
const vec3 prev_origin = (ubo.ubo.prev_inv_view * vec4(0., 0., 0., 1.)).xyz;
|
|
|
|
|
const float depth_nessesary = length(prev_position - prev_origin);
|
|
|
|
|
const float depth_treshold = 0.01 * clip_space.w;
|
|
|
|
|
|
|
|
|
|
float better_depth_offset = depth_treshold;
|
|
|
|
|
vec3 history_diffuse = diffuse;
|
|
|
|
|
vec3 history_specular = specular;
|
2023-02-11 20:36:45 +01:00
|
|
|
|
const int TEMPORAL_KERNEL = 1; // lifekilled says it should be fixed
|
|
|
|
|
for(int x = -TEMPORAL_KERNEL; x <=TEMPORAL_KERNEL; x++) {
|
|
|
|
|
for(int y = -TEMPORAL_KERNEL; y <=TEMPORAL_KERNEL; y++) {
|
2023-02-11 20:06:33 +01:00
|
|
|
|
const ivec2 p = reproj_pix + ivec2(x, y);
|
|
|
|
|
if (any(greaterThanEqual(p, res)) || any(lessThan(p, ivec2(0)))) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-12-04 18:14:44 +01:00
|
|
|
|
|
|
|
|
|
if (any(greaterThanEqual(reproj_pix, res)) || any(lessThan(reproj_pix, ivec2(0)))) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-02-11 20:06:33 +01:00
|
|
|
|
const vec4 history_diffuse_depth = imageLoad( prev_temporal_diffuse, reproj_pix );
|
|
|
|
|
const vec4 history_specular_sample = imageLoad( prev_temporal_specular, reproj_pix );
|
|
|
|
|
|
|
|
|
|
const float history_depth = history_diffuse_depth.w;
|
|
|
|
|
const float depth_offset = abs(history_depth - depth_nessesary);
|
|
|
|
|
if ( depth_offset < better_depth_offset ) {
|
|
|
|
|
better_depth_offset = depth_offset;
|
|
|
|
|
history_diffuse = history_diffuse_depth.rgb;
|
|
|
|
|
history_specular = history_specular_sample.rgb;
|
|
|
|
|
}
|
2021-11-12 19:43:14 +01:00
|
|
|
|
}
|
2021-11-07 21:46:27 +01:00
|
|
|
|
}
|
2024-01-08 18:03:56 +01:00
|
|
|
|
|
2024-01-09 18:05:31 +01:00
|
|
|
|
#ifdef DEBUG_VALIDATE_EXTRA
|
2024-01-16 18:29:15 +01:00
|
|
|
|
if (IS_INVALIDV(history_specular)) {
|
2024-01-08 18:03:56 +01:00
|
|
|
|
debugPrintfEXT("PRE pix=(%d,%d) history_specular=inv", pix.x, pix.y);
|
|
|
|
|
history_specular = vec3(0.);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-16 18:29:15 +01:00
|
|
|
|
if (IS_INVALIDV(specular)) {
|
2024-01-08 18:03:56 +01:00
|
|
|
|
debugPrintfEXT("PRE pix=(%d,%d) specular=(%f,%f,%f)", pix.x, pix.y, PRIVEC3(specular));
|
|
|
|
|
specular = vec3(0.);
|
|
|
|
|
}
|
2024-01-09 18:05:31 +01:00
|
|
|
|
#endif
|
2024-01-08 18:03:56 +01:00
|
|
|
|
|
2023-02-11 20:06:33 +01:00
|
|
|
|
if (better_depth_offset < depth_treshold) {
|
|
|
|
|
diffuse = mix(diffuse, history_diffuse, 0.8);
|
2024-01-09 18:05:31 +01:00
|
|
|
|
specular = mix(specular, history_specular, 0.3);
|
2024-01-08 18:03:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-09 18:05:31 +01:00
|
|
|
|
#ifdef DEBUG_VALIDATE_EXTRA
|
2024-01-16 18:29:15 +01:00
|
|
|
|
if (IS_INVALIDV(diffuse)) {
|
2024-01-08 18:03:56 +01:00
|
|
|
|
debugPrintfEXT("pix=(%d,%d) diffuse=inv", pix.x, pix.y);
|
|
|
|
|
diffuse = vec3(0.);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-16 18:29:15 +01:00
|
|
|
|
if (IS_INVALIDV(specular)) {
|
2024-01-08 18:03:56 +01:00
|
|
|
|
debugPrintfEXT("pix=(%d,%d) new_specular=inv, specular=(%f, %f, %f) history_specular=(%f, %f, %f)",
|
|
|
|
|
pix.x, pix.y,
|
|
|
|
|
specular.r, specular.g, specular.b,
|
|
|
|
|
history_specular.r, history_specular.g, history_specular.b
|
|
|
|
|
);
|
2024-01-09 18:05:31 +01:00
|
|
|
|
specular = vec3(0.);
|
2023-02-11 20:06:33 +01:00
|
|
|
|
}
|
2024-01-09 18:05:31 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2024-01-12 19:31:02 +01:00
|
|
|
|
DEBUG_VALIDATE_RANGE_VEC3("denoiser.diffuse", diffuse, 0., 1e6);
|
|
|
|
|
DEBUG_VALIDATE_RANGE_VEC3("denoiser.specular", specular, 0., 1e6);
|
2021-11-07 21:46:27 +01:00
|
|
|
|
|
2023-02-11 20:06:33 +01:00
|
|
|
|
imageStore(out_temporal_diffuse, pix, vec4(diffuse, depth));
|
|
|
|
|
imageStore(out_temporal_specular, pix, vec4(specular, 0./*unused*/));
|
2023-11-21 18:10:14 +01:00
|
|
|
|
#endif // ifndef DISABLE_TEMPORAL_DENOISER
|
2021-11-12 19:43:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
2023-12-11 17:48:44 +01:00
|
|
|
|
vec3 colour = vec3(0.);
|
|
|
|
|
|
2023-11-03 16:26:57 +01:00
|
|
|
|
if (ubo.ubo.debug_display_only != DEBUG_DISPLAY_LIGHTING) {
|
2023-12-11 17:48:44 +01:00
|
|
|
|
const vec3 base_color = SRGBtoLINEAR(imageLoad(base_color_a, pix).rgb);
|
2024-01-02 19:01:58 +01:00
|
|
|
|
const float metalness = imageLoad(material_rmxx, pix).g;
|
2024-01-04 19:10:26 +01:00
|
|
|
|
colour = mixFinalColor(base_color, diffuse, specular, metalness);
|
2023-12-11 17:48:44 +01:00
|
|
|
|
} else {
|
|
|
|
|
colour = diffuse + specular;
|
2023-11-03 16:26:57 +01:00
|
|
|
|
}
|
2023-12-11 17:48:44 +01:00
|
|
|
|
|
2023-12-29 18:04:38 +01:00
|
|
|
|
const vec4 legacy_blend = imageLoad(legacy_blend, pix);
|
|
|
|
|
|
|
|
|
|
colour += imageLoad(emissive, pix).rgb;
|
|
|
|
|
// Revealage. TODO: which colorspace?
|
|
|
|
|
colour *= legacy_blend.a;
|
|
|
|
|
|
|
|
|
|
colour = LINEARtoSRGB(colour);
|
|
|
|
|
|
2023-12-22 20:23:22 +01:00
|
|
|
|
// See issue https://github.com/w23/xash3d-fwgs/issues/668, map test_blendmode_additive_alpha.
|
2024-01-23 18:13:48 +01:00
|
|
|
|
// Adding emissive_blend to the final color in the *incorrect* sRGB-γ space. It makes
|
2023-12-22 20:23:22 +01:00
|
|
|
|
// it look much more like the original. Adding emissive in the *correct* linear space differs
|
|
|
|
|
// from the original a lot, and looks perceptively worse.
|
2023-12-29 18:04:38 +01:00
|
|
|
|
colour += legacy_blend.rgb;
|
2023-01-28 23:50:43 +01:00
|
|
|
|
|
2024-01-12 19:31:02 +01:00
|
|
|
|
DEBUG_VALIDATE_RANGE_VEC3("denoiser.colour", colour, 0., 1e6);
|
2024-01-09 18:05:31 +01:00
|
|
|
|
|
2023-02-11 20:06:33 +01:00
|
|
|
|
imageStore(out_dest, pix, vec4(colour, 0./*unused*/));
|
2021-11-05 20:08:15 +01:00
|
|
|
|
}
|