From 016f421f6f113463edf62f5533788aa062d00230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Sat, 21 Dec 2024 02:49:08 +0400 Subject: [PATCH 01/12] add separated reflections pass --- ref/vk/shaders/bounce.comp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/ref/vk/shaders/bounce.comp b/ref/vk/shaders/bounce.comp index d87b4faa5a..f66ff209e9 100644 --- a/ref/vk/shaders/bounce.comp +++ b/ref/vk/shaders/bounce.comp @@ -121,13 +121,13 @@ const vec3 kThrougputExtinctionThreshold = vec3(1e-3); const float kRayNormalOffsetFudge = .01; ivec2 pix; -void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, inout vec3 diffuse, inout vec3 specular) { +void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, inout vec3 diffuse, inout vec3 specular) { vec3 throughput = vec3(1.); // TODO split into two distinct passes, see #734 int first_brdf_type = BRDF_TYPE_NONE; - for (int i = 0; i < kMaxBounces; ++i) { + for (int i = 0; i < bouncesCount; ++i) { vec3 bounce_direction; // TODO blue noise @@ -288,7 +288,22 @@ void main() { mat.prop.roughness = material_data.r; } - computeBounces(mat, pos_t.xyz, direction, diffuse, specular); + computeBounces(mat, pos_t.xyz, direction, kMaxBounces, diffuse, specular); + + if ((ubo.ubo.renderer_flags & RENDERER_FLAG_ONLY_DIFFUSE_GI) != 0) { + diffuse += specular; + specular = vec3(0.); + } + + if ((ubo.ubo.renderer_flags & RENDERER_FLAG_SEPARATED_REFLECTION) != 0) { + specular = vec3(0.); + + mat.prop.metalness = 1.0; + mat.prop.roughness = material_data.r; + + vec3 unusedDiffuse = vec3(0.); + computeBounces(mat, pos_t.xyz, direction, 1, unusedDiffuse, specular); + } } #ifdef DEBUG_VALIDATE_EXTRA @@ -306,11 +321,6 @@ void main() { DEBUG_VALIDATE_RANGE_VEC3("bounce.specular", specular, 0., 1e6); #endif - if ((ubo.ubo.renderer_flags & RENDERER_FLAG_ONLY_DIFFUSE_GI) != 0) { - diffuse += specular; - specular = vec3(0.); - } - imageStore(out_indirect_diffuse, pix, vec4(diffuse, 0.f)); imageStore(out_indirect_specular, pix, vec4(specular, 0.f)); } From bfd6304be611c79cb8563d68fed404e7717f6ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Sat, 21 Dec 2024 03:24:47 +0400 Subject: [PATCH 02/12] calculate pdf for specular --- ref/vk/shaders/bounce.comp | 15 ++++++++++----- ref/vk/shaders/brdf.glsl | 7 ++++--- ref/vk/shaders/brdf.h | 5 ++++- ref/vk/shaders/light.glsl | 3 ++- ref/vk/shaders/light_polygon.glsl | 12 ++++++++---- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/ref/vk/shaders/bounce.comp b/ref/vk/shaders/bounce.comp index f66ff209e9..6df76f3b7b 100644 --- a/ref/vk/shaders/bounce.comp +++ b/ref/vk/shaders/bounce.comp @@ -121,7 +121,7 @@ const vec3 kThrougputExtinctionThreshold = vec3(1e-3); const float kRayNormalOffsetFudge = .01; ivec2 pix; -void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, inout vec3 diffuse, inout vec3 specular) { +void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, inout vec3 diffuse, inout vec3 specular, inout float specularPdf) { vec3 throughput = vec3(1.); // TODO split into two distinct passes, see #734 @@ -129,14 +129,18 @@ void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, for (int i = 0; i < bouncesCount; ++i) { vec3 bounce_direction; + float bounceSpecularPdf; // TODO blue noise const vec2 rnd = vec2(rand01(), rand01()); - const int brdf_type = brdfGetSample(rnd, mat.prop, -direction, mat.geometry_normal, mat.shading_normal/* TODO, mat.base_color_a.a*/, bounce_direction, throughput); + const int brdf_type = brdfGetSample(rnd, mat.prop, -direction, mat.geometry_normal, mat.shading_normal/* TODO, mat.base_color_a.a*/, bounce_direction, throughput, bounceSpecularPdf); if (brdf_type == BRDF_TYPE_NONE) return; + if (i == 0) + specularPdf = bounceSpecularPdf; + if (IS_INVALIDV(throughput)) { #ifdef SHADER_DEBUG_ENABLE debugPrintfEXT("pix=(%d,%d) pos=(%f,%f,%f) dir=(%f,%f,%f) throughput=invalid", @@ -262,6 +266,7 @@ void main() { const vec4 pos_t = imageLoad(position_t, pix * INDIRECT_SCALE); vec3 diffuse = vec3(0.), specular = vec3(0.); + float specularPdf = 0.; if (pos_t.w > 0.) { const vec3 origin = (ubo.ubo.inv_view * vec4(0, 0, 0, 1)).xyz; const vec4 target = ubo.ubo.inv_proj * vec4(uv.x, uv.y, 1, 1); @@ -288,7 +293,7 @@ void main() { mat.prop.roughness = material_data.r; } - computeBounces(mat, pos_t.xyz, direction, kMaxBounces, diffuse, specular); + computeBounces(mat, pos_t.xyz, direction, kMaxBounces, diffuse, specular, specularPdf); if ((ubo.ubo.renderer_flags & RENDERER_FLAG_ONLY_DIFFUSE_GI) != 0) { diffuse += specular; @@ -302,7 +307,7 @@ void main() { mat.prop.roughness = material_data.r; vec3 unusedDiffuse = vec3(0.); - computeBounces(mat, pos_t.xyz, direction, 1, unusedDiffuse, specular); + computeBounces(mat, pos_t.xyz, direction, 1, unusedDiffuse, specular, specularPdf); } } @@ -322,5 +327,5 @@ void main() { #endif imageStore(out_indirect_diffuse, pix, vec4(diffuse, 0.f)); - imageStore(out_indirect_specular, pix, vec4(specular, 0.f)); + imageStore(out_indirect_specular, pix, vec4(specular, specularPdf)); } diff --git a/ref/vk/shaders/brdf.glsl b/ref/vk/shaders/brdf.glsl index f4bc4af5b8..985aa1d6d5 100644 --- a/ref/vk/shaders/brdf.glsl +++ b/ref/vk/shaders/brdf.glsl @@ -189,7 +189,7 @@ void brdfComputeGltfModel(vec3 N, vec3 L, vec3 V, MaterialProperties material, o #endif } -void evalSplitBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material, out vec3 out_diffuse, out vec3 out_specular) { +void evalSplitBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material, out vec3 out_diffuse, out vec3 out_specular, out float out_specular_pdf) { out_diffuse = vec3(0.); out_specular = vec3(0.); @@ -347,7 +347,7 @@ vec3 SampleGGXReflection ( vec3 i , vec2 alpha , vec2 rand ) { #define BRDF_TYPE_DIFFUSE 1 #define BRDF_TYPE_SPECULAR 2 -int brdfGetSample(vec2 rnd, MaterialProperties material, vec3 view, vec3 geometry_normal, vec3 shading_normal, /*float alpha, */out vec3 out_direction, inout vec3 inout_throughput) { +int brdfGetSample(vec2 rnd, MaterialProperties material, vec3 view, vec3 geometry_normal, vec3 shading_normal, /*float alpha, */out vec3 out_direction, inout vec3 inout_throughput, inout float inout_specular_pdf) { #if 1 // See SELECTING BRDF LOBES in 14.3.6 RT Gems 2 // TODO DRY brdfComputeGltfModel @@ -429,7 +429,8 @@ if (g_mat_gltf2) { const vec2 u = vec2(rand01(), rand01()); vec3 brdf_weight = vec3(0.); - if (!evalIndirectCombinedBRDF(u, shading_normal, geometry_normal, -direction, material, brdf_type, bounce_direction, brdf_weight)) + float inout_specular_pdf = 0.; + if (!evalIndirectCombinedBRDF(u, shading_normal, geometry_normal, -direction, material, brdf_type, bounce_direction, brdf_weight, inout_specular_pdf)) return false; throughput *= brdf_weight; } diff --git a/ref/vk/shaders/brdf.h b/ref/vk/shaders/brdf.h index eab24fcc43..ea24a05cdf 100644 --- a/ref/vk/shaders/brdf.h +++ b/ref/vk/shaders/brdf.h @@ -907,7 +907,7 @@ vec3 evalCombinedBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material) { } // This is an entry point for evaluation of all other BRDFs based on selected configuration (for indirect light) -bool evalIndirectCombinedBRDF(vec2 u, vec3 shadingNormal, vec3 geometryNormal, vec3 V, MaterialProperties material, const int brdfType, OUT_PARAMETER(vec3) rayDirection, OUT_PARAMETER(vec3) sampleWeight) { +bool evalIndirectCombinedBRDF(vec2 u, vec3 shadingNormal, vec3 geometryNormal, vec3 V, MaterialProperties material, const int brdfType, OUT_PARAMETER(vec3) rayDirection, OUT_PARAMETER(vec3) sampleWeight, OUT_PARAMETER(float) reflectionPdf) { // Ignore incident ray coming from "below" the hemisphere if (dot(shadingNormal, V) <= 0.0f) return false; @@ -938,9 +938,12 @@ bool evalIndirectCombinedBRDF(vec2 u, vec3 shadingNormal, vec3 geometryNormal, v sampleWeight *= (vec3(1.0f, 1.0f, 1.0f) - evalFresnel(data.specularF0, shadowedF90(data.specularF0), VdotH)); #endif + reflectionPdf = 0.0; + } else if (brdfType == SPECULAR_TYPE) { const BrdfData data = prepareBRDFData(Nlocal, vec3(0.0f, 0.0f, 1.0f) /* unused L vector */, Vlocal, material); rayDirectionLocal = sampleSpecular(Vlocal, data.alpha, data.alphaSquared, data.specularF0, u, sampleWeight); + reflectionPdf = specularPdf(data.alpha, data.alphaSquared, data.NdotH, data.NdotV, data.LdotH); } // Prevent tracing direction with no contribution diff --git a/ref/vk/shaders/light.glsl b/ref/vk/shaders/light.glsl index 22dbd039a7..69deec3985 100644 --- a/ref/vk/shaders/light.glsl +++ b/ref/vk/shaders/light.glsl @@ -166,7 +166,8 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 view_dir, Mater color *= one_over_pdf; vec3 ldiffuse, lspecular; - evalSplitBRDF(N, light_dir, view_dir, material, ldiffuse, lspecular); + float specularPdf; + evalSplitBRDF(N, light_dir, view_dir, material, ldiffuse, lspecular, specularPdf); ldiffuse *= color; lspecular *= color; diff --git a/ref/vk/shaders/light_polygon.glsl b/ref/vk/shaders/light_polygon.glsl index c55f42bfa1..f4328393c2 100644 --- a/ref/vk/shaders/light_polygon.glsl +++ b/ref/vk/shaders/light_polygon.glsl @@ -208,7 +208,8 @@ void sampleSinglePolygonLight(in vec3 P, in vec3 N, in vec3 view_dir, in SampleC return; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); - evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular); + float specular_pdf = 0.; + evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular, specular_pdf); const float estimate = light_sample_dir.w; const vec3 emissive = poly.emissive * estimate; diffuse += emissive * poly_diffuse; @@ -278,7 +279,8 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 view_dir, MaterialProperties ma //const float estimate = total_contrib; const float estimate = light_sample_dir.w; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); - evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular); + float specular_pdf = 0.; + evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular, specular_pdf); diffuse += emissive * estimate * poly_diffuse; specular += emissive * estimate * poly_specular; @@ -345,7 +347,8 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 view_dir, MaterialProperties ma const PolygonLight poly = lights.m.polygons[selected - 1]; const vec3 emissive = poly.emissive; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); - evalSplitBRDF(N, normalize(poly.center-P), view_dir, material, poly_diffuse, poly_specular); + float specular_pdf = 0.; + evalSplitBRDF(N, normalize(poly.center-P), view_dir, material, poly_diffuse, poly_specular, specular_pdf); diffuse += emissive * total_contrib; specular += emissive * total_contrib; #else @@ -367,7 +370,8 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 view_dir, MaterialProperties ma //const float estimate = total_contrib; const float estimate = light_sample_dir.w; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); - evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular); + float specular_pdf = 0.; + evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular, specular_pdf); diffuse += emissive * estimate; specular += emissive * estimate; } From d535c9079eff04510b0602a3b5ce00a82a4fd5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Sat, 21 Dec 2024 05:10:02 +0400 Subject: [PATCH 03/12] copypaste spartial reconstruction from Diligent engine --- ref/vk/shaders/bounce.comp | 20 +- ref/vk/shaders/denoiser.comp | 15 +- .../shaders/diffuse_gi_sh_denoise_init.comp | 2 +- ref/vk/shaders/ray_interop.h | 3 +- ref/vk/shaders/rt.json | 3 + ref/vk/shaders/spartial_reconstruction.comp | 252 ++++++++++++++++++ ref/vk/vk_cvar.c | 1 + ref/vk/vk_cvar.h | 1 + ref/vk/vk_rtx.c | 3 +- 9 files changed, 285 insertions(+), 15 deletions(-) create mode 100644 ref/vk/shaders/spartial_reconstruction.comp diff --git a/ref/vk/shaders/bounce.comp b/ref/vk/shaders/bounce.comp index 6df76f3b7b..b9532f6401 100644 --- a/ref/vk/shaders/bounce.comp +++ b/ref/vk/shaders/bounce.comp @@ -32,7 +32,8 @@ layout(set = 0, binding = 13, rgba8) uniform readonly image2D base_color_a; layout(set = 0, binding = 20, rgba16f) uniform writeonly image2D out_indirect_diffuse; layout(set = 0, binding = 21, rgba16f) uniform writeonly image2D out_indirect_specular; -layout(set = 0, binding = 22, rgba16f) uniform writeonly image2D out_first_bounce_direction; // for spherical harmonics denoising +layout(set = 0, binding = 22, rgba32f) uniform writeonly image2D out_first_bounce_direction; // for spherical harmonics denoising +layout(set = 0, binding = 23, rgba32f) uniform writeonly image2D out_reflection_direction_pdf; // for spartial reconstruction layout(set = 0, binding = 30, std430) readonly buffer ModelHeaders { ModelHeader a[]; } model_headers; layout(set = 0, binding = 31, std430) readonly buffer Kusochki { Kusok a[]; } kusochki; @@ -121,7 +122,7 @@ const vec3 kThrougputExtinctionThreshold = vec3(1e-3); const float kRayNormalOffsetFudge = .01; ivec2 pix; -void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, inout vec3 diffuse, inout vec3 specular, inout float specularPdf) { +void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, inout vec3 diffuse, inout vec3 specular, inout float specularPdf, inout vec3 first_bounce_direction) { vec3 throughput = vec3(1.); // TODO split into two distinct passes, see #734 @@ -227,7 +228,7 @@ void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, specular += contribution; if (i == 0) - imageStore(out_first_bounce_direction, pix, vec4(normalize(bounce_direction), 0.f)); // for spherical harmonics denoising + first_bounce_direction = bounce_direction; if (!did_hit) break; @@ -266,6 +267,7 @@ void main() { const vec4 pos_t = imageLoad(position_t, pix * INDIRECT_SCALE); vec3 diffuse = vec3(0.), specular = vec3(0.); + vec3 first_bounce_direction = vec3(0.), reflection_direction = vec3(0.); float specularPdf = 0.; if (pos_t.w > 0.) { const vec3 origin = (ubo.ubo.inv_view * vec4(0, 0, 0, 1)).xyz; @@ -293,7 +295,7 @@ void main() { mat.prop.roughness = material_data.r; } - computeBounces(mat, pos_t.xyz, direction, kMaxBounces, diffuse, specular, specularPdf); + computeBounces(mat, pos_t.xyz, direction, kMaxBounces, diffuse, specular, specularPdf, first_bounce_direction); if ((ubo.ubo.renderer_flags & RENDERER_FLAG_ONLY_DIFFUSE_GI) != 0) { diffuse += specular; @@ -307,7 +309,7 @@ void main() { mat.prop.roughness = material_data.r; vec3 unusedDiffuse = vec3(0.); - computeBounces(mat, pos_t.xyz, direction, 1, unusedDiffuse, specular, specularPdf); + computeBounces(mat, pos_t.xyz, direction, 1, unusedDiffuse, specular, specularPdf, reflection_direction); } } @@ -326,6 +328,12 @@ void main() { DEBUG_VALIDATE_RANGE_VEC3("bounce.specular", specular, 0., 1e6); #endif + if (any(equal(reflection_direction, vec3(0.)))) { + reflection_direction = first_bounce_direction; + } + imageStore(out_indirect_diffuse, pix, vec4(diffuse, 0.f)); - imageStore(out_indirect_specular, pix, vec4(specular, specularPdf)); + imageStore(out_indirect_specular, pix, vec4(specular, 0.f)); + imageStore(out_first_bounce_direction, pix, vec4(first_bounce_direction, 0.f)); // for spherical harmonics denoising + imageStore(out_reflection_direction_pdf, pix, vec4(reflection_direction, specularPdf)); // for spartial reconstruction } diff --git a/ref/vk/shaders/denoiser.comp b/ref/vk/shaders/denoiser.comp index 0de52cdbe0..edf7c89885 100644 --- a/ref/vk/shaders/denoiser.comp +++ b/ref/vk/shaders/denoiser.comp @@ -29,7 +29,8 @@ layout(set = 0, binding = 11) uniform UBO { UniformBuffer ubo; } ubo; layout(set = 0, binding = 12, rgba16f) uniform readonly image2D indirect_diffuse; layout(set = 0, binding = 13, rgba16f) uniform readonly image2D indirect_diffuse_atrous1; -layout(set = 0, binding = 14, rgba16f) uniform readonly image2D indirect_specular; +//layout(set = 0, binding = 14, rgba16f) uniform readonly image2D indirect_specular; +layout(set = 0, binding = 14, rgba16f) uniform readonly image2D indirect_specular_reconstructed; layout(set = 0, binding = 15, rgba16f) uniform readonly image2D indirect_diffuse_denoised_by_sh; layout(set = 0, binding = 16, rgba16f) uniform image2D out_temporal_diffuse; @@ -106,7 +107,7 @@ Components dontBlurSamples(const ivec2 res, const ivec2 pix) { } 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; + c.indirect_specular += imageLoad(indirect_specular_reconstructed, p_indirect).rgb; return c; } @@ -152,7 +153,7 @@ Components boxBlurSamples(ivec2 res, ivec2 pix) { BOX_BLUR(c.indirect_diffuse, indirect_diffuse, res, pix, INDIRECT_DIFFUSE_KERNEL); } - BOX_BLUR(c.indirect_specular, indirect_specular, res, pix, INDIRECT_SPECULAR_KERNEL); + BOX_BLUR(c.indirect_specular, indirect_specular_reconstructed, res, pix, INDIRECT_SPECULAR_KERNEL); return c; } @@ -237,7 +238,7 @@ Components blurATrous(const ivec2 res, const ivec2 pix, vec3 pos, vec3 shading_n const bool do_indirect = all(lessThan(p_scaled, res_scaled)); if (do_indirect) { weight_total_indirect_specular += weight; - c.indirect_specular += imageLoad(indirect_specular, p_scaled).rgb * weight; + c.indirect_specular += imageLoad(indirect_specular_reconstructed, p_scaled).rgb * weight; } } } @@ -350,7 +351,7 @@ Components blurSamples(const ivec2 res, const ivec2 pix) { // 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; - c.indirect_specular += imageLoad(indirect_specular, p_indirect).rgb * specular_scale; + c.indirect_specular += imageLoad(indirect_specular_reconstructed, p_indirect).rgb * specular_scale; } } } @@ -461,7 +462,9 @@ void main() { } vec3 diffuse = c.direct_diffuse + c.indirect_diffuse; - vec3 specular = c.direct_specular + c.indirect_specular; + //vec3 specular = c.direct_specular + c.indirect_specular; + + vec3 specular = c.direct_specular + imageLoad(indirect_specular_reconstructed, pix / INDIRECT_SCALE).rgb; if ((ubo.ubo.renderer_flags & RENDERER_FLAG_DENOISE_GI_BY_SH) != 0) { diffuse += imageLoad(indirect_diffuse_denoised_by_sh, pix).rgb; diff --git a/ref/vk/shaders/diffuse_gi_sh_denoise_init.comp b/ref/vk/shaders/diffuse_gi_sh_denoise_init.comp index 6960a9bcc8..feb3c6bca1 100644 --- a/ref/vk/shaders/diffuse_gi_sh_denoise_init.comp +++ b/ref/vk/shaders/diffuse_gi_sh_denoise_init.comp @@ -18,7 +18,7 @@ layout(set = 0, binding = 1, rgba16f) uniform image2D out_sh2_ping; layout(set = 0, binding = 2, rgba8) uniform readonly image2D base_color_a; layout(set = 0, binding = 3, rgba32f) uniform readonly image2D position_t; layout(set = 0, binding = 4, rgba16f) uniform readonly image2D indirect_diffuse; -layout(set = 0, binding = 5, rgba16f) uniform readonly image2D first_bounce_direction; +layout(set = 0, binding = 5, rgba32f) uniform readonly image2D first_bounce_direction; void main() { ivec2 res = ivec2(imageSize(base_color_a)); diff --git a/ref/vk/shaders/ray_interop.h b/ref/vk/shaders/ray_interop.h index df819ac3f4..08c9a0bf8b 100644 --- a/ref/vk/shaders/ray_interop.h +++ b/ref/vk/shaders/ray_interop.h @@ -130,7 +130,7 @@ struct Kusok { }; struct PointLight { - vec4 origin_r2; // vec4(center.xyz, radius²) + vec4 origin_r2; // vec4(center.xyz, radius�) vec4 color_stopdot; vec4 dir_stopdot2; @@ -197,6 +197,7 @@ struct LightCluster { #define RENDERER_FLAG_SEPARATED_REFLECTION (1<<1) #define RENDERER_FLAG_DENOISE_GI_BY_SH (1<<2) #define RENDERER_FLAG_DISABLE_GI (1<<3) +#define RENDERER_FLAG_SPARTIAL_RECONSTRUCTION (1<<4) struct UniformBuffer { mat4 inv_proj, inv_view; diff --git a/ref/vk/shaders/rt.json b/ref/vk/shaders/rt.json index db7f38b001..ff232d8088 100644 --- a/ref/vk/shaders/rt.json +++ b/ref/vk/shaders/rt.json @@ -62,6 +62,9 @@ "indiff_sh_save": { "comp": "diffuse_gi_sh_denoise_save" }, + "spartial_reconstruction": { + "comp": "spartial_reconstruction" + }, "denoiser": { "comp": "denoiser" }, diff --git a/ref/vk/shaders/spartial_reconstruction.comp b/ref/vk/shaders/spartial_reconstruction.comp new file mode 100644 index 0000000000..86499c40b3 --- /dev/null +++ b/ref/vk/shaders/spartial_reconstruction.comp @@ -0,0 +1,252 @@ +#version 460 core +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_shader_16bit_storage : require +#extension GL_EXT_ray_query: require + +#include "debug.glsl" + +#define SPATIAL_RECONSTRUCTION_SAMPLES 8 +#define SPARTIAL_RECONSTRUCTION_RADIUS 4. +#define SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR 5. +#define SPATIAL_RECONSTRUCTION_SIGMA 0.9 +#define INDIRECT_SCALE 2 +//#define SSR_OPTION_HALF_RESOLUTION 1 + +#define GLSL +#include "ray_interop.h" +#undef GLSL + +#define RAY_BOUNCE +#define RAY_QUERY +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +layout(set = 0, binding = 0, rgba16f) uniform image2D out_indirect_specular_reconstructed; + +layout(set = 0, binding = 1, rgba32f) uniform readonly image2D position_t; +layout(set = 0, binding = 2, rgba16f) uniform readonly image2D normals_gs; +layout(set = 0, binding = 3, rgba8) uniform readonly image2D material_rmxx; +layout(set = 0, binding = 4, rgba16f) uniform readonly image2D indirect_specular; +layout(set = 0, binding = 5, rgba32f) uniform readonly image2D reflection_direction_pdf; + +layout(set = 0, binding = 6) uniform UBO { UniformBuffer ubo; } ubo; + +#include "utils.glsl" +#include "noise.glsl" +#include "brdf.glsl" + +#ifndef PI + #define PI 3.14 // FIXME please +#endif + +void readNormals(ivec2 uv, out vec3 geometry_normal, out vec3 shading_normal) { + const vec4 n = imageLoad(normals_gs, uv); + geometry_normal = normalDecode(n.xy); + shading_normal = normalDecode(n.zw); +} + +struct PixelAreaStatistic +{ + float Mean; + float Variance; + float WeightSum; + vec4 ColorSum; +}; + +float ComputeGaussianWeight(float Distance) +{ + return exp(-0.66 * Distance * Distance); // assuming Distance is normalized to 1 +} + +// vec4 ComputeBlurKernelRotation(ivec2 pix, uint FrameIndex) +// { +// float Angle = Bayer4x4(pix, FrameIndex); +// return GetRotator(2.0 * PI * Angle); +// } + +// Visibility = G2(v,l,a) / (4 * (n,v) * (n,l)) +// see https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf +float SmithGGXVisibilityCorrelated(float NdotL, float NdotV, float AlphaRoughness) +{ + // G1 (masking) is % microfacets visible in 1 direction + // G2 (shadow-masking) is % microfacets visible in 2 directions + // If uncorrelated: + // G2(NdotL, NdotV) = G1(NdotL) * G1(NdotV) + // Less realistic as higher points are more likely visible to both L and V + // + // https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf + + float a2 = AlphaRoughness * AlphaRoughness; + + float GGXV = NdotL * sqrt(max(NdotV * NdotV * (1.0 - a2) + a2, 1e-7)); + float GGXL = NdotV * sqrt(max(NdotL * NdotL * (1.0 - a2) + a2, 1e-7)); + + return 0.5 / (GGXV + GGXL); +} + +// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) +// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz +// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games, Equation 3. +float NormalDistribution_GGX(float NdotH, float AlphaRoughness) +{ + // "Sampling the GGX Distribution of Visible Normals" (2018) by Eric Heitz - eq. (1) + // https://jcgt.org/published/0007/04/01/ + + // Make sure we reasonably handle AlphaRoughness == 0 + // (which corresponds to delta function) + AlphaRoughness = max(AlphaRoughness, 1e-3); + + float a2 = AlphaRoughness * AlphaRoughness; + float nh2 = NdotH * NdotH; + float f = nh2 * a2 + (1.0 - nh2); + return a2 / max(PI * f * f, 1e-9); +} + +vec2 ComputeWeightRayLength(ivec2 pix, vec3 V, vec3 N, float roughness, float NdotV, float Weight) +{ + vec4 RayDirectionPDF = imageLoad(reflection_direction_pdf, pix); + float InvRayLength = inversesqrt(dot(RayDirectionPDF.xyz, RayDirectionPDF.xyz)); + if (isnan(InvRayLength)) + { + return vec2(1.0e-6f, 1.0e-6f); + } + else + { + vec3 RayDirection = RayDirectionPDF.xyz * InvRayLength; + float PDF = RayDirectionPDF.w; + float AlphaRoughness = roughness * roughness; + + vec3 L = RayDirection; + vec3 H = normalize(L + V); + + float NdotH = saturate(dot(N, H)); + float NdotL = saturate(dot(N, L)); + + float Vis = SmithGGXVisibilityCorrelated(NdotL, NdotV, AlphaRoughness); + float D = NormalDistribution_GGX(NdotH, AlphaRoughness); + float LocalBRDF = Vis * D * NdotL; + LocalBRDF *= ComputeGaussianWeight(Weight); + float rcpRayLength = InvRayLength == 0. ? 0. : 1. / InvRayLength; + return vec2(max(LocalBRDF / max(PDF, 1.0e-5f), 1e-6), 1. / InvRayLength); + } + + return vec2(0.); +} + +// Weighted incremental variance +// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance +void ComputeWeightedVariance(inout PixelAreaStatistic Stat, vec4 SampleColor, float Weight) +{ + Stat.ColorSum += Weight * SampleColor; + Stat.WeightSum += Weight; + + float Value = luminance(SampleColor.rgb); + float PrevMean = Stat.Mean; + + float rcpWeightSum = Stat.WeightSum == 0. ? 0. : 1. / Stat.WeightSum; + + Stat.Mean += Weight * rcpWeightSum * (Value - PrevMean); + Stat.Variance += Weight * (Value - PrevMean) * (Value - Stat.Mean); +} + +float ComputeResolvedDepth(vec3 origin, vec3 PositionWS, float SurfaceHitDistance) +{ + return distance(origin, PositionWS) + SurfaceHitDistance; + //float CameraSurfaceDistance = distance(origin, PositionWS) + SurfaceHitDistance; + //return CameraZToDepth(CameraSurfaceDistance + SurfaceHitDistance, g_Camera.mProj); +} + +ivec2 ClampScreenCoord(ivec2 pix, ivec2 res)\ +{ + return max(ivec2(0), min(ivec2(res - 1), pix)); +} + + +float ComputeSpatialWeight(float Distance, float Sigma) +{ + return exp(-(Distance) / (2.0 * Sigma * Sigma)); +} + +void main() { + const ivec2 pix = ivec2(gl_GlobalInvocationID); + const ivec2 res = ubo.ubo.res / INDIRECT_SCALE; + if (any(greaterThanEqual(pix, res))) { + return; + } + + if ((ubo.ubo.renderer_flags & RENDERER_FLAG_SPARTIAL_RECONSTRUCTION) == 0) { + imageStore(out_indirect_specular_reconstructed, pix, imageLoad(indirect_specular, pix)); + return; + } + + const vec2 uv = (gl_GlobalInvocationID.xy + .5) / res * 2. - 1.; + + const vec3 origin = (ubo.ubo.inv_view * vec4(0, 0, 0, 1)).xyz; + const vec3 position = imageLoad(position_t, pix).xyz; + + // samples = 8, min distance = 0.5, average samples on radius = 2 + vec3 Poisson[SPATIAL_RECONSTRUCTION_SAMPLES]; + Poisson[0] = vec3(-0.4706069, -0.4427112, +0.6461146); + Poisson[1] = vec3(-0.9057375, +0.3003471, +0.9542373); + Poisson[2] = vec3(-0.3487388, +0.4037880, +0.5335386); + Poisson[3] = vec3(+0.1023042, +0.6439373, +0.6520134); + Poisson[4] = vec3(+0.5699277, +0.3513750, +0.6695386); + Poisson[5] = vec3(+0.2939128, -0.1131226, +0.3149309); + Poisson[6] = vec3(+0.7836658, -0.4208784, +0.8895339); + Poisson[7] = vec3(+0.1564120, -0.8198990, +0.8346850); + + vec3 geometry_normal, shading_normal; + readNormals(pix, geometry_normal, shading_normal); + + vec3 V = normalize(origin - position); + float NdotV = saturate(dot(shading_normal, V)); + + float roughness = imageLoad(material_rmxx, pix).x; + + float roughness_factor = saturate(float(SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR) * roughness); + float radius = mix(0.0, SPARTIAL_RECONSTRUCTION_RADIUS, roughness_factor); + //vec4 Rotator = ComputeBlurKernelRotation(pix, g_Camera.uiFrameIndex); + + PixelAreaStatistic PixelAreaStat; + PixelAreaStat.ColorSum = vec4(0.0, 0.0, 0.0, 0.0); + PixelAreaStat.WeightSum = 0.0; + PixelAreaStat.Variance = 0.0; + PixelAreaStat.Mean = 0.0; + + float NearestSurfaceHitDistance = 0.0; + + vec3 result_color = vec3(0.); + float weights_sum = 0.; + + // TODO: Try to implement sampling from https://youtu.be/MyTOGHqyquU?t=1043 + for (int SampleIdx = 0; SampleIdx < SPATIAL_RECONSTRUCTION_SAMPLES; SampleIdx++) + { + vec2 Xi = Poisson[SampleIdx].xy; + //vec2 Xi = RotateVector(Rotator, Poisson[SampleIdx].xy); // TODO: rotate samples +// #ifdef SSR_OPTION_HALF_RESOLUTION +// ivec2 SampleCoord = ClampScreenCoord(ivec2(0.5 * (vec2(pix) + radius * Xi) + vec2(0.5, 0.5)), ivec2(res)); +// #else + ivec2 SampleCoord = ClampScreenCoord(ivec2(vec2(pix) + radius * Xi), res); +//#endif + float WeightS = ComputeSpatialWeight(Poisson[SampleIdx].z * Poisson[SampleIdx].z, SPATIAL_RECONSTRUCTION_SIGMA); + vec2 WeightLength = ComputeWeightRayLength(SampleCoord, V, shading_normal, roughness, NdotV, WeightS); + vec4 SampleColor = imageLoad(indirect_specular, SampleCoord); + ComputeWeightedVariance(PixelAreaStat, SampleColor, WeightLength.x); + + if (WeightLength.x > 1.0e-6) + NearestSurfaceHitDistance = max(WeightLength.y, NearestSurfaceHitDistance); + + result_color += SampleColor.xyz * WeightLength.x; + weights_sum += WeightLength.x; + } + + if (weights_sum > 0.) { + result_color /= weights_sum; + } + + vec4 ResolvedRadiance = PixelAreaStat.ColorSum / max(PixelAreaStat.WeightSum, 1e-6f); + float ResolvedVariance = PixelAreaStat.Variance / max(PixelAreaStat.WeightSum, 1e-6f); + float ResolvedDepth = ComputeResolvedDepth(origin, position, NearestSurfaceHitDistance); + + imageStore(out_indirect_specular_reconstructed, pix, vec4(ResolvedRadiance.xyz, ResolvedVariance)); +} diff --git a/ref/vk/vk_cvar.c b/ref/vk/vk_cvar.c index cfdb58c4bc..9d7e44887c 100644 --- a/ref/vk/vk_cvar.c +++ b/ref/vk/vk_cvar.c @@ -44,6 +44,7 @@ void VK_LoadCvarsAfterInit( void ) rt_separated_reflection = gEngine.Cvar_Get("rt_separated_reflection", "", FCVAR_GLCONFIG, "Add separated high quality reflection pass"); rt_denoise_gi_by_sh = gEngine.Cvar_Get("rt_denoise_gi_by_sh", "", FCVAR_GLCONFIG, "Denoise global illumination by spherical harmonics"); rt_disable_gi = gEngine.Cvar_Get("rt_disable_gi", "", FCVAR_GLCONFIG, "Disable global illumination calculation"); + rt_spartial_reconstruction = gEngine.Cvar_Get("rt_spartial_reconstruction", "", FCVAR_GLCONFIG, "Apply spartial reconstruction to specular"); } else { rt_enable = gEngine.Cvar_Get( "rt_enable", "0", FCVAR_READ_ONLY, "DISABLED: Ray tracing is not supported by your hardware/drivers" ); } diff --git a/ref/vk/vk_cvar.h b/ref/vk/vk_cvar.h index e9dac33ea9..e900df0c85 100644 --- a/ref/vk/vk_cvar.h +++ b/ref/vk/vk_cvar.h @@ -30,6 +30,7 @@ void VK_LoadCvarsAfterInit( void ); X(rt_separated_reflection) \ X(rt_denoise_gi_by_sh) \ X(rt_disable_gi) \ + X(rt_spartial_reconstruction) \ #define EXTERN_CVAR(cvar) extern cvar_t *cvar; DECLARE_CVAR(EXTERN_CVAR) diff --git a/ref/vk/vk_rtx.c b/ref/vk/vk_rtx.c index 4c51229232..88193c8627 100644 --- a/ref/vk/vk_rtx.c +++ b/ref/vk/vk_rtx.c @@ -272,7 +272,8 @@ static void prepareUniformBuffer( const vk_ray_frame_render_args_t *args, int fr ubo->renderer_flags = SET_RENDERER_FLAG(rt_only_diffuse_gi, RENDERER_FLAG_ONLY_DIFFUSE_GI) | SET_RENDERER_FLAG(rt_separated_reflection, RENDERER_FLAG_SEPARATED_REFLECTION) | SET_RENDERER_FLAG(rt_denoise_gi_by_sh, RENDERER_FLAG_DENOISE_GI_BY_SH) | - SET_RENDERER_FLAG(rt_disable_gi, RENDERER_FLAG_DISABLE_GI); + SET_RENDERER_FLAG(rt_disable_gi, RENDERER_FLAG_DISABLE_GI) | + SET_RENDERER_FLAG(rt_spartial_reconstruction, RENDERER_FLAG_SPARTIAL_RECONSTRUCTION); #undef SET_RENDERER_FLAG } From 0b4f4cd27ad3dc109aaf83c9a32a4ce1d28910fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Tue, 24 Dec 2024 06:18:50 +0400 Subject: [PATCH 04/12] fix spartial reconstruction --- ref/vk/shaders/bounce.comp | 1 + ref/vk/shaders/denoiser.comp | 2 + ref/vk/shaders/spartial_reconstruction.comp | 76 ++++++++++----------- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/ref/vk/shaders/bounce.comp b/ref/vk/shaders/bounce.comp index b9532f6401..8dae7e98c7 100644 --- a/ref/vk/shaders/bounce.comp +++ b/ref/vk/shaders/bounce.comp @@ -305,6 +305,7 @@ void main() { if ((ubo.ubo.renderer_flags & RENDERER_FLAG_SEPARATED_REFLECTION) != 0) { specular = vec3(0.); + mat.prop.base_color = vec3(1.); mat.prop.metalness = 1.0; mat.prop.roughness = material_data.r; diff --git a/ref/vk/shaders/denoiser.comp b/ref/vk/shaders/denoiser.comp index edf7c89885..2586b67669 100644 --- a/ref/vk/shaders/denoiser.comp +++ b/ref/vk/shaders/denoiser.comp @@ -562,6 +562,8 @@ void main() { colour = diffuse + specular; } + colour = imageLoad(indirect_specular_reconstructed, pix / INDIRECT_SCALE).rgb; // DEBUG! + const vec4 legacy_blend = imageLoad(legacy_blend, pix); colour += imageLoad(emissive, pix).rgb; diff --git a/ref/vk/shaders/spartial_reconstruction.comp b/ref/vk/shaders/spartial_reconstruction.comp index 86499c40b3..655d785bcf 100644 --- a/ref/vk/shaders/spartial_reconstruction.comp +++ b/ref/vk/shaders/spartial_reconstruction.comp @@ -6,8 +6,10 @@ #include "debug.glsl" +#define SPECULAR_CLAMPING_MAX 1.0 #define SPATIAL_RECONSTRUCTION_SAMPLES 8 -#define SPARTIAL_RECONSTRUCTION_RADIUS 4. +//#define SPATIAL_RECONSTRUCTION_SAMPLES 64 +#define SPARTIAL_RECONSTRUCTION_RADIUS 8. #define SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR 5. #define SPATIAL_RECONSTRUCTION_SIGMA 0.9 #define INDIRECT_SCALE 2 @@ -105,39 +107,30 @@ float NormalDistribution_GGX(float NdotH, float AlphaRoughness) vec2 ComputeWeightRayLength(ivec2 pix, vec3 V, vec3 N, float roughness, float NdotV, float Weight) { vec4 RayDirectionPDF = imageLoad(reflection_direction_pdf, pix); - float InvRayLength = inversesqrt(dot(RayDirectionPDF.xyz, RayDirectionPDF.xyz)); - if (isnan(InvRayLength)) - { - return vec2(1.0e-6f, 1.0e-6f); - } - else - { - vec3 RayDirection = RayDirectionPDF.xyz * InvRayLength; - float PDF = RayDirectionPDF.w; - float AlphaRoughness = roughness * roughness; - - vec3 L = RayDirection; - vec3 H = normalize(L + V); - - float NdotH = saturate(dot(N, H)); - float NdotL = saturate(dot(N, L)); - - float Vis = SmithGGXVisibilityCorrelated(NdotL, NdotV, AlphaRoughness); - float D = NormalDistribution_GGX(NdotH, AlphaRoughness); - float LocalBRDF = Vis * D * NdotL; - LocalBRDF *= ComputeGaussianWeight(Weight); - float rcpRayLength = InvRayLength == 0. ? 0. : 1. / InvRayLength; - return vec2(max(LocalBRDF / max(PDF, 1.0e-5f), 1e-6), 1. / InvRayLength); - } - - return vec2(0.); + float rayLength = length(RayDirectionPDF.xyz); + vec3 RayDirection = normalize(RayDirectionPDF.xyz); + float PDF = RayDirectionPDF.w; + float AlphaRoughness = roughness * roughness; + + vec3 L = RayDirection; + vec3 H = normalize(L + V); + + float NdotH = saturate(dot(N, H)); + float NdotL = saturate(dot(N, L)); + + float Vis = SmithGGXVisibilityCorrelated(NdotL, NdotV, AlphaRoughness); + float D = NormalDistribution_GGX(NdotH, AlphaRoughness); + float LocalBRDF = Vis * D * NdotL; + LocalBRDF *= ComputeGaussianWeight(Weight); + float rcpRayLength = rayLength == 0. ? 0. : 1. / rayLength; + return vec2(max(LocalBRDF / max(PDF, 1.0e-5f), 1e-6), rcpRayLength); } // Weighted incremental variance // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance -void ComputeWeightedVariance(inout PixelAreaStatistic Stat, vec4 SampleColor, float Weight) +void ComputeWeightedVariance(inout PixelAreaStatistic Stat, vec3 SampleColor, float Weight) { - Stat.ColorSum += Weight * SampleColor; + Stat.ColorSum.xyz += Weight * SampleColor; Stat.WeightSum += Weight; float Value = luminance(SampleColor.rgb); @@ -167,6 +160,15 @@ float ComputeSpatialWeight(float Distance, float Sigma) return exp(-(Distance) / (2.0 * Sigma * Sigma)); } +vec3 clampSpecular(vec3 specular, float maxLuminace) { + float lum = luminance(specular); + if (lum == 0.) + return vec3(0.); + + float clamped = min(maxLuminace, lum); + return specular * (clamped / lum); +} + void main() { const ivec2 pix = ivec2(gl_GlobalInvocationID); const ivec2 res = ubo.ubo.res / INDIRECT_SCALE; @@ -182,7 +184,7 @@ void main() { const vec2 uv = (gl_GlobalInvocationID.xy + .5) / res * 2. - 1.; const vec3 origin = (ubo.ubo.inv_view * vec4(0, 0, 0, 1)).xyz; - const vec3 position = imageLoad(position_t, pix).xyz; + const vec3 position = imageLoad(position_t, pix * INDIRECT_SCALE).xyz; // samples = 8, min distance = 0.5, average samples on radius = 2 vec3 Poisson[SPATIAL_RECONSTRUCTION_SAMPLES]; @@ -196,12 +198,12 @@ void main() { Poisson[7] = vec3(+0.1564120, -0.8198990, +0.8346850); vec3 geometry_normal, shading_normal; - readNormals(pix, geometry_normal, shading_normal); + readNormals(pix * INDIRECT_SCALE, geometry_normal, shading_normal); vec3 V = normalize(origin - position); float NdotV = saturate(dot(shading_normal, V)); - float roughness = imageLoad(material_rmxx, pix).x; + float roughness = imageLoad(material_rmxx, pix * INDIRECT_SCALE).x; float roughness_factor = saturate(float(SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR) * roughness); float radius = mix(0.0, SPARTIAL_RECONSTRUCTION_RADIUS, roughness_factor); @@ -222,15 +224,11 @@ void main() { for (int SampleIdx = 0; SampleIdx < SPATIAL_RECONSTRUCTION_SAMPLES; SampleIdx++) { vec2 Xi = Poisson[SampleIdx].xy; - //vec2 Xi = RotateVector(Rotator, Poisson[SampleIdx].xy); // TODO: rotate samples -// #ifdef SSR_OPTION_HALF_RESOLUTION -// ivec2 SampleCoord = ClampScreenCoord(ivec2(0.5 * (vec2(pix) + radius * Xi) + vec2(0.5, 0.5)), ivec2(res)); -// #else - ivec2 SampleCoord = ClampScreenCoord(ivec2(vec2(pix) + radius * Xi), res); -//#endif + ivec2 SampleCoord = max(ivec2(0), min(ivec2(res) - ivec2(1), ivec2(pix + radius * Xi))); + float WeightS = ComputeSpatialWeight(Poisson[SampleIdx].z * Poisson[SampleIdx].z, SPATIAL_RECONSTRUCTION_SIGMA); vec2 WeightLength = ComputeWeightRayLength(SampleCoord, V, shading_normal, roughness, NdotV, WeightS); - vec4 SampleColor = imageLoad(indirect_specular, SampleCoord); + vec3 SampleColor = clampSpecular(imageLoad(indirect_specular, SampleCoord).xyz, SPECULAR_CLAMPING_MAX); ComputeWeightedVariance(PixelAreaStat, SampleColor, WeightLength.x); if (WeightLength.x > 1.0e-6) From 5f8dc8ebb43d2e0d5ce2bd3d5944d8610381e105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Tue, 24 Dec 2024 07:32:16 +0400 Subject: [PATCH 05/12] add 2-pass spartial reconstruction --- ref/vk/shaders/denoiser.comp | 23 ++++++++----- ref/vk/shaders/rt.json | 7 ++-- ...tion.comp => spartial_reconstruction.glsl} | 34 +++++++++---------- .../spartial_reconstruction_pass1.comp | 11 ++++++ .../spartial_reconstruction_pass2.comp | 11 ++++++ 5 files changed, 59 insertions(+), 27 deletions(-) rename ref/vk/shaders/{spartial_reconstruction.comp => spartial_reconstruction.glsl} (88%) create mode 100644 ref/vk/shaders/spartial_reconstruction_pass1.comp create mode 100644 ref/vk/shaders/spartial_reconstruction_pass2.comp diff --git a/ref/vk/shaders/denoiser.comp b/ref/vk/shaders/denoiser.comp index 2586b67669..df96185af6 100644 --- a/ref/vk/shaders/denoiser.comp +++ b/ref/vk/shaders/denoiser.comp @@ -158,7 +158,14 @@ Components boxBlurSamples(ivec2 res, ivec2 pix) { return c; } -Components blurATrous(const ivec2 res, const ivec2 pix, vec3 pos, vec3 shading_normal, vec3 geometry_normal) { +vec3 restoreSpecular(vec3 decolorized_specular, vec3 base_color, float metalness) { + // TODO: add fresnel and do like PBR + const vec3 plasticSpecular = decolorized_specular * 0.02; + const vec3 metalSpecular = decolorized_specular * base_color; + return mix(plasticSpecular, metalSpecular, metalness); +} + +Components blurATrous(const ivec2 res, const ivec2 pix, vec3 pos, vec3 shading_normal, vec3 geometry_normal, vec3 base_color, float metalness) { Components c; c.direct_diffuse = c.direct_specular = c.indirect_diffuse = c.indirect_specular = vec3(0.); @@ -238,7 +245,7 @@ Components blurATrous(const ivec2 res, const ivec2 pix, vec3 pos, vec3 shading_n const bool do_indirect = all(lessThan(p_scaled, res_scaled)); if (do_indirect) { weight_total_indirect_specular += weight; - c.indirect_specular += imageLoad(indirect_specular_reconstructed, p_scaled).rgb * weight; + c.indirect_specular += restoreSpecular(imageLoad(indirect_specular_reconstructed, p_scaled).rgb, base_color, metalness) * weight; } } } @@ -399,6 +406,10 @@ void main() { } const vec3 position = imageLoad(position_t, pix).xyz; + + const vec3 base_color = SRGBtoLINEAR(imageLoad(base_color_a, pix).rgb); + const float metalness = imageLoad(material_rmxx, pix).g; + vec3 geometry_normal, shading_normal; readNormals(pix, geometry_normal, shading_normal); @@ -431,7 +442,7 @@ void main() { //const Components c = blurSamples(res, pix); //const Components c = boxBlurSamples(res, pix); //const Components c = dontBlurSamples(res, pix); - const Components c = blurATrous(res, pix, position, shading_normal, geometry_normal); + const Components c = blurATrous(res, pix, position, shading_normal, geometry_normal, base_color, metalness); if (ubo.ubo.debug_display_only == DEBUG_DISPLAY_DISABLED) { // Skip @@ -483,7 +494,7 @@ void main() { 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; @@ -555,15 +566,11 @@ void main() { vec3 colour = vec3(0.); if (ubo.ubo.debug_display_only != DEBUG_DISPLAY_LIGHTING) { - const vec3 base_color = SRGBtoLINEAR(imageLoad(base_color_a, pix).rgb); - const float metalness = imageLoad(material_rmxx, pix).g; colour = mixFinalColor(base_color, diffuse, specular, metalness); } else { colour = diffuse + specular; } - colour = imageLoad(indirect_specular_reconstructed, pix / INDIRECT_SCALE).rgb; // DEBUG! - const vec4 legacy_blend = imageLoad(legacy_blend, pix); colour += imageLoad(emissive, pix).rgb; diff --git a/ref/vk/shaders/rt.json b/ref/vk/shaders/rt.json index ff232d8088..d083551338 100644 --- a/ref/vk/shaders/rt.json +++ b/ref/vk/shaders/rt.json @@ -62,8 +62,11 @@ "indiff_sh_save": { "comp": "diffuse_gi_sh_denoise_save" }, - "spartial_reconstruction": { - "comp": "spartial_reconstruction" + "spartial_reconstruction_pass1": { + "comp": "spartial_reconstruction_pass1" + }, + "spartial_reconstruction_pass2": { + "comp": "spartial_reconstruction_pass2" }, "denoiser": { "comp": "denoiser" diff --git a/ref/vk/shaders/spartial_reconstruction.comp b/ref/vk/shaders/spartial_reconstruction.glsl similarity index 88% rename from ref/vk/shaders/spartial_reconstruction.comp rename to ref/vk/shaders/spartial_reconstruction.glsl index 655d785bcf..4745951ce2 100644 --- a/ref/vk/shaders/spartial_reconstruction.comp +++ b/ref/vk/shaders/spartial_reconstruction.glsl @@ -1,19 +1,22 @@ -#version 460 core -#extension GL_GOOGLE_include_directive : require -#extension GL_EXT_nonuniform_qualifier : enable -#extension GL_EXT_shader_16bit_storage : require -#extension GL_EXT_ray_query: require +#ifndef SPARTIAL_RECONSTRUCTION_RADIUS +#define SPARTIAL_RECONSTRUCTION_RADIUS 7. +#endif + +#ifndef SPECULAR_INPUT_IMAGE +#define SPECULAR_INPUT_IMAGE indirect_specular +#endif + +#ifndef SPECULAR_OUTPUT_IMAGE +#define SPECULAR_OUTPUT_IMAGE out_indirect_specular_reconstructed +#endif #include "debug.glsl" -#define SPECULAR_CLAMPING_MAX 1.0 +#define SPECULAR_CLAMPING_MAX 1.2 #define SPATIAL_RECONSTRUCTION_SAMPLES 8 -//#define SPATIAL_RECONSTRUCTION_SAMPLES 64 -#define SPARTIAL_RECONSTRUCTION_RADIUS 8. #define SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR 5. #define SPATIAL_RECONSTRUCTION_SIGMA 0.9 #define INDIRECT_SCALE 2 -//#define SSR_OPTION_HALF_RESOLUTION 1 #define GLSL #include "ray_interop.h" @@ -23,12 +26,12 @@ #define RAY_QUERY layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; -layout(set = 0, binding = 0, rgba16f) uniform image2D out_indirect_specular_reconstructed; +layout(set = 0, binding = 0, rgba16f) uniform image2D SPECULAR_OUTPUT_IMAGE; layout(set = 0, binding = 1, rgba32f) uniform readonly image2D position_t; layout(set = 0, binding = 2, rgba16f) uniform readonly image2D normals_gs; layout(set = 0, binding = 3, rgba8) uniform readonly image2D material_rmxx; -layout(set = 0, binding = 4, rgba16f) uniform readonly image2D indirect_specular; +layout(set = 0, binding = 4, rgba16f) uniform readonly image2D SPECULAR_INPUT_IMAGE; layout(set = 0, binding = 5, rgba32f) uniform readonly image2D reflection_direction_pdf; layout(set = 0, binding = 6) uniform UBO { UniformBuffer ubo; } ubo; @@ -145,8 +148,6 @@ void ComputeWeightedVariance(inout PixelAreaStatistic Stat, vec3 SampleColor, fl float ComputeResolvedDepth(vec3 origin, vec3 PositionWS, float SurfaceHitDistance) { return distance(origin, PositionWS) + SurfaceHitDistance; - //float CameraSurfaceDistance = distance(origin, PositionWS) + SurfaceHitDistance; - //return CameraZToDepth(CameraSurfaceDistance + SurfaceHitDistance, g_Camera.mProj); } ivec2 ClampScreenCoord(ivec2 pix, ivec2 res)\ @@ -177,7 +178,7 @@ void main() { } if ((ubo.ubo.renderer_flags & RENDERER_FLAG_SPARTIAL_RECONSTRUCTION) == 0) { - imageStore(out_indirect_specular_reconstructed, pix, imageLoad(indirect_specular, pix)); + imageStore(SPECULAR_OUTPUT_IMAGE, pix, imageLoad(SPECULAR_INPUT_IMAGE, pix)); return; } @@ -207,7 +208,6 @@ void main() { float roughness_factor = saturate(float(SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR) * roughness); float radius = mix(0.0, SPARTIAL_RECONSTRUCTION_RADIUS, roughness_factor); - //vec4 Rotator = ComputeBlurKernelRotation(pix, g_Camera.uiFrameIndex); PixelAreaStatistic PixelAreaStat; PixelAreaStat.ColorSum = vec4(0.0, 0.0, 0.0, 0.0); @@ -228,7 +228,7 @@ void main() { float WeightS = ComputeSpatialWeight(Poisson[SampleIdx].z * Poisson[SampleIdx].z, SPATIAL_RECONSTRUCTION_SIGMA); vec2 WeightLength = ComputeWeightRayLength(SampleCoord, V, shading_normal, roughness, NdotV, WeightS); - vec3 SampleColor = clampSpecular(imageLoad(indirect_specular, SampleCoord).xyz, SPECULAR_CLAMPING_MAX); + vec3 SampleColor = clampSpecular(imageLoad(SPECULAR_INPUT_IMAGE, SampleCoord).xyz, SPECULAR_CLAMPING_MAX); ComputeWeightedVariance(PixelAreaStat, SampleColor, WeightLength.x); if (WeightLength.x > 1.0e-6) @@ -246,5 +246,5 @@ void main() { float ResolvedVariance = PixelAreaStat.Variance / max(PixelAreaStat.WeightSum, 1e-6f); float ResolvedDepth = ComputeResolvedDepth(origin, position, NearestSurfaceHitDistance); - imageStore(out_indirect_specular_reconstructed, pix, vec4(ResolvedRadiance.xyz, ResolvedVariance)); + imageStore(SPECULAR_OUTPUT_IMAGE, pix, vec4(ResolvedRadiance.xyz, ResolvedVariance)); } diff --git a/ref/vk/shaders/spartial_reconstruction_pass1.comp b/ref/vk/shaders/spartial_reconstruction_pass1.comp new file mode 100644 index 0000000000..b8bc2a8ade --- /dev/null +++ b/ref/vk/shaders/spartial_reconstruction_pass1.comp @@ -0,0 +1,11 @@ +#version 460 core +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_shader_16bit_storage : require +#extension GL_EXT_ray_query: require + +#define SPARTIAL_RECONSTRUCTION_RADIUS 11. +#define SPECULAR_INPUT_IMAGE indirect_specular +#define SPECULAR_OUTPUT_IMAGE out_indirect_specular_reconstructed_pass1 + +#include "spartial_reconstruction.glsl" diff --git a/ref/vk/shaders/spartial_reconstruction_pass2.comp b/ref/vk/shaders/spartial_reconstruction_pass2.comp new file mode 100644 index 0000000000..17d189335e --- /dev/null +++ b/ref/vk/shaders/spartial_reconstruction_pass2.comp @@ -0,0 +1,11 @@ +#version 460 core +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : enable +#extension GL_EXT_shader_16bit_storage : require +#extension GL_EXT_ray_query: require + +#define SPARTIAL_RECONSTRUCTION_RADIUS 5. +#define SPECULAR_INPUT_IMAGE indirect_specular_reconstructed_pass1 +#define SPECULAR_OUTPUT_IMAGE out_indirect_specular_reconstructed + +#include "spartial_reconstruction.glsl" From fba9c3c9329bc9e3beee364fb47c0e7bb2d31111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Wed, 25 Dec 2024 01:45:27 +0400 Subject: [PATCH 06/12] parallax reprojecting --- ref/vk/shaders/bounce.comp | 2 +- ref/vk/shaders/denoiser.comp | 72 +++++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/ref/vk/shaders/bounce.comp b/ref/vk/shaders/bounce.comp index 8dae7e98c7..1f8512f837 100644 --- a/ref/vk/shaders/bounce.comp +++ b/ref/vk/shaders/bounce.comp @@ -228,7 +228,7 @@ void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, specular += contribution; if (i == 0) - first_bounce_direction = bounce_direction; + first_bounce_direction = hit_pos - pos; if (!did_hit) break; diff --git a/ref/vk/shaders/denoiser.comp b/ref/vk/shaders/denoiser.comp index df96185af6..ae6c2beb5c 100644 --- a/ref/vk/shaders/denoiser.comp +++ b/ref/vk/shaders/denoiser.comp @@ -29,25 +29,25 @@ layout(set = 0, binding = 11) uniform UBO { UniformBuffer ubo; } ubo; layout(set = 0, binding = 12, rgba16f) uniform readonly image2D indirect_diffuse; layout(set = 0, binding = 13, rgba16f) uniform readonly image2D indirect_diffuse_atrous1; -//layout(set = 0, binding = 14, rgba16f) uniform readonly image2D indirect_specular; layout(set = 0, binding = 14, rgba16f) uniform readonly image2D indirect_specular_reconstructed; layout(set = 0, binding = 15, rgba16f) uniform readonly image2D indirect_diffuse_denoised_by_sh; +layout(set = 0, binding = 16, rgba32f) uniform readonly image2D reflection_direction_pdf; -layout(set = 0, binding = 16, rgba16f) uniform image2D out_temporal_diffuse; -layout(set = 0, binding = 17, rgba16f) uniform image2D prev_temporal_diffuse; +layout(set = 0, binding = 17, rgba16f) uniform image2D out_temporal_diffuse; +layout(set = 0, binding = 18, rgba16f) uniform image2D prev_temporal_diffuse; -layout(set = 0, binding = 18, rgba16f) uniform image2D out_temporal_specular; -layout(set = 0, binding = 19, rgba16f) uniform image2D prev_temporal_specular; +layout(set = 0, binding = 19, rgba16f) uniform image2D out_temporal_specular; +layout(set = 0, binding = 20, rgba16f) uniform image2D prev_temporal_specular; //#define DEBUG_NOISE #ifdef DEBUG_NOISE -layout(set = 0, binding = 20) uniform sampler3D blue_noise_texture; +layout(set = 0, binding = 21) uniform sampler3D blue_noise_texture; #include "bluenoise.glsl" #endif -layout(set = 0, binding = 21, rgba16f) uniform readonly image2D legacy_blend; +layout(set = 0, binding = 22, rgba16f) uniform readonly image2D legacy_blend; -//layout(set = 0, binding = 22) uniform sampler2D textures[MAX_TEXTURES]; +//layout(set = 0, binding = 23) uniform sampler2D textures[MAX_TEXTURES]; #include "atrous.glsl" @@ -89,6 +89,12 @@ void readNormals(ivec2 uv, out vec3 geometry_normal, out vec3 shading_normal) { shading_normal = normalDecode(n.zw); } +vec3 closestColor(vec3 color1, vec3 color2, vec3 sampleColor) { + float dist1 = dot(color1 - sampleColor, color1 - sampleColor); + float dist2 = dot(color2 - sampleColor, color2 - sampleColor); + return (dist1 < dist2) ? color1 : color2; +} + struct Components { vec3 direct_diffuse, direct_specular, indirect_diffuse, indirect_specular; }; @@ -522,6 +528,54 @@ void main() { } } + // parallax reprojecting for specular + float average_ray_length = 0.; + float ray_length_samples_count = 0.; + for(int x = -TEMPORAL_KERNEL; x <=TEMPORAL_KERNEL; x++) { + for(int y = -TEMPORAL_KERNEL; y <=TEMPORAL_KERNEL; y++) { + const ivec2 p = pix / INDIRECT_SCALE + ivec2(x, y); + if (any(greaterThanEqual(p, res / INDIRECT_SCALE)) || any(lessThan(p, ivec2(0)))) { + continue; + } + + average_ray_length += length(imageLoad( reflection_direction_pdf, p ).xyz); + ray_length_samples_count += 1.; + } + } + if (ray_length_samples_count > 0. && average_ray_length > 0.) { + average_ray_length /= ray_length_samples_count; + + // origin (camera) + // []< reflection destination + // | \ (UwU) (reflected in + // | \ / | surface texel) + // | \ / | + // --------x------x-----x------------ + // origin on ^ reflection on plane + // plane | + // reflection center + // (surface texel in current frame) + // (need to find this in previous frame) + // + + const vec3 refl_position = reflect(normalize(position - origin), geometry_normal) * average_ray_length + position; + const float refl_distance_to_plane = dot(geometry_normal, refl_position - prev_position); + const vec3 refl_on_plane = refl_position - geometry_normal * refl_distance_to_plane; + const float prev_distance_to_plane = dot(geometry_normal, prev_origin - prev_position); + const vec3 prev_origin_on_plane = prev_origin - geometry_normal * prev_distance_to_plane; + const float refl_center = prev_distance_to_plane / (prev_distance_to_plane + refl_distance_to_plane); + const vec3 parallax_position = mix(prev_origin_on_plane, refl_on_plane, refl_center); + + const vec4 clip_space = inverse(ubo.ubo.prev_inv_proj) * vec4((inverse(ubo.ubo.prev_inv_view) * vec4(parallax_position, 1.)).xyz, 1.); + const vec2 parallax_uv = clip_space.xy / clip_space.w; + const ivec2 parallax_pix = ivec2((parallax_uv * 0.5 + vec2(0.5)) * vec2(res)); + + if (any(greaterThanEqual(parallax_pix, ivec2(0))) && any(lessThan(parallax_pix, res))) { + const vec4 history_specular_sample = imageLoad( prev_temporal_specular, parallax_pix ); + history_specular = closestColor(history_specular_sample.xyz, history_specular, specular); + } + } + #ifdef DEBUG_VALIDATE_EXTRA if (IS_INVALIDV(history_specular)) { debugPrintfEXT("PRE pix=(%d,%d) history_specular=inv", pix.x, pix.y); @@ -536,7 +590,7 @@ void main() { if (better_depth_offset < depth_treshold) { diffuse = mix(diffuse, history_diffuse, 0.8); - specular = mix(specular, history_specular, 0.3); + specular = mix(specular, history_specular, 0.8); } #ifdef DEBUG_VALIDATE_EXTRA From 86e39f01783602015985e8432fb11380f3597cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Wed, 25 Dec 2024 02:02:55 +0400 Subject: [PATCH 07/12] fixes --- ref/vk/shaders/denoiser.comp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ref/vk/shaders/denoiser.comp b/ref/vk/shaders/denoiser.comp index ae6c2beb5c..79a8cf6369 100644 --- a/ref/vk/shaders/denoiser.comp +++ b/ref/vk/shaders/denoiser.comp @@ -411,6 +411,8 @@ void main() { return; } + const vec3 origin = (ubo.ubo.inv_view * vec4(0., 0., 0., 1.)).xyz; + const vec3 position = imageLoad(position_t, pix).xyz; const vec3 base_color = SRGBtoLINEAR(imageLoad(base_color_a, pix).rgb); @@ -479,9 +481,7 @@ void main() { } vec3 diffuse = c.direct_diffuse + c.indirect_diffuse; - //vec3 specular = c.direct_specular + c.indirect_specular; - - vec3 specular = c.direct_specular + imageLoad(indirect_specular_reconstructed, pix / INDIRECT_SCALE).rgb; + vec3 specular = c.direct_specular + c.indirect_specular; if ((ubo.ubo.renderer_flags & RENDERER_FLAG_DENOISE_GI_BY_SH) != 0) { diffuse += imageLoad(indirect_diffuse_denoised_by_sh, pix).rgb; @@ -491,7 +491,6 @@ void main() { //#define DISABLE_TEMPORAL_DENOISER #ifndef DISABLE_TEMPORAL_DENOISER // 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; const float depth = length(origin - position); 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.); From bf0b9ae056363612b999ca8ee46747173b988507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Wed, 25 Dec 2024 02:19:43 +0400 Subject: [PATCH 08/12] fix codestyle and add author of spartial reconstruction --- ref/vk/shaders/spartial_reconstruction.glsl | 243 +++++++++----------- 1 file changed, 115 insertions(+), 128 deletions(-) diff --git a/ref/vk/shaders/spartial_reconstruction.glsl b/ref/vk/shaders/spartial_reconstruction.glsl index 4745951ce2..96b53ac2c7 100644 --- a/ref/vk/shaders/spartial_reconstruction.glsl +++ b/ref/vk/shaders/spartial_reconstruction.glsl @@ -1,3 +1,6 @@ +// originally implemented by Mikhail Gorobets for Diligent Engine +// https://github.com/DiligentGraphics/DiligentEngine + #ifndef SPARTIAL_RECONSTRUCTION_RADIUS #define SPARTIAL_RECONSTRUCTION_RADIUS 7. #endif @@ -50,124 +53,109 @@ void readNormals(ivec2 uv, out vec3 geometry_normal, out vec3 shading_normal) { shading_normal = normalDecode(n.zw); } -struct PixelAreaStatistic -{ - float Mean; - float Variance; - float WeightSum; - vec4 ColorSum; +struct PixelAreaStatistic { + float mean; + float variance; + float weightSum; + vec4 colorSum; }; -float ComputeGaussianWeight(float Distance) -{ - return exp(-0.66 * Distance * Distance); // assuming Distance is normalized to 1 +float computeGaussianWeight(float texelDistance) { + return exp(-0.66 * texelDistance * texelDistance); // assuming texelDistance is normalized to 1 } -// vec4 ComputeBlurKernelRotation(ivec2 pix, uint FrameIndex) -// { -// float Angle = Bayer4x4(pix, FrameIndex); -// return GetRotator(2.0 * PI * Angle); -// } - // Visibility = G2(v,l,a) / (4 * (n,v) * (n,l)) // see https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf -float SmithGGXVisibilityCorrelated(float NdotL, float NdotV, float AlphaRoughness) -{ - // G1 (masking) is % microfacets visible in 1 direction - // G2 (shadow-masking) is % microfacets visible in 2 directions - // If uncorrelated: - // G2(NdotL, NdotV) = G1(NdotL) * G1(NdotV) - // Less realistic as higher points are more likely visible to both L and V - // - // https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf - - float a2 = AlphaRoughness * AlphaRoughness; - - float GGXV = NdotL * sqrt(max(NdotV * NdotV * (1.0 - a2) + a2, 1e-7)); - float GGXL = NdotV * sqrt(max(NdotL * NdotL * (1.0 - a2) + a2, 1e-7)); - - return 0.5 / (GGXV + GGXL); +float smithGGXVisibilityCorrelated(float NdotL, float NdotV, float alphaRoughness) { + // G1 (masking) is % microfacets visible in 1 direction + // G2 (shadow-masking) is % microfacets visible in 2 directions + // If uncorrelated: + // G2(NdotL, NdotV) = G1(NdotL) * G1(NdotV) + // Less realistic as higher points are more likely visible to both L and V + // + // https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf + + float a2 = alphaRoughness * alphaRoughness; + + float GGXV = NdotL * sqrt(max(NdotV * NdotV * (1.0 - a2) + a2, 1e-7)); + float GGXL = NdotV * sqrt(max(NdotL * NdotL * (1.0 - a2) + a2, 1e-7)); + + return 0.5 / (GGXV + GGXL); } // The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) // Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz // Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games, Equation 3. -float NormalDistribution_GGX(float NdotH, float AlphaRoughness) -{ - // "Sampling the GGX Distribution of Visible Normals" (2018) by Eric Heitz - eq. (1) - // https://jcgt.org/published/0007/04/01/ - - // Make sure we reasonably handle AlphaRoughness == 0 - // (which corresponds to delta function) - AlphaRoughness = max(AlphaRoughness, 1e-3); - - float a2 = AlphaRoughness * AlphaRoughness; - float nh2 = NdotH * NdotH; - float f = nh2 * a2 + (1.0 - nh2); - return a2 / max(PI * f * f, 1e-9); +float normalDistribution_GGX(float NdotH, float alphaRoughness) { + // "Sampling the GGX Distribution of Visible Normals" (2018) by Eric Heitz - eq. (1) + // https://jcgt.org/published/0007/04/01/ + + // Make sure we reasonably handle alphaRoughness == 0 + // (which corresponds to delta function) + alphaRoughness = max(alphaRoughness, 1e-3); + + float a2 = alphaRoughness * alphaRoughness; + float nh2 = NdotH * NdotH; + float f = nh2 * a2 + (1.0 - nh2); + return a2 / max(PI * f * f, 1e-9); } -vec2 ComputeWeightRayLength(ivec2 pix, vec3 V, vec3 N, float roughness, float NdotV, float Weight) -{ - vec4 RayDirectionPDF = imageLoad(reflection_direction_pdf, pix); - float rayLength = length(RayDirectionPDF.xyz); - vec3 RayDirection = normalize(RayDirectionPDF.xyz); - float PDF = RayDirectionPDF.w; - float AlphaRoughness = roughness * roughness; - - vec3 L = RayDirection; - vec3 H = normalize(L + V); - - float NdotH = saturate(dot(N, H)); - float NdotL = saturate(dot(N, L)); - - float Vis = SmithGGXVisibilityCorrelated(NdotL, NdotV, AlphaRoughness); - float D = NormalDistribution_GGX(NdotH, AlphaRoughness); - float LocalBRDF = Vis * D * NdotL; - LocalBRDF *= ComputeGaussianWeight(Weight); - float rcpRayLength = rayLength == 0. ? 0. : 1. / rayLength; - return vec2(max(LocalBRDF / max(PDF, 1.0e-5f), 1e-6), rcpRayLength); +vec2 computeWeightRayLength(ivec2 pix, vec3 V, vec3 N, float roughness, float NdotV, float weight) { + vec4 rayDirectionPDF = imageLoad(reflection_direction_pdf, pix); + float rayLength = length(rayDirectionPDF.xyz); + vec3 rayDirection = normalize(rayDirectionPDF.xyz); + float PDF = rayDirectionPDF.w; + float alphaRoughness = roughness * roughness; + + vec3 L = rayDirection; + vec3 H = normalize(L + V); + + float NdotH = saturate(dot(N, H)); + float NdotL = saturate(dot(N, L)); + + float vis = smithGGXVisibilityCorrelated(NdotL, NdotV, alphaRoughness); + float D = normalDistribution_GGX(NdotH, alphaRoughness); + float localBRDF = vis * D * NdotL; + localBRDF *= computeGaussianWeight(weight); + float rcpRayLength = rayLength == 0. ? 0. : 1. / rayLength; + return vec2(max(localBRDF / max(PDF, 1.0e-5f), 1e-6), rcpRayLength); } // Weighted incremental variance // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance -void ComputeWeightedVariance(inout PixelAreaStatistic Stat, vec3 SampleColor, float Weight) -{ - Stat.ColorSum.xyz += Weight * SampleColor; - Stat.WeightSum += Weight; +void computeWeightedVariance(inout PixelAreaStatistic stat, vec3 sampleColor, float weight) { + stat.colorSum.xyz += weight * sampleColor; + stat.weightSum += weight; - float Value = luminance(SampleColor.rgb); - float PrevMean = Stat.Mean; + float value = luminance(sampleColor.rgb); + float prevMean = stat.mean; - float rcpWeightSum = Stat.WeightSum == 0. ? 0. : 1. / Stat.WeightSum; + float rcpWeightSum = stat.weightSum == 0. ? 0. : 1. / stat.weightSum; - Stat.Mean += Weight * rcpWeightSum * (Value - PrevMean); - Stat.Variance += Weight * (Value - PrevMean) * (Value - Stat.Mean); + stat.mean += weight * rcpWeightSum * (value - prevMean); + stat.variance += weight * (value - prevMean) * (value - stat.mean); } -float ComputeResolvedDepth(vec3 origin, vec3 PositionWS, float SurfaceHitDistance) -{ - return distance(origin, PositionWS) + SurfaceHitDistance; +float computeResolvedDepth(vec3 origin, vec3 position, float surfaceHitDistance) { + return distance(origin, position) + surfaceHitDistance; } -ivec2 ClampScreenCoord(ivec2 pix, ivec2 res)\ -{ +ivec2 clampScreenCoord(ivec2 pix, ivec2 res) { return max(ivec2(0), min(ivec2(res - 1), pix)); } -float ComputeSpatialWeight(float Distance, float Sigma) -{ - return exp(-(Distance) / (2.0 * Sigma * Sigma)); +float computeSpatialWeight(float texelDistance, float sigma) { + return exp(-(texelDistance) / (2.0 * sigma * sigma)); } vec3 clampSpecular(vec3 specular, float maxLuminace) { - float lum = luminance(specular); - if (lum == 0.) - return vec3(0.); + float lum = luminance(specular); + if (lum == 0.) + return vec3(0.); - float clamped = min(maxLuminace, lum); - return specular * (clamped / lum); + float clamped = min(maxLuminace, lum); + return specular * (clamped / lum); } void main() { @@ -178,73 +166,72 @@ void main() { } if ((ubo.ubo.renderer_flags & RENDERER_FLAG_SPARTIAL_RECONSTRUCTION) == 0) { - imageStore(SPECULAR_OUTPUT_IMAGE, pix, imageLoad(SPECULAR_INPUT_IMAGE, pix)); - return; - } + imageStore(SPECULAR_OUTPUT_IMAGE, pix, imageLoad(SPECULAR_INPUT_IMAGE, pix)); + return; + } const vec2 uv = (gl_GlobalInvocationID.xy + .5) / res * 2. - 1.; const vec3 origin = (ubo.ubo.inv_view * vec4(0, 0, 0, 1)).xyz; const vec3 position = imageLoad(position_t, pix * INDIRECT_SCALE).xyz; - // samples = 8, min distance = 0.5, average samples on radius = 2 - vec3 Poisson[SPATIAL_RECONSTRUCTION_SAMPLES]; - Poisson[0] = vec3(-0.4706069, -0.4427112, +0.6461146); - Poisson[1] = vec3(-0.9057375, +0.3003471, +0.9542373); - Poisson[2] = vec3(-0.3487388, +0.4037880, +0.5335386); - Poisson[3] = vec3(+0.1023042, +0.6439373, +0.6520134); - Poisson[4] = vec3(+0.5699277, +0.3513750, +0.6695386); - Poisson[5] = vec3(+0.2939128, -0.1131226, +0.3149309); - Poisson[6] = vec3(+0.7836658, -0.4208784, +0.8895339); - Poisson[7] = vec3(+0.1564120, -0.8198990, +0.8346850); + // samples = 8, min distance = 0.5, average samples on radius = 2 + vec3 poisson[SPATIAL_RECONSTRUCTION_SAMPLES]; + poisson[0] = vec3(-0.4706069, -0.4427112, +0.6461146); + poisson[1] = vec3(-0.9057375, +0.3003471, +0.9542373); + poisson[2] = vec3(-0.3487388, +0.4037880, +0.5335386); + poisson[3] = vec3(+0.1023042, +0.6439373, +0.6520134); + poisson[4] = vec3(+0.5699277, +0.3513750, +0.6695386); + poisson[5] = vec3(+0.2939128, -0.1131226, +0.3149309); + poisson[6] = vec3(+0.7836658, -0.4208784, +0.8895339); + poisson[7] = vec3(+0.1564120, -0.8198990, +0.8346850); vec3 geometry_normal, shading_normal; readNormals(pix * INDIRECT_SCALE, geometry_normal, shading_normal); - vec3 V = normalize(origin - position); - float NdotV = saturate(dot(shading_normal, V)); + vec3 V = normalize(origin - position); + float NdotV = saturate(dot(shading_normal, V)); - float roughness = imageLoad(material_rmxx, pix * INDIRECT_SCALE).x; + float roughness = imageLoad(material_rmxx, pix * INDIRECT_SCALE).x; - float roughness_factor = saturate(float(SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR) * roughness); - float radius = mix(0.0, SPARTIAL_RECONSTRUCTION_RADIUS, roughness_factor); + float roughness_factor = saturate(float(SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR) * roughness); + float radius = mix(0.0, SPARTIAL_RECONSTRUCTION_RADIUS, roughness_factor); - PixelAreaStatistic PixelAreaStat; - PixelAreaStat.ColorSum = vec4(0.0, 0.0, 0.0, 0.0); - PixelAreaStat.WeightSum = 0.0; - PixelAreaStat.Variance = 0.0; - PixelAreaStat.Mean = 0.0; + PixelAreaStatistic pixelAreaStat; + pixelAreaStat.colorSum = vec4(0.0, 0.0, 0.0, 0.0); + pixelAreaStat.weightSum = 0.0; + pixelAreaStat.variance = 0.0; + pixelAreaStat.mean = 0.0; - float NearestSurfaceHitDistance = 0.0; + float nearestSurfaceHitDistance = 0.0; vec3 result_color = vec3(0.); float weights_sum = 0.; - // TODO: Try to implement sampling from https://youtu.be/MyTOGHqyquU?t=1043 - for (int SampleIdx = 0; SampleIdx < SPATIAL_RECONSTRUCTION_SAMPLES; SampleIdx++) - { - vec2 Xi = Poisson[SampleIdx].xy; - ivec2 SampleCoord = max(ivec2(0), min(ivec2(res) - ivec2(1), ivec2(pix + radius * Xi))); + // TODO: Try to implement sampling from https://youtu.be/MyTOGHqyquU?t=1043 + for (int i = 0; i < SPATIAL_RECONSTRUCTION_SAMPLES; i++) + { + ivec2 p = max(ivec2(0), min(ivec2(res) - ivec2(1), ivec2(pix + radius * poisson[i].xy))); - float WeightS = ComputeSpatialWeight(Poisson[SampleIdx].z * Poisson[SampleIdx].z, SPATIAL_RECONSTRUCTION_SIGMA); - vec2 WeightLength = ComputeWeightRayLength(SampleCoord, V, shading_normal, roughness, NdotV, WeightS); - vec3 SampleColor = clampSpecular(imageLoad(SPECULAR_INPUT_IMAGE, SampleCoord).xyz, SPECULAR_CLAMPING_MAX); - ComputeWeightedVariance(PixelAreaStat, SampleColor, WeightLength.x); + float weightS = computeSpatialWeight(poisson[i].z * poisson[i].z, SPATIAL_RECONSTRUCTION_SIGMA); + vec2 weightLength = computeWeightRayLength(p, V, shading_normal, roughness, NdotV, weightS); + vec3 sampleColor = clampSpecular(imageLoad(SPECULAR_INPUT_IMAGE, p).xyz, SPECULAR_CLAMPING_MAX); + computeWeightedVariance(pixelAreaStat, sampleColor, weightLength.x); - if (WeightLength.x > 1.0e-6) - NearestSurfaceHitDistance = max(WeightLength.y, NearestSurfaceHitDistance); + if (weightLength.x > 1.0e-6) + nearestSurfaceHitDistance = max(weightLength.y, nearestSurfaceHitDistance); - result_color += SampleColor.xyz * WeightLength.x; - weights_sum += WeightLength.x; - } + result_color += sampleColor.xyz * weightLength.x; + weights_sum += weightLength.x; + } if (weights_sum > 0.) { result_color /= weights_sum; } - vec4 ResolvedRadiance = PixelAreaStat.ColorSum / max(PixelAreaStat.WeightSum, 1e-6f); - float ResolvedVariance = PixelAreaStat.Variance / max(PixelAreaStat.WeightSum, 1e-6f); - float ResolvedDepth = ComputeResolvedDepth(origin, position, NearestSurfaceHitDistance); + vec4 resolvedRadiance = pixelAreaStat.colorSum / max(pixelAreaStat.weightSum, 1e-6f); + float resolvedVariance = pixelAreaStat.variance / max(pixelAreaStat.weightSum, 1e-6f); + float resolvedDepth = computeResolvedDepth(origin, position, nearestSurfaceHitDistance); - imageStore(SPECULAR_OUTPUT_IMAGE, pix, vec4(ResolvedRadiance.xyz, ResolvedVariance)); + imageStore(SPECULAR_OUTPUT_IMAGE, pix, vec4(resolvedRadiance.xyz, resolvedVariance)); } From 48c1d3453b803b18ab2b5253cf1539ecaf9a471b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Wed, 25 Dec 2024 02:24:01 +0400 Subject: [PATCH 09/12] fixes --- ref/vk/shaders/denoiser.comp | 4 +--- ref/vk/shaders/ray_interop.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ref/vk/shaders/denoiser.comp b/ref/vk/shaders/denoiser.comp index 79a8cf6369..93c52ed51f 100644 --- a/ref/vk/shaders/denoiser.comp +++ b/ref/vk/shaders/denoiser.comp @@ -411,8 +411,6 @@ void main() { return; } - const vec3 origin = (ubo.ubo.inv_view * vec4(0., 0., 0., 1.)).xyz; - const vec3 position = imageLoad(position_t, pix).xyz; const vec3 base_color = SRGBtoLINEAR(imageLoad(base_color_a, pix).rgb); @@ -491,6 +489,7 @@ void main() { //#define DISABLE_TEMPORAL_DENOISER #ifndef DISABLE_TEMPORAL_DENOISER // 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; const float depth = length(origin - position); 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.); @@ -499,7 +498,6 @@ void main() { 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; diff --git a/ref/vk/shaders/ray_interop.h b/ref/vk/shaders/ray_interop.h index 08c9a0bf8b..cb033d3b26 100644 --- a/ref/vk/shaders/ray_interop.h +++ b/ref/vk/shaders/ray_interop.h @@ -130,7 +130,7 @@ struct Kusok { }; struct PointLight { - vec4 origin_r2; // vec4(center.xyz, radius�) + vec4 origin_r2; // vec4(center.xyz, radius²) vec4 color_stopdot; vec4 dir_stopdot2; From ac7b503b10ba9db8c2409c2cdd3f7469a754bd08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Wed, 25 Dec 2024 22:30:07 +0400 Subject: [PATCH 10/12] review fixes --- ref/vk/shaders/bounce.comp | 17 +++---- ref/vk/shaders/brdf.glsl | 7 ++- ref/vk/shaders/brdf.h | 5 +- ref/vk/shaders/denoiser.comp | 47 +++++++++---------- ref/vk/shaders/light.glsl | 3 +- ref/vk/shaders/light_polygon.glsl | 12 ++--- ref/vk/shaders/ray_interop.h | 2 +- ref/vk/shaders/rt.json | 8 ++-- ...ction.glsl => spatial_reconstruction.glsl} | 8 ++-- ...comp => spatial_reconstruction_pass1.comp} | 4 +- ...comp => spatial_reconstruction_pass2.comp} | 4 +- ref/vk/vk_cvar.c | 2 +- ref/vk/vk_cvar.h | 2 +- ref/vk/vk_rtx.c | 2 +- 14 files changed, 52 insertions(+), 71 deletions(-) rename ref/vk/shaders/{spartial_reconstruction.glsl => spatial_reconstruction.glsl} (97%) rename ref/vk/shaders/{spartial_reconstruction_pass1.comp => spatial_reconstruction_pass1.comp} (79%) rename ref/vk/shaders/{spartial_reconstruction_pass2.comp => spatial_reconstruction_pass2.comp} (80%) diff --git a/ref/vk/shaders/bounce.comp b/ref/vk/shaders/bounce.comp index 1f8512f837..d0ef8f659b 100644 --- a/ref/vk/shaders/bounce.comp +++ b/ref/vk/shaders/bounce.comp @@ -33,7 +33,7 @@ layout(set = 0, binding = 13, rgba8) uniform readonly image2D base_color_a; layout(set = 0, binding = 20, rgba16f) uniform writeonly image2D out_indirect_diffuse; layout(set = 0, binding = 21, rgba16f) uniform writeonly image2D out_indirect_specular; layout(set = 0, binding = 22, rgba32f) uniform writeonly image2D out_first_bounce_direction; // for spherical harmonics denoising -layout(set = 0, binding = 23, rgba32f) uniform writeonly image2D out_reflection_direction_pdf; // for spartial reconstruction +layout(set = 0, binding = 23, rgba32f) uniform writeonly image2D out_reflection_direction_pdf; // for spatial reconstruction layout(set = 0, binding = 30, std430) readonly buffer ModelHeaders { ModelHeader a[]; } model_headers; layout(set = 0, binding = 31, std430) readonly buffer Kusochki { Kusok a[]; } kusochki; @@ -122,7 +122,7 @@ const vec3 kThrougputExtinctionThreshold = vec3(1e-3); const float kRayNormalOffsetFudge = .01; ivec2 pix; -void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, inout vec3 diffuse, inout vec3 specular, inout float specularPdf, inout vec3 first_bounce_direction) { +void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, inout vec3 diffuse, inout vec3 specular, inout vec3 first_bounce_direction) { vec3 throughput = vec3(1.); // TODO split into two distinct passes, see #734 @@ -130,18 +130,14 @@ void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, int bouncesCount, for (int i = 0; i < bouncesCount; ++i) { vec3 bounce_direction; - float bounceSpecularPdf; // TODO blue noise const vec2 rnd = vec2(rand01(), rand01()); - const int brdf_type = brdfGetSample(rnd, mat.prop, -direction, mat.geometry_normal, mat.shading_normal/* TODO, mat.base_color_a.a*/, bounce_direction, throughput, bounceSpecularPdf); + const int brdf_type = brdfGetSample(rnd, mat.prop, -direction, mat.geometry_normal, mat.shading_normal/* TODO, mat.base_color_a.a*/, bounce_direction, throughput); if (brdf_type == BRDF_TYPE_NONE) return; - if (i == 0) - specularPdf = bounceSpecularPdf; - if (IS_INVALIDV(throughput)) { #ifdef SHADER_DEBUG_ENABLE debugPrintfEXT("pix=(%d,%d) pos=(%f,%f,%f) dir=(%f,%f,%f) throughput=invalid", @@ -268,7 +264,6 @@ void main() { const vec4 pos_t = imageLoad(position_t, pix * INDIRECT_SCALE); vec3 diffuse = vec3(0.), specular = vec3(0.); vec3 first_bounce_direction = vec3(0.), reflection_direction = vec3(0.); - float specularPdf = 0.; if (pos_t.w > 0.) { const vec3 origin = (ubo.ubo.inv_view * vec4(0, 0, 0, 1)).xyz; const vec4 target = ubo.ubo.inv_proj * vec4(uv.x, uv.y, 1, 1); @@ -295,7 +290,7 @@ void main() { mat.prop.roughness = material_data.r; } - computeBounces(mat, pos_t.xyz, direction, kMaxBounces, diffuse, specular, specularPdf, first_bounce_direction); + computeBounces(mat, pos_t.xyz, direction, kMaxBounces, diffuse, specular, first_bounce_direction); if ((ubo.ubo.renderer_flags & RENDERER_FLAG_ONLY_DIFFUSE_GI) != 0) { diffuse += specular; @@ -310,7 +305,7 @@ void main() { mat.prop.roughness = material_data.r; vec3 unusedDiffuse = vec3(0.); - computeBounces(mat, pos_t.xyz, direction, 1, unusedDiffuse, specular, specularPdf, reflection_direction); + computeBounces(mat, pos_t.xyz, direction, 1, unusedDiffuse, specular, reflection_direction); } } @@ -336,5 +331,5 @@ void main() { imageStore(out_indirect_diffuse, pix, vec4(diffuse, 0.f)); imageStore(out_indirect_specular, pix, vec4(specular, 0.f)); imageStore(out_first_bounce_direction, pix, vec4(first_bounce_direction, 0.f)); // for spherical harmonics denoising - imageStore(out_reflection_direction_pdf, pix, vec4(reflection_direction, specularPdf)); // for spartial reconstruction + imageStore(out_reflection_direction_pdf, pix, vec4(reflection_direction, 0.f)); // TODO: calculate specular pdf in w for spatial reconstruction } diff --git a/ref/vk/shaders/brdf.glsl b/ref/vk/shaders/brdf.glsl index 985aa1d6d5..f4bc4af5b8 100644 --- a/ref/vk/shaders/brdf.glsl +++ b/ref/vk/shaders/brdf.glsl @@ -189,7 +189,7 @@ void brdfComputeGltfModel(vec3 N, vec3 L, vec3 V, MaterialProperties material, o #endif } -void evalSplitBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material, out vec3 out_diffuse, out vec3 out_specular, out float out_specular_pdf) { +void evalSplitBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material, out vec3 out_diffuse, out vec3 out_specular) { out_diffuse = vec3(0.); out_specular = vec3(0.); @@ -347,7 +347,7 @@ vec3 SampleGGXReflection ( vec3 i , vec2 alpha , vec2 rand ) { #define BRDF_TYPE_DIFFUSE 1 #define BRDF_TYPE_SPECULAR 2 -int brdfGetSample(vec2 rnd, MaterialProperties material, vec3 view, vec3 geometry_normal, vec3 shading_normal, /*float alpha, */out vec3 out_direction, inout vec3 inout_throughput, inout float inout_specular_pdf) { +int brdfGetSample(vec2 rnd, MaterialProperties material, vec3 view, vec3 geometry_normal, vec3 shading_normal, /*float alpha, */out vec3 out_direction, inout vec3 inout_throughput) { #if 1 // See SELECTING BRDF LOBES in 14.3.6 RT Gems 2 // TODO DRY brdfComputeGltfModel @@ -429,8 +429,7 @@ if (g_mat_gltf2) { const vec2 u = vec2(rand01(), rand01()); vec3 brdf_weight = vec3(0.); - float inout_specular_pdf = 0.; - if (!evalIndirectCombinedBRDF(u, shading_normal, geometry_normal, -direction, material, brdf_type, bounce_direction, brdf_weight, inout_specular_pdf)) + if (!evalIndirectCombinedBRDF(u, shading_normal, geometry_normal, -direction, material, brdf_type, bounce_direction, brdf_weight)) return false; throughput *= brdf_weight; } diff --git a/ref/vk/shaders/brdf.h b/ref/vk/shaders/brdf.h index ea24a05cdf..eab24fcc43 100644 --- a/ref/vk/shaders/brdf.h +++ b/ref/vk/shaders/brdf.h @@ -907,7 +907,7 @@ vec3 evalCombinedBRDF(vec3 N, vec3 L, vec3 V, MaterialProperties material) { } // This is an entry point for evaluation of all other BRDFs based on selected configuration (for indirect light) -bool evalIndirectCombinedBRDF(vec2 u, vec3 shadingNormal, vec3 geometryNormal, vec3 V, MaterialProperties material, const int brdfType, OUT_PARAMETER(vec3) rayDirection, OUT_PARAMETER(vec3) sampleWeight, OUT_PARAMETER(float) reflectionPdf) { +bool evalIndirectCombinedBRDF(vec2 u, vec3 shadingNormal, vec3 geometryNormal, vec3 V, MaterialProperties material, const int brdfType, OUT_PARAMETER(vec3) rayDirection, OUT_PARAMETER(vec3) sampleWeight) { // Ignore incident ray coming from "below" the hemisphere if (dot(shadingNormal, V) <= 0.0f) return false; @@ -938,12 +938,9 @@ bool evalIndirectCombinedBRDF(vec2 u, vec3 shadingNormal, vec3 geometryNormal, v sampleWeight *= (vec3(1.0f, 1.0f, 1.0f) - evalFresnel(data.specularF0, shadowedF90(data.specularF0), VdotH)); #endif - reflectionPdf = 0.0; - } else if (brdfType == SPECULAR_TYPE) { const BrdfData data = prepareBRDFData(Nlocal, vec3(0.0f, 0.0f, 1.0f) /* unused L vector */, Vlocal, material); rayDirectionLocal = sampleSpecular(Vlocal, data.alpha, data.alphaSquared, data.specularF0, u, sampleWeight); - reflectionPdf = specularPdf(data.alpha, data.alphaSquared, data.NdotH, data.NdotV, data.LdotH); } // Prevent tracing direction with no contribution diff --git a/ref/vk/shaders/denoiser.comp b/ref/vk/shaders/denoiser.comp index 93c52ed51f..8027436e38 100644 --- a/ref/vk/shaders/denoiser.comp +++ b/ref/vk/shaders/denoiser.comp @@ -7,6 +7,10 @@ #include "ray_interop.h" #undef GLSL +#define DIFFUSE_TEMPORAL_HISTORY_MIX_WEIGHT 0.8 +#define SPECULAR_TEMPORAL_HISTORY_MIX_WEIGHT 0.8 +#define DIELECTRIC_SPECULAR_MULTIPLIER 0.02 // default value from pbr papers, but 0.04 in Unreal Engine + layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(set = 0, binding = 0, rgba16f) uniform image2D out_dest; @@ -166,7 +170,7 @@ Components boxBlurSamples(ivec2 res, ivec2 pix) { vec3 restoreSpecular(vec3 decolorized_specular, vec3 base_color, float metalness) { // TODO: add fresnel and do like PBR - const vec3 plasticSpecular = decolorized_specular * 0.02; + const vec3 plasticSpecular = decolorized_specular * DIELECTRIC_SPECULAR_MULTIPLIER; const vec3 metalSpecular = decolorized_specular * base_color; return mix(plasticSpecular, metalSpecular, metalness); } @@ -501,35 +505,26 @@ void main() { float better_depth_offset = depth_treshold; vec3 history_diffuse = diffuse; vec3 history_specular = specular; - 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++) { - const ivec2 p = reproj_pix + ivec2(x, y); - if (any(greaterThanEqual(p, res)) || any(lessThan(p, ivec2(0)))) { - continue; - } - - if (any(greaterThanEqual(reproj_pix, res)) || any(lessThan(reproj_pix, ivec2(0)))) { - continue; - } - 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; - } + + if (any(greaterThanEqual(reproj_pix, ivec2(0))) && any(lessThan(reproj_pix, res))) { + 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; } } // parallax reprojecting for specular float average_ray_length = 0.; float ray_length_samples_count = 0.; - for(int x = -TEMPORAL_KERNEL; x <=TEMPORAL_KERNEL; x++) { - for(int y = -TEMPORAL_KERNEL; y <=TEMPORAL_KERNEL; y++) { + const int AVERAGE_RAY_LENGTH_KERNEL = 1; + for(int x = -AVERAGE_RAY_LENGTH_KERNEL; x <=AVERAGE_RAY_LENGTH_KERNEL; x++) { + for(int y = -AVERAGE_RAY_LENGTH_KERNEL; y <=AVERAGE_RAY_LENGTH_KERNEL; y++) { const ivec2 p = pix / INDIRECT_SCALE + ivec2(x, y); if (any(greaterThanEqual(p, res / INDIRECT_SCALE)) || any(lessThan(p, ivec2(0)))) { continue; @@ -586,8 +581,8 @@ void main() { #endif if (better_depth_offset < depth_treshold) { - diffuse = mix(diffuse, history_diffuse, 0.8); - specular = mix(specular, history_specular, 0.8); + diffuse = mix(diffuse, history_diffuse, DIFFUSE_TEMPORAL_HISTORY_MIX_WEIGHT); + specular = mix(specular, history_specular, SPECULAR_TEMPORAL_HISTORY_MIX_WEIGHT); } #ifdef DEBUG_VALIDATE_EXTRA diff --git a/ref/vk/shaders/light.glsl b/ref/vk/shaders/light.glsl index 69deec3985..22dbd039a7 100644 --- a/ref/vk/shaders/light.glsl +++ b/ref/vk/shaders/light.glsl @@ -166,8 +166,7 @@ void computePointLights(vec3 P, vec3 N, uint cluster_index, vec3 view_dir, Mater color *= one_over_pdf; vec3 ldiffuse, lspecular; - float specularPdf; - evalSplitBRDF(N, light_dir, view_dir, material, ldiffuse, lspecular, specularPdf); + evalSplitBRDF(N, light_dir, view_dir, material, ldiffuse, lspecular); ldiffuse *= color; lspecular *= color; diff --git a/ref/vk/shaders/light_polygon.glsl b/ref/vk/shaders/light_polygon.glsl index f4328393c2..c55f42bfa1 100644 --- a/ref/vk/shaders/light_polygon.glsl +++ b/ref/vk/shaders/light_polygon.glsl @@ -208,8 +208,7 @@ void sampleSinglePolygonLight(in vec3 P, in vec3 N, in vec3 view_dir, in SampleC return; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); - float specular_pdf = 0.; - evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular, specular_pdf); + evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular); const float estimate = light_sample_dir.w; const vec3 emissive = poly.emissive * estimate; diffuse += emissive * poly_diffuse; @@ -279,8 +278,7 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 view_dir, MaterialProperties ma //const float estimate = total_contrib; const float estimate = light_sample_dir.w; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); - float specular_pdf = 0.; - evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular, specular_pdf); + evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular); diffuse += emissive * estimate * poly_diffuse; specular += emissive * estimate * poly_specular; @@ -347,8 +345,7 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 view_dir, MaterialProperties ma const PolygonLight poly = lights.m.polygons[selected - 1]; const vec3 emissive = poly.emissive; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); - float specular_pdf = 0.; - evalSplitBRDF(N, normalize(poly.center-P), view_dir, material, poly_diffuse, poly_specular, specular_pdf); + evalSplitBRDF(N, normalize(poly.center-P), view_dir, material, poly_diffuse, poly_specular); diffuse += emissive * total_contrib; specular += emissive * total_contrib; #else @@ -370,8 +367,7 @@ void sampleEmissiveSurfaces(vec3 P, vec3 N, vec3 view_dir, MaterialProperties ma //const float estimate = total_contrib; const float estimate = light_sample_dir.w; vec3 poly_diffuse = vec3(0.), poly_specular = vec3(0.); - float specular_pdf = 0.; - evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular, specular_pdf); + evalSplitBRDF(N, light_sample_dir.xyz, view_dir, material, poly_diffuse, poly_specular); diffuse += emissive * estimate; specular += emissive * estimate; } diff --git a/ref/vk/shaders/ray_interop.h b/ref/vk/shaders/ray_interop.h index cb033d3b26..9cd9784a7f 100644 --- a/ref/vk/shaders/ray_interop.h +++ b/ref/vk/shaders/ray_interop.h @@ -197,7 +197,7 @@ struct LightCluster { #define RENDERER_FLAG_SEPARATED_REFLECTION (1<<1) #define RENDERER_FLAG_DENOISE_GI_BY_SH (1<<2) #define RENDERER_FLAG_DISABLE_GI (1<<3) -#define RENDERER_FLAG_SPARTIAL_RECONSTRUCTION (1<<4) +#define RENDERER_FLAG_SPATIAL_RECONSTRUCTION (1<<4) struct UniformBuffer { mat4 inv_proj, inv_view; diff --git a/ref/vk/shaders/rt.json b/ref/vk/shaders/rt.json index d083551338..8e58aa0c00 100644 --- a/ref/vk/shaders/rt.json +++ b/ref/vk/shaders/rt.json @@ -62,11 +62,11 @@ "indiff_sh_save": { "comp": "diffuse_gi_sh_denoise_save" }, - "spartial_reconstruction_pass1": { - "comp": "spartial_reconstruction_pass1" + "spatial_reconstruction_pass1": { + "comp": "spatial_reconstruction_pass1" }, - "spartial_reconstruction_pass2": { - "comp": "spartial_reconstruction_pass2" + "spatial_reconstruction_pass2": { + "comp": "spatial_reconstruction_pass2" }, "denoiser": { "comp": "denoiser" diff --git a/ref/vk/shaders/spartial_reconstruction.glsl b/ref/vk/shaders/spatial_reconstruction.glsl similarity index 97% rename from ref/vk/shaders/spartial_reconstruction.glsl rename to ref/vk/shaders/spatial_reconstruction.glsl index 96b53ac2c7..07d4246736 100644 --- a/ref/vk/shaders/spartial_reconstruction.glsl +++ b/ref/vk/shaders/spatial_reconstruction.glsl @@ -1,8 +1,8 @@ // originally implemented by Mikhail Gorobets for Diligent Engine // https://github.com/DiligentGraphics/DiligentEngine -#ifndef SPARTIAL_RECONSTRUCTION_RADIUS -#define SPARTIAL_RECONSTRUCTION_RADIUS 7. +#ifndef SPATIAL_RECONSTRUCTION_RADIUS +#define SPATIAL_RECONSTRUCTION_RADIUS 7. #endif #ifndef SPECULAR_INPUT_IMAGE @@ -165,7 +165,7 @@ void main() { return; } - if ((ubo.ubo.renderer_flags & RENDERER_FLAG_SPARTIAL_RECONSTRUCTION) == 0) { + if ((ubo.ubo.renderer_flags & RENDERER_FLAG_SPATIAL_RECONSTRUCTION) == 0) { imageStore(SPECULAR_OUTPUT_IMAGE, pix, imageLoad(SPECULAR_INPUT_IMAGE, pix)); return; } @@ -195,7 +195,7 @@ void main() { float roughness = imageLoad(material_rmxx, pix * INDIRECT_SCALE).x; float roughness_factor = saturate(float(SPATIAL_RECONSTRUCTION_ROUGHNESS_FACTOR) * roughness); - float radius = mix(0.0, SPARTIAL_RECONSTRUCTION_RADIUS, roughness_factor); + float radius = mix(0.0, SPATIAL_RECONSTRUCTION_RADIUS, roughness_factor); PixelAreaStatistic pixelAreaStat; pixelAreaStat.colorSum = vec4(0.0, 0.0, 0.0, 0.0); diff --git a/ref/vk/shaders/spartial_reconstruction_pass1.comp b/ref/vk/shaders/spatial_reconstruction_pass1.comp similarity index 79% rename from ref/vk/shaders/spartial_reconstruction_pass1.comp rename to ref/vk/shaders/spatial_reconstruction_pass1.comp index b8bc2a8ade..e1654096d6 100644 --- a/ref/vk/shaders/spartial_reconstruction_pass1.comp +++ b/ref/vk/shaders/spatial_reconstruction_pass1.comp @@ -4,8 +4,8 @@ #extension GL_EXT_shader_16bit_storage : require #extension GL_EXT_ray_query: require -#define SPARTIAL_RECONSTRUCTION_RADIUS 11. +#define SPATIAL_RECONSTRUCTION_RADIUS 11. #define SPECULAR_INPUT_IMAGE indirect_specular #define SPECULAR_OUTPUT_IMAGE out_indirect_specular_reconstructed_pass1 -#include "spartial_reconstruction.glsl" +#include "spatial_reconstruction.glsl" diff --git a/ref/vk/shaders/spartial_reconstruction_pass2.comp b/ref/vk/shaders/spatial_reconstruction_pass2.comp similarity index 80% rename from ref/vk/shaders/spartial_reconstruction_pass2.comp rename to ref/vk/shaders/spatial_reconstruction_pass2.comp index 17d189335e..c9c6ea2b55 100644 --- a/ref/vk/shaders/spartial_reconstruction_pass2.comp +++ b/ref/vk/shaders/spatial_reconstruction_pass2.comp @@ -4,8 +4,8 @@ #extension GL_EXT_shader_16bit_storage : require #extension GL_EXT_ray_query: require -#define SPARTIAL_RECONSTRUCTION_RADIUS 5. +#define SPATIAL_RECONSTRUCTION_RADIUS 5. #define SPECULAR_INPUT_IMAGE indirect_specular_reconstructed_pass1 #define SPECULAR_OUTPUT_IMAGE out_indirect_specular_reconstructed -#include "spartial_reconstruction.glsl" +#include "spatial_reconstruction.glsl" diff --git a/ref/vk/vk_cvar.c b/ref/vk/vk_cvar.c index 9d7e44887c..7bfbc7b17a 100644 --- a/ref/vk/vk_cvar.c +++ b/ref/vk/vk_cvar.c @@ -44,7 +44,7 @@ void VK_LoadCvarsAfterInit( void ) rt_separated_reflection = gEngine.Cvar_Get("rt_separated_reflection", "", FCVAR_GLCONFIG, "Add separated high quality reflection pass"); rt_denoise_gi_by_sh = gEngine.Cvar_Get("rt_denoise_gi_by_sh", "", FCVAR_GLCONFIG, "Denoise global illumination by spherical harmonics"); rt_disable_gi = gEngine.Cvar_Get("rt_disable_gi", "", FCVAR_GLCONFIG, "Disable global illumination calculation"); - rt_spartial_reconstruction = gEngine.Cvar_Get("rt_spartial_reconstruction", "", FCVAR_GLCONFIG, "Apply spartial reconstruction to specular"); + rt_spatial_reconstruction = gEngine.Cvar_Get("rt_spatial_reconstruction", "", FCVAR_GLCONFIG, "Apply spatial reconstruction to specular"); } else { rt_enable = gEngine.Cvar_Get( "rt_enable", "0", FCVAR_READ_ONLY, "DISABLED: Ray tracing is not supported by your hardware/drivers" ); } diff --git a/ref/vk/vk_cvar.h b/ref/vk/vk_cvar.h index e900df0c85..478161ccf6 100644 --- a/ref/vk/vk_cvar.h +++ b/ref/vk/vk_cvar.h @@ -30,7 +30,7 @@ void VK_LoadCvarsAfterInit( void ); X(rt_separated_reflection) \ X(rt_denoise_gi_by_sh) \ X(rt_disable_gi) \ - X(rt_spartial_reconstruction) \ + X(rt_spatial_reconstruction) \ #define EXTERN_CVAR(cvar) extern cvar_t *cvar; DECLARE_CVAR(EXTERN_CVAR) diff --git a/ref/vk/vk_rtx.c b/ref/vk/vk_rtx.c index 88193c8627..7c2a7a9bad 100644 --- a/ref/vk/vk_rtx.c +++ b/ref/vk/vk_rtx.c @@ -273,7 +273,7 @@ static void prepareUniformBuffer( const vk_ray_frame_render_args_t *args, int fr SET_RENDERER_FLAG(rt_separated_reflection, RENDERER_FLAG_SEPARATED_REFLECTION) | SET_RENDERER_FLAG(rt_denoise_gi_by_sh, RENDERER_FLAG_DENOISE_GI_BY_SH) | SET_RENDERER_FLAG(rt_disable_gi, RENDERER_FLAG_DISABLE_GI) | - SET_RENDERER_FLAG(rt_spartial_reconstruction, RENDERER_FLAG_SPARTIAL_RECONSTRUCTION); + SET_RENDERER_FLAG(rt_spatial_reconstruction, RENDERER_FLAG_SPATIAL_RECONSTRUCTION); #undef SET_RENDERER_FLAG } From d79b6e690cec0699d8d6ff5b0a323ce024e30c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Wed, 25 Dec 2024 22:52:13 +0400 Subject: [PATCH 11/12] fix symbol encoding again --- ref/vk/shaders/ray_interop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ref/vk/shaders/ray_interop.h b/ref/vk/shaders/ray_interop.h index 9cd9784a7f..65272e320c 100644 --- a/ref/vk/shaders/ray_interop.h +++ b/ref/vk/shaders/ray_interop.h @@ -130,7 +130,7 @@ struct Kusok { }; struct PointLight { - vec4 origin_r2; // vec4(center.xyz, radius²) + vec4 origin_r2; // vec4(center.xyz, radius�) vec4 color_stopdot; vec4 dir_stopdot2; From 3d1a14781302531016f0b4a30fd0b5b8ccc03c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D1=80=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9=20=D0=9A?= =?UTF-8?q?=D0=B0=D0=B1=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Wed, 25 Dec 2024 23:04:48 +0400 Subject: [PATCH 12/12] fix encoding #2 --- .editorconfig | 2 +- ref/vk/shaders/ray_interop.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 77807af0d6..84af569000 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ root = true [*] -charset = latin1 +charset = utf-8 end_of_line = lf indent_style = tab insert_final_newline = true diff --git a/ref/vk/shaders/ray_interop.h b/ref/vk/shaders/ray_interop.h index 65272e320c..9cd9784a7f 100644 --- a/ref/vk/shaders/ray_interop.h +++ b/ref/vk/shaders/ray_interop.h @@ -130,7 +130,7 @@ struct Kusok { }; struct PointLight { - vec4 origin_r2; // vec4(center.xyz, radius�) + vec4 origin_r2; // vec4(center.xyz, radius²) vec4 color_stopdot; vec4 dir_stopdot2;