Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dontnoiser reflections #755

Merged
merged 12 commits into from
Dec 25, 2024
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
root = true

[*]
charset = latin1
charset = utf-8
end_of_line = lf
indent_style = tab
insert_final_newline = true
Expand Down
35 changes: 27 additions & 8 deletions ref/vk/shaders/bounce.comp
Original file line number Diff line number Diff line change
Expand Up @@ -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 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;
Expand Down Expand Up @@ -121,13 +122,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, inout vec3 first_bounce_direction) {
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
Expand Down Expand Up @@ -223,7 +224,7 @@ void computeBounces(MaterialEx mat, vec3 pos, vec3 direction, inout vec3 diffuse
specular += contribution;

if (i == 0)
imageStore(out_first_bounce_direction, pix, vec4(normalize(bounce_direction), 0.f)); // for spherical harmonics denoising
first_bounce_direction = hit_pos - pos;

if (!did_hit)
break;
Expand Down Expand Up @@ -262,6 +263,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.);
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);
Expand All @@ -288,7 +290,23 @@ 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, first_bounce_direction);

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.base_color = vec3(1.);
mat.prop.metalness = 1.0;
mat.prop.roughness = material_data.r;

vec3 unusedDiffuse = vec3(0.);
computeBounces(mat, pos_t.xyz, direction, 1, unusedDiffuse, specular, reflection_direction);
}
}

#ifdef DEBUG_VALIDATE_EXTRA
Expand All @@ -306,11 +324,12 @@ 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.);
if (any(equal(reflection_direction, vec3(0.)))) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

крайне маловероятно, что (случайный) отражённый луч может иметь какую-либо из компонент в точности равной нулю, но

Suggested change
if (any(equal(reflection_direction, vec3(0.)))) {
if (all(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, 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, 0.f)); // TODO: calculate specular pdf in w for spatial reconstruction
}
132 changes: 95 additions & 37 deletions ref/vk/shaders/denoiser.comp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,24 +33,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"

Expand Down Expand Up @@ -88,6 +93,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;
};
Expand All @@ -106,7 +117,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;
}

Expand Down Expand Up @@ -152,12 +163,19 @@ 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;
}

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 * DIELECTRIC_SPECULAR_MULTIPLIER;
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.);

Expand Down Expand Up @@ -237,7 +255,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 += restoreSpecular(imageLoad(indirect_specular_reconstructed, p_scaled).rgb, base_color, metalness) * weight;
}
}
}
Expand Down Expand Up @@ -350,7 +368,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;
}
}
}
Expand Down Expand Up @@ -398,6 +416,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);

Expand Down Expand Up @@ -430,7 +452,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
Expand Down Expand Up @@ -480,31 +502,69 @@ 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;
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, 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;
}
}

if (any(greaterThanEqual(reproj_pix, res)) || any(lessThan(reproj_pix, ivec2(0)))) {
// parallax reprojecting for specular
float average_ray_length = 0.;
float ray_length_samples_count = 0.;
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;
}
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;
}

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
w23 marked this conversation as resolved.
Show resolved Hide resolved
// | \ / | 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);
}
}

Expand All @@ -521,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.3);
diffuse = mix(diffuse, history_diffuse, DIFFUSE_TEMPORAL_HISTORY_MIX_WEIGHT);
specular = mix(specular, history_specular, SPECULAR_TEMPORAL_HISTORY_MIX_WEIGHT);
}

#ifdef DEBUG_VALIDATE_EXTRA
Expand Down Expand Up @@ -552,8 +612,6 @@ 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;
Expand Down
2 changes: 1 addition & 1 deletion ref/vk/shaders/diffuse_gi_sh_denoise_init.comp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
3 changes: 2 additions & 1 deletion ref/vk/shaders/ray_interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ struct Kusok {
};

struct PointLight {
vec4 origin_r2; // vec4(center.xyz, radius²)
vec4 origin_r2; // vec4(center.xyz, radius²)
w23 marked this conversation as resolved.
Show resolved Hide resolved
vec4 color_stopdot;
vec4 dir_stopdot2;

Expand Down Expand Up @@ -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_SPATIAL_RECONSTRUCTION (1<<4)

struct UniformBuffer {
mat4 inv_proj, inv_view;
Expand Down
6 changes: 6 additions & 0 deletions ref/vk/shaders/rt.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@
"indiff_sh_save": {
"comp": "diffuse_gi_sh_denoise_save"
},
"spatial_reconstruction_pass1": {
"comp": "spatial_reconstruction_pass1"
},
"spatial_reconstruction_pass2": {
"comp": "spatial_reconstruction_pass2"
},
"denoiser": {
"comp": "denoiser"
},
Expand Down
Loading